Python数据分析笔记----第十章数据聚合与分组操作

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值