假设你想要按key1进行分组,并计算data1列的平均值。实现该功能的方式有很多,而我们这里要用的是:访问data1,并根据key1调用groupby:
grouped = df['data1'].groupby(df['key1']) 变量grouped是一个GroupBy对象。它实际上还没有进行任何计算,只是含有一些有关分组键df['key1']的中间数据而已。换句话说,该对象已经有了接下来对各分组执行运算所需的一切信息。
grouped.mean()
means = df['data1'].groupby([df['key1'], df['key2']]).mean() 一次传入多个数组的列表,得到的Series具有一个层次化索引
In [18]: states = np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])
In [19]: years = np.array([2005, 2005, 2006, 2005, 2006])
In [20]: df['data1'].groupby([states, years]).mean() 分组键可以是任何长度适当的数组,长度适当指的是长度跟原始df一样
df.groupby('key1').mean() 可以将列名(可以是字符串、数字或其他Python对象)用作分组键
df.groupby(['key1', 'key2']).mean()
df.groupby(['key1', 'key2']).size() #GroupBy的size方法,它可以返回一个含有分组大小的Series
for name, group in df.groupby('key1'): #GroupBy对象支持迭代,可以产生一组二元元组(由分组名和数据块组成)
for (k1, k2), group in df.groupby(['key1', 'key2']): #对于多重键的情况,元组的第一个元素将会是由键值组成的元组
pieces = dict(list(df.groupby('key1'))) #这里得到的pieces是一个字典
grouped = df.groupby(df.dtypes, axis=1) #groupby默认是在axis=0上进行分组的,通过设置也可以在其他任何轴上进行分组。后续可进行迭代操作,如for dtype, group in grouped:
df.groupby('key1')['data1']
df.groupby('key1')[['data2']]
上面写法等价于:
df['data1'].groupby(df['key1'])
df[['data2']].groupby(df['key1'])
df.groupby(['key1', 'key2'])[['data2']].mean() #只需计算data2列的平均值并以DataFrame形式得到结果
s_grouped = df.groupby(['key1', 'key2'])['data2'] #s_grouped.mean()得到的就不是df了,而是series
通过字典或Series进行分组
by_column = people.groupby(mapping, axis=1) #by_column.sum()也可以,这里mapping是一个字典
people.groupby(map_series, axis=1).count()
通过函数进行分组
people.groupby(len).sum() #根据索引长度进行分组求和
people.groupby([len, key_list]).min() #将函数跟数组、列表、字典、Series混合使用也不是问题,因为任何东西在内部都会被转换为数组
根据索引级别分组
hier_df.groupby(level='cty', axis=1).count()
10.2 数据聚合
In [52]: grouped = df.groupby('key1')
In [53]: grouped['data1'].quantile(0.9) #
In [54]: def peak_to_peak(arr):
....: return arr.max() - arr.min()
In [55]: grouped.agg(peak_to_peak) #使用自定义聚合函数
grouped.describe() #也能用面向列的多函数应用
In [60]: grouped = tips.groupby(['day', 'smoker'])
In [61]: grouped_pct = grouped['tip_pct']
In [62]: grouped_pct.agg('mean') #将函数名以字符串的形式传入
In [63]: grouped_pct.agg(['mean', 'std', peak_to_peak]) #这里,我们传递了一组聚合函数进行聚合,独立对数据分组进行评估
In [64]: grouped_pct.agg([('foo', 'mean'), ('bar', np.std)]) #自定义每一列的列名
In [65]: functions = ['count', 'mean', 'max']
In [66]: result = grouped['tip_pct', 'total_bill'].agg(functions) #对原始的2列分别计算3个统计信息,得到的是层次化的列索引
In [69]: ftuples = [('Durchschnitt', 'mean'),('Abweichung', np.var)]
In [70]: grouped['tip_pct', 'total_bill'].agg(ftuples) #传入带有自定义名称的一组元组
In [71]: grouped.agg({'tip' : np.max, 'size' : 'sum'}) #对一个列或不同的列应用不同的函数。具体的办法是向agg传入一个从列名映射到函数的字典
In [72]: grouped.agg({'tip_pct' : ['min', 'max', 'mean', 'std'],'size' : 'sum'})
以“没有行索引”的形式返回聚合数据
In [73]: tips.groupby(['day', 'smoker'], as_index=False).mean() #通过设置参数as_index=False得到的结果不具有实质性行索引
10.3 apply:一般性的“拆分-应用-合并”
In [74]: def top(df, n=5, column='tip_pct'):
....: return df.sort_values(by=column)[-n:]
In [76]: tips.groupby('smoker').apply(top) #对smoker分组并用该函数调用apply
In [77]: tips.groupby(['smoker', 'day']).apply(top, n=1, column='total_bill') #给top函数传递参数
In [78]: result = tips.groupby('smoker')['tip_pct'].describe()
等价于:
f = lambda x: x.describe()
grouped.apply(f)
In [81]: tips.groupby('smoker', group_keys=False).apply(top) #将group_keys=False传入groupby即可禁止分组键