文章目录
1. 拆分-应用-联合
拆分-应用-联合是由Hadley Wickham(许多流行R语言包的作者)创造的用于描述组操作的术语。
- 第一步,拆分。数据包含在pandas对象中,可以是Series、DataFrame或者其他数据结构中,之后根据你提供的一个或多个键分离到各个组中。分离操作是在数据对象的特定轴向上进行的。
- 第二步,应用。将一个函数应用到各个组中,产生新的值。
- 第三部,联合。将第二步产生的结果联合为一个结果对象。
2. 分组
分组对应拆分-应用-联合中的拆分步骤
分组绝大多数都是通过groupby()函数来实现的
groupby()函数传入的是一个分组键
分组键可以是多种形式,并且键不一定是完全相同的类型
- 与要分组的轴向长度一致的值列表或值数组
- DataFrame的列名
- 可以将分组轴向上的值和分组名称相匹配的字典或Series
- 可以在轴索引和索引中的单个标签上调用的函数
2.1 分组键为与要分组的轴向长度一致的值列表或值数组
In [3]: df = pd.DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one','two','one'],'data1':np.random.randn(5),'data2':np.random.randn(5)})
In [4]: df
Out[4]:
key1 key2 data1 data2
0 a one -0.294789 0.864142
1 a two 0.308868 0.816679
2 b one -0.028162 0.175393
3 b two -1.114972 0.451209
4 a one -1.083039 0.817825
In [5]: grouped = df['data1'].groupby(df['key1'])#传入的是df的一列,Series对象,可以视作是数组
In [6]: grouped#返回的是一个生成器
Out[6]: <pandas.core.groupby.generic.SeriesGroupBy object at 0x000002D70112D4E0>
In [7]: grouped.mean()
Out[7]:
key1
a -0.356320
b -0.571567
Name: data1, dtype: float64
In [12]: df['data1'].groupby([df['key1'],df['key2']]).mean()#可以以列表的形式传入多个分组键
Out[12]:
key1 key2
a one -0.688914
two 0.308868
b one -0.028162
two -1.114972
Name: data1, dtype: float64
In [8]: states = ['Ohio','California','Colifornia','Ohio','Ohio']
In [9]: years = np.array([2005,2005,2006,2005,2006])
In [10]: df['data1'].groupby([states,years]).mean()#可以以列表的形式传入多个分组键,每个键是一个数组,且长度与data1一致
Out[10]:
California 2005 0.308868
Colifornia 2006 -0.028162
Ohio 2005 -0.704881
2006 -1.083039
Name: data1, dtype: float64
从上面的grouped变量的输出结果,我们可以看出,groupby函数返回的是一个生成器,并没有进行任何的实际上的计算
2.2 分组键为列名
注意,直接传入一个或多个列名作为分组键时,被分类的对象一定是DataFrame对象,不能是DataFrame对象的某一列,传入的列名也必须是DataFrame对象中有的
In [15]: df
Out[15]:
key1 key2 data1 data2
0 a one -0.294789 0.864142
1 a two 0.308868 0.816679
2 b one -0.028162 0.175393
3 b two -1.114972 0.451209
4 a one -1.083039 0.817825
In [16]: df.groupby('key1').mean()#直接传入一个列名,对整个df进行分组,注意这里的返回结果中忽略了key2列
Out[16]:
data1 data2
key1
a -0.356320 0.832882
b -0.571567 0.313301
In [18]: df.groupby(['key1','key2']).mean()#可以以列表的形式传入多个列名,作为分组键
Out[18]:
data1 data2
key1 key2
a one -0.688914 0.840984
two 0.308868 0.816679
b one -0.028162 0.175393
two -1.114972 0.451209
注意到上面的df.groupby(‘key1’).mean()忽略的key2列,这是因为,mean()函数只能对数值数据进行计算,而key2列不是数组,所以会被排除在结果之外
2.3 使用字典和Series对象来分组
In [19]: people = pd.DataFrame(np.random.randn(5,5),index=['Job','Steve','Wes','Jim','Travis'],columns=['a','b','c','d' ,'e'])
In [20]: people
Out[20]:
a b c d e
Job -0.262621 -1.173377 0.853039 -0.936418 -0.066394
Steve 0.049563 -0.005865 0.260011 -0.364812 0.784902
Wes -0.551790 -0.396983 0.224848 -1.472888 -0.255783
Jim -0.415112 0.496094 1.152986 0.178381 -0.056376
Travis 0.648749 0.299355 0.758770 1.533886 -0.371593
In [21]: mapping = {'a':'red','b':'red','c':'blue','d':'blue','e':'red','f':'orange'}
In [22]: by_column = people.groupby(mapping,axis=1)
In [23]: by_column.size()
Out[23]:
blue 2
red 3
dtype: int64
In [24]: by_column.sum()#groupby返回的对象的聚集函数是没有axis参数的,因为这些聚集函数一定是应用到每一个分组中,不管轴向
Out[24]:
blue red
Job -0.083379 -1.502393
Steve -0.104802 0.828600
Wes -1.248040 -1.204556
Jim 1.331367 0.024607
Travis 2.292656 0.576511
2.4 使用函数分组
作为分组键传递的函数将会按照每个索引值调用一次,同时返回值会被用作分组名称。
In [8]: people
Out[8]:
a b c d e
Job 1.285676 0.202332 -1.024280 0.302843 0.353441
Steve 0.142570 -1.022175 -1.960104 -1.129355 0.328469
Wes -0.051612 -0.220906 -0.459788 1.094590 -1.856675
Jim -1.195870 -0.709341 0.697290 -0.288937 1.483106
Travis -0.553946 0.417555 -0.992368 0.424146 -2.163491
In [9]: people.groupby(len).sum()#分组键为len函数,会对people中的每个索引调用一遍,然后将返回值作为分组名称
Out[9]:
a b c d e
3 0.038194 -0.727915 -0.786779 1.108496 -0.020128
5 0.142570 -1.022175 -1.960104 -1.129355 0.328469
6 -0.553946 0.417555 -0.992368 0.424146 -2.163491
In [10]: key_list = ['one','one','one','two','two']
In [11]: people.groupby([len,key_list]).sum()#分组键可以为函数名称和列表的组合
Out[11]:
a b c d e
3 one 1.234064 -0.018573 -1.484068 1.397433 -1.503234
two -1.195870 -0.709341 0.697290 -0.288937 1.483106
5 one 0.142570 -1.022175 -1.960104 -1.129355 0.328469
6 two -0.553946 0.417555 -0.992368 0.424146 -2.163491
2.5 根据索引层级分组
In [20]: columns = pd.MultiIndex.from_arrays([['US','US','US','JP','JP'],[1,3,5,1,3]])
In [21]: columns
Out[21]:
MultiIndex([('US', 1),
('US', 3),
('US', 5),
('JP', 1),
('JP', 3)],
)
In [22]: hire_df = pd.DataFrame(np.random.randn(4,5),columns=columns)
In [23]: hire_df
Out[23]:
US JP
1 3 5 1 3
0 0.100497 -1.560053 1.229384 0.902571 -2.545500
1 -1.934847 -0.222499 -0.718524 1.096697 1.781109
2 -0.775430 -0.703403 -0.261697 -0.246785 -0.679584
3 0.952827 0.052682 -0.182493 -2.445421 -0.453074
In [24]: hire_df.groupby(level=0,axis=1).count()#传入的层级序号0,表示按照最外层的索引为分组键
Out[24]:
JP US
0 2 3
1 2 3
2 2 3
3 2 3
2.6 遍历各分组
GroupBy对象支持迭代,迭代GroupBy对象,会生成一个包含组名和数据块的2维元组序列
In [13]: df
Out[13]:
key1 key2 data1 data2
0 a one 0.400552 -1.074171
1 a two -0.705424 0.723268
2 b one 0.702501 1.415966
3 b two 1.584459 0.945358
4 a one -0.249631 -0.987256
In [14]: for name , group in df.groupby('key1'):
...: print(name)
...: print(group)
...:
a
key1 key2 data1 data2
0 a one 0.400552 -1.074171
1 a two -0.705424 0.723268
4 a one -0.249631 -0.987256
b
key1 key2 data1 data2
2 b one 0.702501 1.415966
3 b two 1.584459 0.945358
多个分组键的情况下,元组中的第一个元素是键值的元组
In [15]: for (key1,key2),group in df.groupby(['key1','key2']):
...: print((key1,key2))
...: print(group)
...:
('a', 'one')
key1 key2 data1 data2
0 a one 0.400552 -1.074171
4 a one -0.249631 -0.987256
('a', 'two')
key1 key2 data1 data2
1 a two -0.705424 0.723268
('b', 'one')
key1 key2 data1 data2
2 b one 0.702501 1.415966
('b', 'two')
key1 key2 data1 data2
3 b two 1.584459 0.945358
将分组后的数据块转换成字典,方便从中去除某一块数据块,执行一些其他的操作
In [16]: piece = dict(list(df.groupby('key1')))
In [17]: piece['a']
Out[17]:
key1 key2 data1 data2
0 a one 0.400552 -1.074171
1 a two -0.705424 0.723268
4 a one -0.249631 -0.987256
2.7 选择一列或所有列的子集
df.groupby(‘key1’)[‘data1’]等价于df[‘data1’].groupby(df[‘key1’]),这种情况产生的GroupBy对象的每一个分组是Series对象
df.groupby(‘key1’)[[‘data2’]]等价于df[[‘data2’]].groupby(df[‘key1’]),这种情况由于传入的是一个数组,因此产生的GroupBy对选哪个的每一个分组是DataFrame对象。
In [18]: df.groupby('key1')['data1']#SeriesGroupBy对象
Out[18]: <pandas.core.groupby.generic.SeriesGroupBy object at 0x0000024E228A4F98>
In [19]: df.groupby('key1')[['data1']]#DataFrameGroupBy对象
Out[19]: <pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000024E228A4E80>
3. 数据聚合
聚合:是指所有根据数据产生标量值的数据转换过程
GroupBy对象优化的常见的聚集方法
- count 分组中非NA值的数量
- sum() 非NA值的累和
- mean() 非NA值的均值
- median() 非NA值的算术中位数
- std(),var() 非NA值的算术中位数
- min(),max()非NA值的最小值、最大值
- prod() 非NA值的乘积
- first()、last()非NA值的第一个和最后一个值
可以自定义聚合函数,自定义的聚合函数有一点要求,就是返回值必须是一个标量值,然后通过aggregate()或agg()方法传递进去
另外对GroupBy对象调用聚合函数时,会将聚合函数对每一个分组调用一次,然后将返回的结果组合成一个结果集
In [27]: df
Out[27]:
key1 key2 data1 data2
0 a one 0.400552 -1.074171
1 a two -0.705424 0.723268
2 b one 0.702501 1.415966
3 b two 1.584459 0.945358
4 a one -0.249631 -0.987256
In [28]: grouped = df.groupby('key1')
In [29]: grouped
Out[29]: <pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000024E22892BE0>
In [30]: def peak_to_peak(arr):
...: return arr.max() - arr.min()
...:
...:
In [31]: grouped.agg(peak_to_peak)
Out[31]:
data1 data2
key1
a 1.105976 1.797439
b 0.881958 0.470608
自定义的聚合函数通常比GroupBy对象优化的聚合函数慢得多,这是因为在构造中间组数据块时有额外开销(函数调用、数据重排列)
3.1 逐列及多函数应用
数据
In [35]: tips = pd.read_csv('F:/python程序文件/jupyter/pydata-book-2nd-edition/examples/tips.csv')
In [36]: tips['tip_pct'] = tips['tip']/tips['total_bill']
In [37]: tips.head(5)
Out[37]:
total_bill tip smoker day time size tip_pct
0 16.99 1.01 No Sun Dinner 2 0.059447
1 10.34 1.66 No Sun Dinner 3 0.160542
2 21.01 3.50 No Sun Dinner 3 0.166587
3 23.68 3.31 No Sun Dinner 2 0.139780
4 24.59 3.61 No Sun Dinner 4 0.146808
In [38]: grouped = tips.groupby(['day','smoker'])
3.1.1 对某一列应用多个聚合函数
In [39]: grouped['tip_pct'].agg(['mean','std',peak_to_peak])#自定义函数不需要加引号,优化的聚合函数需要加引号
Out[39]:
mean std peak_to_peak
day smoker
Fri No 0.151650 0.028123 0.067349
Yes 0.174783 0.051293 0.159925
Sat No 0.158048 0.039767 0.235193
Yes 0.147906 0.061375 0.290095
Sun No 0.160113 0.042347 0.193226
Yes 0.187250 0.154134 0.644685
Thur No 0.160298 0.038774 0.193350
Yes 0.163863 0.039389 0.151240
In [40]: grouped['tip_pct'].agg([('foo','mean'),('bar',np.std)])#还可以对应用的函数取别名,只有优化的函数需要加引号
Out[40]:
foo bar
day smoker
Fri No 0.151650 0.028123
Yes 0.174783 0.051293
Sat No 0.158048 0.039767
Yes 0.147906 0.061375
Sun No 0.160113 0.042347
Yes 0.187250 0.154134
Thur No 0.160298 0.038774
Yes 0.163863 0.039389
3.1.2 对多列应用多个聚合函数
In [41]: grouped['tip_pct','total_bill'].agg(['count','mean','max'])#也可以为每个函数起别名
Out[41]:
tip_pct total_bill
count mean max count mean max
day smoker
Fri No 4 0.151650 0.187735 4 18.420000 22.75
Yes 15 0.174783 0.263480 15 16.813333 40.17
Sat No 45 0.158048 0.291990 45 19.661778 48.33
Yes 42 0.147906 0.325733 42 21.276667 50.81
Sun No 57 0.160113 0.252672 57 20.506667 48.17
Yes 19 0.187250 0.710345 19 24.120000 45.35
Thur No 45 0.160298 0.266312 45 17.113111 41.19
Yes 17 0.163863 0.241255 17 19.190588 43.11
In [42]: grouped['tip_pct','total_bill'].agg([('zhangfan','count'),'mean','max'])#为count函数起了别名
Out[42]:
tip_pct total_bill
zhangfan mean max zhangfan mean max
day smoker
Fri No 4 0.151650 0.187735 4 18.420000 22.75
Yes 15 0.174783 0.263480 15 16.813333 40.17
Sat No 45 0.158048 0.291990 45 19.661778 48.33
Yes 42 0.147906 0.325733 42 21.276667 50.81
Sun No 57 0.160113 0.252672 57 20.506667 48.17
Yes 19 0.187250 0.710345 19 24.120000 45.35
Thur No 45 0.160298 0.266312 45 17.113111 41.19
Yes 17 0.163863 0.241255 17 19.190588 43.11
3.1.3 对不同的列应用不同的聚合函数
In [43]: grouped.agg({'tip':np.max,'size':'sum'})
Out[43]:
tip size
day smoker
Fri No 3.50 9
Yes 4.73 31
Sat No 9.00 115
Yes 10.00 104
Sun No 6.00 167
Yes 6.50 49
Thur No 6.70 112
Yes 5.00 40
############也可以对不同的列应用不同数量的不同的聚合函数
In [44]: grouped.agg({'tip_pct':['min','max','mean','std'],'size':'sum'})
Out[44]:
tip_pct size
min max mean std sum
day smoker
Fri No 0.120385 0.187735 0.151650 0.028123 9
Yes 0.103555 0.263480 0.174783 0.051293 31
Sat No 0.056797 0.291990 0.158048 0.039767 115
Yes 0.035638 0.325733 0.147906 0.061375 104
Sun No 0.059447 0.252672 0.160113 0.042347 167
Yes 0.065660 0.710345 0.187250 0.154134 49
Thur No 0.072961 0.266312 0.160298 0.038774 112
Yes 0.090014 0.241255 0.163863 0.039389 40
3.2 返回不含行索引的聚合数据
默认情况下,对GroupBy对象使用聚合函数,会返回以分组键构成的索引,但是可以在分组是传入as_index=False来禁用分组键作为索引,而成为结果集中的一列。
In [45]: tips.groupby(['day','smoker'],as_index=False).mean()
Out[45]:
day smoker total_bill tip size tip_pct
0 Fri No 18.420000 2.812500 2.250000 0.151650
1 Fri Yes 16.813333 2.714000 2.066667 0.174783
2 Sat No 19.661778 3.102889 2.555556 0.158048
3 Sat Yes 21.276667 2.875476 2.476190 0.147906
4 Sun No 20.506667 3.167895 2.929825 0.160113
5 Sun Yes 24.120000 3.516842 2.578947 0.187250
6 Thur No 17.113111 2.673778 2.488889 0.160298
7 Thur Yes 19.190588 3.030000 2.352941 0.163863
4. apply(应用)
groupby.apply(函数名),对每一个分组调用传入的参数,然后使用pd.concate函数将结果粘贴在一起,并使用分组名作为各组的标签。
In [46]: def top(df,n=5,column='tip_pct'):
...: return df.sort_values(by=column)[-n:]
...:
...:
In [47]: tips.groupby('smoker').apply(top)
Out[47]:
total_bill tip smoker day time size tip_pct
smoker
No 88 24.71 5.85 No Thur Lunch 2 0.236746
185 20.69 5.00 No Sun Dinner 5 0.241663
51 10.29 2.60 No Sun Dinner 2 0.252672
149 7.51 2.00 No Thur Lunch 2 0.266312
232 11.61 3.39 No Sat Dinner 2 0.291990
Yes 109 14.31 4.00 Yes Sat Dinner 2 0.279525
183 23.17 6.50 Yes Sun Dinner 4 0.280535
67 3.07 1.00 Yes Sat Dinner 1 0.325733
178 9.60 4.00 Yes Sun Dinner 2 0.416667
172 7.25 5.15 Yes Sun Dinner 2 0.710345
In [48]: tips.groupby('smoker').apply(top,n=6,column='total_bill')#可以在后面直接传入函数需要的参数
Out[48]:
total_bill tip smoker day time size tip_pct
smoker
No 112 38.07 4.00 No Sun Dinner 3 0.105070
23 39.42 7.58 No Sat Dinner 4 0.192288
142 41.19 5.00 No Thur Lunch 5 0.121389
156 48.17 5.00 No Sun Dinner 6 0.103799
59 48.27 6.73 No Sat Dinner 4 0.139424
212 48.33 9.00 No Sat Dinner 4 0.186220
Yes 95 40.17 4.73 Yes Fri Dinner 4 0.117750
184 40.55 3.00 Yes Sun Dinner 2 0.073983
197 43.11 5.00 Yes Thur Lunch 4 0.115982
102 44.30 2.50 Yes Sat Dinner 3 0.056433
182 45.35 3.50 Yes Sun Dinner 3 0.077178
170 50.81 10.00 Yes Sat Dinner 3 0.196812
5. 压缩分组键
分组是传入group_keys=False,就可以忽略分组键作为索引,而将分组键作为结果集中的一列,索引列为对应的行在原数据中的索引
与as_index=False的区别是,group_by=False会保留原来的索引,而as_index=False则是不保留任何索引,而生成一个整数索引。
In [53]: tips.groupby('smoker',group_keys=False).apply(top)
Out[53]:
total_bill tip smoker day time size tip_pct
88 24.71 5.85 No Thur Lunch 2 0.236746
185 20.69 5.00 No Sun Dinner 5 0.241663
51 10.29 2.60 No Sun Dinner 2 0.252672
149 7.51 2.00 No Thur Lunch 2 0.266312
232 11.61 3.39 No Sat Dinner 2 0.291990
109 14.31 4.00 Yes Sat Dinner 2 0.279525
183 23.17 6.50 Yes Sun Dinner 4 0.280535
67 3.07 1.00 Yes Sat Dinner 1 0.325733
178 9.60 4.00 Yes Sun Dinner 2 0.416667
172 7.25 5.15 Yes Sun Dinner 2 0.710345
6. 分位数与桶分析
pd.cut()返回的对象可以直接传给groupby()作为分组键
In [56]: frame = pd.DataFrame({'data1':np.random.randn(1000),'data2':np.random.randn(1000)})
In [57]: quartiles = pd.cut(frame.data1,4)
In [59]: def get_stats(group):
...: return {'min':group.min(),'max':group.max(),'count':group.count(),'mean':group.mean()}
...:
...:
In [61]: frame.data2.groupby(quartiles).apply(get_stats).unstack()
Out[61]:
min max count mean
data1
(-3.123, -1.552] -1.582516 2.280941 54.0 0.148933
(-1.552, 0.0122] -3.350551 2.793353 462.0 -0.037190
(0.0122, 1.576] -3.041937 3.577188 435.0 -0.016351
(1.576, 3.141] -1.627630 2.195348 49.0 0.104658
7. 数据透视表与交叉表
7.1 数据透视表
pivot_table()的内在使用的groupby和分层索引的重塑操作来实现的。
df.pivot_table(列名,index,columns,aggfunc,margin,fill_value,dropna)
- 列名:表示在结果集中保留那几列,可以只传入一个列名,也可以以列表的形式传入多个列名
- index:表示结果集中那几列作为索引,可以只传入一个列名,也可以以列表的形式传入多个列名。index是分组键
- columns:表示结果集中那几列作为columns,可以只传入一个列名,也可以以列表的形式传入多个列名
- aggfunc:表示pivot_table对每一组应用的函数,默认为’mean’,即求每一组的平均值
- margin:bool变量,默认为False,表示不需要添加All列,如果为True则会在结果集中的每一层添加一列All,表示相应层中所有数据的分组统计值
- fill_value:有时候结果集中会产生空值,需要传入一个fill_value参数,来填充空值
- dropna:bool变量,默认为False,如果为True则会删除结果集所有值为NA的列
In [62]: tips
Out[62]:
total_bill tip smoker day time size tip_pct
0 16.99 1.01 No Sun Dinner 2 0.059447
1 10.34 1.66 No Sun Dinner 3 0.160542
2 21.01 3.50 No Sun Dinner 3 0.166587
3 23.68 3.31 No Sun Dinner 2 0.139780
4 24.59 3.61 No Sun Dinner 4 0.146808
.. ... ... ... ... ... ... ...
239 29.03 5.92 No Sat Dinner 3 0.203927
240 27.18 2.00 Yes Sat Dinner 2 0.073584
241 22.67 2.00 Yes Sat Dinner 2 0.088222
242 17.82 1.75 No Sat Dinner 2 0.098204
243 18.78 3.00 No Thur Dinner 2 0.159744
[244 rows x 7 columns]
In [63]: tips.pivot_table(['tip_pct','total_bill'],index=['time','size','smoker'],columns='day',aggfunc='sum',fill_valu
...: e=0)
Out[63]:
tip_pct total_bill
day Fri Sat Sun Thur Fri Sat Sun Thur
time size smoker
Dinner 1 No 0.000000 0.137931 0.000000 0.000000 0.00 7.25 0.00 0.00
Yes 0.000000 0.325733 0.000000 0.000000 0.00 3.07 0.00 0.00
2 No 0.418867 4.067615 4.559198 0.159744 57.70 400.66 422.34 18.78
Yes 1.370377 4.162693 2.494717 0.000000 138.09 491.71 262.50 0.00
3 No 0.000000 1.855926 1.679296 0.000000 0.00 263.55 225.26 0.00
Yes 0.000000 0.869969 0.610639 0.000000 0.00 195.62 107.50 0.00
4 No 0.000000 1.050673 2.370288 0.000000 0.00 213.32 422.57 0.00
Yes 0.117750 0.747088 0.386740 0.000000 40.17 175.07 57.82 0.00
5 No 0.000000 0.000000 0.413857 0.000000 0.00 0.00 50.54 0.00
Yes 0.000000 0.106572 0.065660 0.000000 0.00 28.15 30.46 0.00
6 No 0.000000 0.000000 0.103799 0.000000 0.00 0.00 48.17 0.00
Lunch 1 No 0.000000 0.000000 0.000000 0.181728 0.00 0.00 0.00 10.07
Yes 0.223776 0.000000 0.000000 0.000000 8.58 0.00 0.00 0.00
2 No 0.000000 0.000000 0.000000 5.644187 0.00 0.00 0.00 481.33
Yes 0.909843 0.000000 0.000000 2.064953 65.36 0.00 0.00 227.42
3 No 0.187735 0.000000 0.000000 0.168492 15.98 0.00 0.00 41.46
Yes 0.000000 0.000000 0.000000 0.409904 0.00 0.00 0.00 35.18
4 No 0.000000 0.000000 0.000000 0.416757 0.00 0.00 0.00 86.11
Yes 0.000000 0.000000 0.000000 0.310819 0.00 0.00 0.00 63.64
5 No 0.000000 0.000000 0.000000 0.121389 0.00 0.00 0.00 41.19
6 No 0.000000 0.000000 0.000000 0.521118 0.00 0.00 0.00 91.15
7.2 交叉表
pd.crosstable()数据透视表的一个特殊情况,计算的是分组中的频率
In [66]: tips.head()
Out[66]:
total_bill tip smoker day time size tip_pct
0 16.99 1.01 No Sun Dinner 2 0.059447
1 10.34 1.66 No Sun Dinner 3 0.160542
2 21.01 3.50 No Sun Dinner 3 0.166587
3 23.68 3.31 No Sun Dinner 2 0.139780
4 24.59 3.61 No Sun Dinner 4 0.146808
In [67]: pd.crosstab(tips.smoker,tips.time,margins=True)#交叉表统计是频率
Out[67]:
time Dinner Lunch All
smoker
No 106 45 151
Yes 70 23 93
All 176 68 244
In [68]: pd.crosstab([tips.smoker,tips.time],tips.day,margins=True)#可以传入一个列表
Out[68]:
day Fri Sat Sun Thur All
smoker time
No Dinner 3 45 57 1 106
Lunch 1 0 0 44 45
Yes Dinner 9 42 19 0 70
Lunch 6 0 0 17 23
All 19 87 76 62 244