目录
Group By
Group By功能:
- 根据某些条件将数据拆分成组
- 对每个组独立应用函数
- 将结果合并到一个数据结构中
一、分组 groupby()
df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)
- by:可按单个或多个([])列分组
- axis:默认为0,以行分组;1表示以列分组
- level:level=0,按照索引分组;如果有多个索引,level设置为索引字符串或索引字符串数组。
直接分组得到一个groupby对象,是一个中间数据;通过分组后的计算,得到一个新的DataFrame。
df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
'B': ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
'C': np.random.randn(8),
'D': np.random.randn(8)})
'''
A B C D
0 foo one -0.740154 -0.438300
1 bar one 1.386163 -0.271826
2 foo two -0.558456 -1.502778
3 bar three -0.546329 -1.928753
4 foo two -1.145944 0.320112
5 bar two 0.341525 -0.569331
6 foo one -0.381080 -0.657461
7 foo three -0.101462 1.746577
'''
df.groupby('A')
# <pandas.core.groupby.DataFrameGroupBy object at 0x000001FE6EF0F358>
# <class 'pandas.core.groupby.DataFrameGroupBy'>
a = df.groupby('A').mean()
'''
C D
A
bar 0.393786 -0.923304
foo -0.585419 -0.106370
'''
# <class 'pandas.core.frame.DataFrame'>
# a.columns Index(['C', 'D'], dtype='object') 去除不是数字的列
b = df.groupby(['A','B']).mean()
'''
C D
A B
bar one 1.386163 -0.271826
three -0.546329 -1.928753
two 0.341525 -0.569331
foo one -0.560617 -0.547881
three -0.101462 1.746577
two -0.852200 -0.591333
'''
# <class 'pandas.core.frame.DataFrame'>
# b.columns Index(['C', 'D'], dtype='object')
c = df.groupby(['A'])['D'].mean() # 以A分组,算D的平均值
'''
A
bar -0.923304
foo -0.106370
Name: D, dtype: float64
'''
# <class 'pandas.core.series.Series'>
s = pd.Series([1, 2, 3, 10, 20, 30], index = [1, 2, 3, 1, 2, 3])
s.groupby(level = 0).sum()
'''
1 11
2 22
3 33
dtype: int64
'''
get_group():提取分组后的组
groups:该属性类型为dict,分组后每个组的index
list():将groupby转为元组
df = pd.DataFrame({'X' : ['A', 'B', 'A', 'B'], 'Y' : [1, 4, 3, 2]},index=list("absc"))
'''
X Y
a A 1
b B 4
s A 3
c B 2
'''
df.groupby("X").get_group("A")
'''
X Y
a A 1
s A 3
'''
df.groupby("X").groups # {'B': ['b', 'c'], 'A': ['a', 's']}
list(df.groupby("X"))
'''
[('A', X Y
a A 1
s A 3), ('B', X Y
b B 4
c B 2)]
'''
list(df.groupby("X"))[0][1] # <class 'pandas.core.frame.DataFrame'>
'''
X Y
a A 1
s A 3
'''
按照值类型分组,通常按列分组。
df = pd.DataFrame({'data1': np.random.rand(2),
'data2': np.random.rand(2),
'key':['one', 'two']})
df.groupby(df.dtypes, axis = 1).groups # {dtype('O'): ['key'], dtype('float64'): ['data1', 'data2']}
for n, g in df.groupby(df.dtypes, axis = 1):
print(n, "\n", g)
'''
float64 :
data1 data2
0 0.495566 0.352556
1 0.837635 0.634867
object :
key
0 one
1 two
'''
通过字典或者Series分组,通常按列分组。
df = pd.DataFrame(np.arange(16).reshape(4, 4),
columns = ['a', 'b', 'c', 'd'])
'''
a b c d
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
3 12 13 14 15
'''
dic = {'a': 'one', 'b': 'one', 'c': 'two', 'd': 'two', 'e': 'three'}
df.groupby(dic, axis = 1).sum()
df.groupby(pd.Series(dic), axis = 1).sum()
'''
one two
0 1 5
1 9 13
2 17 21
3 25 29
'''
二、遍历分组
for name, group in df.groupby("A"):
print(name)
print(group)
'''
bar
A B C D
1 bar one 1.386163 -0.271826
3 bar three -0.546329 -1.928753
5 bar two 0.341525 -0.569331
foo
A B C D
0 foo one -0.740154 -0.438300
2 foo two -0.558456 -1.502778
4 foo two -1.145944 0.320112
6 foo one -0.381080 -0.657461
7 foo three -0.101462 1.746577
'''
三、多函数计算 agg()
df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
'B': np.random.randn(8),
'C': np.random.randn(8)})
df.groupby(["A"]).agg(['mean', np.sum])
'''
B C
mean sum mean sum
A
bar 0.224929 0.674786 -0.734798 -2.204393
foo -0.331954 -1.659772 -0.340527 -1.702633
'''
df.groupby(["A"])["B"].agg({"res1": np.mean,
"res2": np.sum})
'''
res1 res2
A
bar 0.224929 0.674786
foo -0.331954 -1.659772
'''
分组可用函数:
方法 | 描述 |
---|---|
count() | 统计分组中非空值、非NaN的数量 |
size() | 统计分组的大小,包括空值 |
sum() | 计算分组的和 |
mean() | 计算分组的平均值 |
prod() | 计算分组的积 |
first()、last()、nth(n) | 获取分组的第一个值、最后一个值、第n个值 |
min()、max() | 计算分组的最小值、最大值 |
std()、var() | 计算分组的标准差、方差 |
describe() | 生成描述统计学 |
df = pd.DataFrame({"data1": np.random.rand(5),
"data2": np.random.rand(5)},
index = list("abaab"))
'''
data1 data2
a 0.287221 0.781097
b 0.229732 0.532843
a 0.169996 0.979437
a 0.683406 0.360751
b 0.046675 0.658154
'''
df.groupby(level = 0).describe()
'''
data1 data2
a count 3.000000 3.000000
mean 0.380208 0.707095
std 0.269040 0.315911
min 0.169996 0.360751
25% 0.228608 0.570924
50% 0.287221 0.781097
75% 0.485313 0.880267
max 0.683406 0.979437
b count 2.000000 2.000000
mean 0.138203 0.595498
std 0.129441 0.088608
min 0.046675 0.532843
25% 0.092439 0.564170
50% 0.138203 0.595498
75% 0.183968 0.626826
max 0.229732 0.658154
'''
四、转换 transform()
分组后转换为与原DataFrame结构相同的DataFrame。
df = pd.DataFrame({'key': list('aabba'),
'data1': np.random.rand(5),
'data2': np.random.rand(5)})
'''
data1 data2 key
0 0.322917 0.127519 a
1 0.169597 0.394329 a
2 0.549236 0.802236 b
3 0.015143 0.568670 b
4 0.411133 0.328612 a
'''
df.groupby(["key"]).mean()
'''
data1 data2
key
a 0.301216 0.283487
b 0.282190 0.685453
'''
df.groupby(["key"]).transform(np.mean)
'''
data1 data2
0 0.301216 0.283487
1 0.301216 0.283487
2 0.282190 0.685453
3 0.282190 0.685453
4 0.301216 0.283487
'''
pd.merge(df,df.groupby(["key"]).mean(),left_on="key",right_index=True)
'''
data1_x data2_x key data1_y data2_y
0 0.322917 0.127519 a 0.301216 0.283487
1 0.169597 0.394329 a 0.301216 0.283487
4 0.411133 0.328612 a 0.301216 0.283487
2 0.549236 0.802236 b 0.282190 0.685453
3 0.015143 0.568670 b 0.282190 0.685453
'''
五、分组后应用自定义函数 apply()
apply(自定义函数名, 参数2, 参数3, …)
- 自定义函数(apply前面的分组???, 参数2, 参数3, …)
- apply前面的分组:双索引或多索引的DataFrame类型,最外层索引是分组名???
df = pd.DataFrame({'key': list('aabba'),
'data1': np.random.rand(5),
'data2': np.random.rand(5)})
'''
data1 data2 key
0 0.408519 0.153052 a
1 0.101206 0.478075 a
2 0.158971 0.394022 b
3 0.059524 0.625927 b
4 0.838733 0.963524 a
'''
df.groupby("key").apply(lambda x: x.mean())
'''
data1 data2
key
a 0.449486 0.531550
b 0.109248 0.509974
'''
def f1(group, col): # 返回按照col列排序后的分组
return group.sort_values(col)
df.groupby("key").apply(f1, "data1")
'''
data1 data2 key
key
a 1 0.101206 0.478075 a
0 0.408519 0.153052 a
4 0.838733 0.963524 a
b 3 0.059524 0.625927 b
2 0.158971 0.394022 b
'''
def f2(group, col): # 选取col列前两行的数据
return group[col][:2]
df.groupby("key").apply(f2, "data1")
'''
key
a 0 0.408519
1 0.101206
b 2 0.158971
3 0.059524
Name: data1, dtype: float64
'''
六、透视表 pivot_table()
pd.pivot_table(data, values=None, index=None, columns=None, aggfunc=‘mean’,
fill_value=None, margins=False, dropna=True, margins_name=‘All’)
- data:DataFrame对象
- values:要聚合的列或多列(列表)
- index:数据透视表的index,从原数据的列中筛选
- columns:数据透视表的columns,从原数据的列中筛选
- aggfunc:用于聚合的函数,默认为numpy.mean,支持numpy计算方法
df = pd.DataFrame({'date': pd.to_datetime(['2017-5-1', '2017-5-2', '2017-5-3'] * 3),
'key': list('abcdabcda'),
'val1': np.random.rand(9) * 10,
'val2': np.random.rand(9) * 10})
'''
date key val1 val2
0 2017-05-01 a 1.292234 3.649055
1 2017-05-02 b 1.836119 5.295825
2 2017-05-03 c 9.986584 7.534052
3 2017-05-01 d 9.333207 1.853681
4 2017-05-02 a 6.754704 1.831979
5 2017-05-03 b 2.824246 7.208884
6 2017-05-01 c 6.142462 8.362095
7 2017-05-02 d 4.500458 6.771704
8 2017-05-03 a 8.408800 9.921002
'''
pd.pivot_table(df, values = 'val1', index = 'date', columns = 'key', aggfunc = np.sum)
'''
key a b c d
date
2017-05-01 1.292234 NaN 6.142462 9.333207
2017-05-02 6.754704 1.836119 NaN 4.500458
2017-05-03 8.408800 2.824246 9.986584 NaN
'''
pd.pivot_table(df, values = ['val1', 'val2'], index = ['date', 'key'], aggfunc = 'sum')
'''
val1 val2
date key
2017-05-01 a 1.292234 3.649055
c 6.142462 8.362095
d 9.333207 1.853681
2017-05-02 a 6.754704 1.831979
b 1.836119 5.295825
d 4.500458 6.771704
2017-05-03 a 8.408800 9.921002
b 2.824246 7.208884
c 9.986584 7.534052
'''
七、交叉表 crosstab()
默认情况下,crosstab()计算因子的频率表,比如用于str的数据透视分析。
pd.crosstab(index, columns, rownames=None, colnames=None,
values=None, aggfunc=None, margins=False, dropna=True, normalize=False)
- index:行中用于分组的值,可以为Series类型
- columns: 列中用于分组的值
如果没有values和aggfunc,将计算频率表
- values:根据因子聚合的值数组,可选
- aggfunc:聚合函数,可选
- margins:是否添加行/列边距(小计),默认为False
- normalize:将所有值除以值的总和进行归一化,默认为False,为True时候显示百分比
如果crosstab只接收两个Series(数组),它将提供一个频率表。用index的唯一值,统计columns唯一值的出现次数。
df = pd.DataFrame({'A': [1, 2, 2, 2, 2],
'B': [3, 3, 4, 4, 4],
'C': [1, 1, np.nan, 1, 1]})
'''
A B C
0 1 3 1.0
1 2 3 1.0
2 2 4 NaN
3 2 4 1.0
4 2 4 1.0
'''
pd.crosstab(df['A'], [df['B'], df['C']])
'''
B 3 4
C 1.0 1.0
A
1 1 0
2 1 2
'''
pd.crosstab([df['A'], df['B']], df['C'])
'''
C 1.0
A B
1 3 1
2 3 1
4 2
'''
pd.crosstab(df['A'], df['B'])
'''
B 3 4
A
1 1 0
2 1 3
'''
相当于以A和B界定分组,计算出每组中第三个系列C的值
pd.crosstab(df['A'], df['B'], values = df['C'], aggfunc = np.sum)
'''
B 3 4
A
1 6.0 NaN
2 1.0 5.0
'''
pd.crosstab(df.A, df.B, margins = True)
'''
B 3 4 All
A
1 1 0 1
2 1 3 4
All 2 3 5
'''
pd.crosstab(df.A, df.B, normalize = True)
'''
B 3 4
A
1 0.2 0.0
2 0.2 0.6
'''