Python之数据聚合与分组运算

1.groupby技术

import pandas as pd

import numpy as np

df=pd.DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one','two','one'],

df

#按key1进行分组，计算data1的平均值

grouped=df['data1'].groupby(df['key1'])

grouped

grouped.mean()

means=df['data1'].groupby([df['key1'],df['key2']]).mean()

means

means.unstack()

#分组键可以是任何长度适当的数组

states=np.array(['o','c','c','o','o'])

years=np.array([2001,2003,2001,2004,2001])

df['data1'].groupby([states,years]).mean()

#将列名当分组键

df.groupby('key1').mean()

df.groupby(['key1','key2']).mean()

#返回一个有分组大小的series

df.groupby(['key1','key2']).size()

%对分组进行迭代

for name,group in df.groupby('key1'):

print name

print group

for (k1,k2),group in df.groupby(['key1','key2']):

print k1,k2

print group

#将数据片段做成字典

pieces=dict(list(df.groupby('key1')))

pieces

pieces['b']

#根据dtype对列进行分组

df.dtypes

grouped=df.groupby(df.dtypes,axis=1)

dict(list(grouped))

%选取一个或一组列

df.groupby('key1')['data1']

df.groupby(['key1','key2'])['data1'].mean()

%通过字典或者Series进行分组

people.ix[2:3,['b','c']]=np.nan

people

#假设已知列的关系，并希望依据分组计算列的总计

mapping={'a':'red','b':'red','c':'blue','d':'blue','e':'red','f':'orange'}

by_column=people.groupby(mapping,axis=1)

by_column.sum

map_series=pd.Series(mapping)

map_series

people.groupby(map_series,axis=1).sum()

people.groupby(map_series,axis=1).count()

%通过函数进行分组

#根据人名的长度进行分组

people.groupby(len).sum()

key=['one','two','one','two','one']

people.groupby([len,key]).min()

%根据索引级别分组

#层次化索引数据集最方便的地方就在于它能够根据索引级别进行聚合。用level

columns=pd.MultiIndex.from_arrays([['us','us','us','jp','jp'],[1,3,5,1,3]],names=['cty','tenor'])

hief_df

hief_df.groupby(level='cty',axis=1).count()

hief_df.groupby(level='cty',axis=1).mean()

2.数据聚合

df=pd.DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one','two','one'],

df

grouped=df.groupby('key1')

grouped['data1'].quantile(0.9)#计算样本分位数

#使用自己的聚合函数，传入aggregate或agg即可

def peak_to_peak(arr):

return arr.max()-arr.min()

grouped.agg(peak_to_peak)

#分组后的大致情况

grouped.describe()

%面向列的多函数应用

df['pct']=df['data1']/df['data2']

grouped=df.groupby(['key1','key2'])

grouped_pct=grouped['pct']

grouped_pct.agg('mean')

grouped_pct.agg(['mean','std',peak_to_peak])

#如果传入的是一个有（name,function）元组组成的列表，则各元组的第一个元素就会被用作dataframe的列名

grouped_pct.agg([('foo','mean'),('bar',np.std)])

#可以自定义函数组合

functions=['count','mean','max']

result=grouped['pct','data2'].agg(functions)

result

result['pct']

#自定义名称的元组列表

func=[('d','mean'),('a',np.var)]

grouped['pct','data2'].agg(func)

##想要对不同的列应用不同的函数。向agg传入一个从列名映射到函数的字典

grouped.agg({'data1':np.max,'data2':'sum'})

grouped.agg({'data1':['min','max','mean','std'],'data2':'sum'})

%以“无索引”的形式返回聚合函数

df.groupby(['key1','key2'],as_index=False).mean()

3.分组级运算和转换：transform&apply

#添加一个各索引分组平均值的列，先聚合再合并

df=pd.DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one','two','one'],

df

k1_means

pd.merge(df,k1_means,left_on='key1',right_index=True)

#以上,不太灵活，换个方法用transform

key=['one','two','one','two','one']

people.groupby(key).mean()

people.groupby(key).transform(np.mean)

#距平化函数（demeaning function）

def demean(arr):

return arr-arr.mean()

demeaned=people.groupby(key).transform(demean)

demeaned

demeaned.groupby(key).mean()

%apply:一般性的“拆分--应用--合并”

#在指定列找出最大值，把这个值所在的行找出来

def top(df,n=3,column='data1'):

return df.sort_index(by=column)[-n:]

top(df,n=5)

df.groupby('key2').apply(top)

#describe

result=df.groupby('key2')['data1'].describe()

result

result.unstack('key2')

#f=lambda x:x.describe()

#df.groupby('key2')['pct'].apply(f)

%禁止分组键:即不会出现层次化索引：group_keys=false

df.groupby('key2',group_keys=False).apply(top)

%分位数和桶分析

factor=pd.cut(frame.data1,4)

factor[:10]

#由cut返回的factor对象可直接用于groupby

def get_stats(group):

return {'min':group.min(),'max':group.max(),'count':group.count(),'mean':group.mean()}

grouped.apply(get_stats).unstack()

#根据样本分位数得到大小相等的桶，使用qcut,返回分位数编号

grouping=pd.qcut(frame.data1,10,labels=False)

grouped.apply(get_stats).unstack()

%示例：用特定于分组的值填充缺失值

#用平均值填充NA值,fillna

s[::2]=np.nan#一个隔一个填充

s

s.fillna(s.mean())

#对不同的分组填充不同的值，apply+fillna

states=['o','ny','v','f','or','n','c','i']

group_key=['east']*4+['west']*4

data[['v','n','i']]=np.nan

data

data.groupby(group_key).mean()

#用分组平均值去填充NA值

fill_mean=lambda g:g.fillna(g.mean())

data.groupby(group_key).apply(fill_mean)

#用预定义各组的值去填充NA值

fill_values={'east':0.1,'west':-0.1}

fill_func=lambda g:g.fillna(fill_values[g.name])

data.groupby(group_key).apply(fill_func)

%示例：随机采样和排列

#构造一副英语型扑克牌

suits=['h','s','c','d']

card_val=(range(1,11)+[10]*3)*4

base_names=['A']+range(2,11)+['j','k','q']

cards=[]

for suit in ['h','s','c','d']:

cards.extend(str(num)+suit for num in base_names)

deck=pd.Series(card_val,index=cards)

deck[:13]

#从整副牌中抽5张

def draw(deck,n=5):

draw(deck)

#每种花色抽两张，根据花色分组然后使用apply

get_suit=lambda card:card[-1]

deck.groupby(get_suit).apply(draw,n=2)

deck.groupby(get_suit,group_keys=False).apply(draw,n=2)

%示例：分组加权平均数和相关系数

df

#利用category计算加权平均数

grouped=df.groupby('category')

get_wavg=lambda g:np.average(g['data'],weights=g['weights'])

grouped.apply(get_wavg)

%示例：面向分组的线性回归

import statsmodels.api as sm

def regress(data,yvar,xvars):

y=data[yvar]

x=data[xvars]

x['intercept']=1

result=sm.ols(y,x).fit()

return result.params

grouped.apply(regress,'data',['weights'])#报错

grouped.apply(lambda g:g['data'].corr(g['weights']))

4.透视表和交叉表pivot_table、crosstab

#小费数据集，假设根据sex和smoker计算分组平均数，并将sex和smoker放在行上，（因没有数据表，所以仅展示code）

tips.pivot_table(rows=['sex','smoker'])

tips.pivot_table(['tip_pct','size'],rows=['sex','day'],cols='smoker')

pd.crosstab([tips.time,tips.day],tips.smoker,margins=True)

• 发表于:
• 原文链接http://kuaibao.qq.com/s/20180227G115OB00?refer=cp_1026
• 腾讯「云+社区」是腾讯内容开放平台帐号（企鹅号）传播渠道之一，根据《腾讯内容开放平台服务协议》转载发布内容。

2020-02-23

2020-02-23

2020-02-23

2020-02-23

2020-02-23

2020-02-23

2018-06-25

2018-06-07

2020-02-23

2020-02-23

2020-02-23

2020-02-23