2013-01-12 13 views
10

Mam ramkę danych z kolumnami numerycznymi. Dla każdej kolumny chciałbym obliczyć informacje kwantyle i przypisać każdy wiersz do jednego z nich. Próbowałem użyć qcut() method, aby zwrócić listę pojemników, ale zamiast tego wyliczyłem indywidualnie te pojemniki. To, co myślałem, że może istnieć, ale nie mogłem go znaleźć, byłoby metodą taką jak df.to_quintile(num of quantiles). Oto, co wymyśliłem, ale zastanawiam się, czy jest to lepszy sposób na pandę/pandę.Konwertuj dane do kwilenu bin

import pandas as pd 

#create a dataframe 
df = pd.DataFrame(randn(10, 4), columns=['A', 'B', 'C', 'D']) 

def quintile(df, column): 
    """ 
    calculate quintiles and assign each sample/column to a quintile 
    """ 
    #calculate the quintiles using pandas .quantile() here 
    quintiles = [df[column].quantile(value) for value in [0.0,0.2,0.4,0.6,0.8]] 
    quintiles.reverse() #reversing makes the next loop simpler 

    #function to check membership in quintile to be used with pandas apply 
    def check_quintile(x, quintiles=quintiles): 
     for num,level in enumerate(quintiles): 
      #print number, level, level[1] 
      if x >= level: 
       print x, num 
       return num+1 

    df[column] = df[column].apply(check_quintile) 

quintile(df,'A') 

Dzięki, Zach cp

EDIT: Po obejrzeniu DSMS odpowiedzieć funkcja może być napisany znacznie prostsze (poniżej). Człowieku, to jest słodkie.

def quantile(column, quantile=5): 
    q = qcut(column, quantile) 
    return len(q.levels)- q.labels 
df.apply(quantile) 
#or 
df['A'].apply(quantile) 

Odpowiedz

13

myślę pomocą labels przechowywany wewnątrz obiektu Categorical zwróconej przez qcut można zrobić to dużo prostsze. Na przykład:

>>> import pandas as pd 
>>> import numpy as np 
>>> np.random.seed(1001) 
>>> df = pd.DataFrame(np.random.randn(10, 2), columns=['A', 'B']) 
>>> df 
      A   B 
0 -1.086446 -0.896065 
1 -0.306299 -1.339934 
2 -1.206586 -0.641727 
3 1.307946 1.845460 
4 0.829115 -0.023299 
5 -0.208564 -0.916620 
6 -1.074743 -0.086143 
7 1.175839 -1.635092 
8 1.228194 1.076386 
9 0.394773 -0.387701 
>>> q = pd.qcut(df["A"], 5) 
>>> q 
Categorical: A 
array([[-1.207, -1.0771], (-1.0771, -0.248], [-1.207, -1.0771], 
     (1.186, 1.308], (0.569, 1.186], (-0.248, 0.569], (-1.0771, -0.248], 
     (0.569, 1.186], (1.186, 1.308], (-0.248, 0.569]], dtype=object) 
Levels (5): Index([[-1.207, -1.0771], (-1.0771, -0.248], 
        (-0.248, 0.569], (0.569, 1.186], (1.186, 1.308]], dtype=object) 
>>> q.labels 
array([0, 1, 0, 4, 3, 2, 1, 3, 4, 2]) 

lub dopasować swój kod:

>>> len(q.levels) - q.labels 
array([5, 4, 5, 1, 2, 3, 4, 2, 1, 3]) 
>>> quintile(df, "A") 
>>> np.array(df["A"]) 
array([5, 4, 5, 1, 2, 3, 4, 2, 1, 3]) 
+0

dzięki DSM. Nie zdawałem sobie sprawy, że na wyjściu qcut() są etykiety. Właśnie tego potrzebowałem! – zach

+0

Dzięki @DSM, nie wiedziałem, że qcut/cut ma atrybut label (nie jest wyświetlany niestety w autouzupełnianiu IPython). Do tej pory myślałem, że muszę wywoływać 'labels = False' do wywołania funkcji, aby uzyskać etykiety. Ale jest ładniej. – tim