2017-11-01 6 views
3

Betrachten Sie die folgende Datenmenge:GROUPBY in Pandas Dataframe

a  b 
0  23 
0  21 
1  25 
1  20 
1  19 
2  44 
2  11 

Wie kann ich die Prozentsätze der Werte in Spalte b finden, die als 20 größer sind, und sind im gleichen Cluster nach Spalte ein. mein Code gibt mir den gleichen Wert für jede Gruppe.

NN20 = [x for x in b if (x > 20)] 
percent_20 = lambda x: float(len(NN20))/float(len(b)) 
pnn20=data.groupby('a').apply(percent_20) 

Antwort

4

IIUC:

In [179]: df.groupby('a')['b'].apply(lambda x: x.gt(20).mean()) 
Out[179]: 
a 
0 1.000000 
1 0.333333 
2 0.500000 
Name: b, dtype: float64 

oder

In [183]: df.groupby('a')['b'].transform(lambda x: x.gt(20).mean()) 
Out[183]: 
0 1.000000 
1 1.000000 
2 0.333333 
3 0.333333 
4 0.333333 
5 0.500000 
6 0.500000 
Name: b, dtype: float64 
+0

Warum Sie verwenden bedeuten statt sum/len? – Elham

+1

@AlterNative, es gibt uns das gleiche Ergebnis, aber es ist schöner, kürzer und erfordert weniger Operationen ... PS eigentlich 'mean (lst) == sum (lst)/len (lst)' ;-) – MaxU

1

Dies ist eine Möglichkeit, es zu tun (einen anderen Wert für 0% hinzugefügt):

data = pd.DataFrame({'a': [0,0,1,1,1,2,2,3], 
        'b': [23,21,25,20,19,44,11,15]}) 

data['c'] = data['b'].apply(lambda x: int(x>20)) 
shareOf20 = data.groupby('a')['c'].sum()/data.groupby('a')['c'].count() 
2

Wenn Sie brauchen etwas schnell, np.bincount könnte eine gute Lösung inst sein ead eines Pandas groupby.

np.bincount(df.loc[df.b > 20, 'a'])/np.bincount(df.a)) 

die

array([ 1.  , 0.33333333, 0.5  ]) 

zurück Oder wenn Sie die Ausgabe zurück auf eine Reihe verwandeln wollte, Sie anschließend np.take nutzen könnten.

pd.Series((np.bincount(df.loc[df.b > 20, 'a'])/np.bincount(df.a)).take(df.a)) 

# 0 1.000000 
# 1 1.000000 
# 2 0.333333 
# 3 0.333333 
# 4 0.333333 
# 5 0.500000 
# 6 0.500000 
# dtype: float64 

In jedem Fall scheint dies ziemlich schnell zu sein.

Kleinere Fall: bereitgestellt Dataset

groupby Ansatz aus MAXU

%timeit df.groupby('a')['b'].transform(lambda x: x.gt(20).mean()) 
2.51 ms ± 65.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

np.bincount Ansatz

%timeit pd.Series((np.bincount(df.loc[df.b > 20, 'a'])/np.bincount(df.a)).take(df.a)) 
271 µs ± 5.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Larg er Fall: erzeugte Datenmenge

df = pd.DataFrame({'a': np.random.randint(0, 10, 100000), 
        'b': np.random.randint(0, 100, 100000)}).sort_values('a') 

groupby Ansatz aus MAXU

%timeit df.groupby('a')['b'].transform(lambda x: x.gt(20).mean()) 
11.3 ms ± 40.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

np.bincount Ansatz

%timeit pd.Series((np.bincount(df.loc[df.b > 20, 'a'])/np.bincount(df.a)).take(df.a)) 
1.56 ms ± 5.47 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
+0

Tolle Lösung, danke zum Teilen! – Elham

Verwandte Themen