pandas 数据框中的分组

Groupby in pandas dataframe

考虑以下数据集:

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

如何找到 b 列中大于 20 的值的百分比,并且根据 a 列位于同一集群中。 我的代码为每个组提供了相同的值。

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) 

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

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% 添加了另一个值):

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()

如果您需要快速的东西,np.bincount 可能是一个很好的解决方案,而不是 Pandas groupby。

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

哪个returns

array([ 1.        ,  0.33333333,  0.5       ])

或者,如果您想将输出转换回系列,您随后可以使用 np.take

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

无论哪种情况,这似乎都相当快。

小案例:提供数据集

groupby 来自 MaxU 的方法

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

np.bincount接近

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

更大的情况:生成的数据集

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

groupby 来自 MaxU 的方法

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

np.bincount接近

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