本文是对《利用Python进行数据分析》中关于groupby进行分组聚合和运算的一个回顾性总结2。

目录

利用groupby进行数据聚合

分组级运算和转换

透视表

交叉表(了解)

案例

利用groupby进行数据聚合

 含义:对于groupby后对象的数据操作,聚合指的是任何能够从数组产生标量值的数据转换过程。
 分位数操作quantile
        实例:# 此处对于聚合,指的是任何能够从数组 产生标量值的数据转换过程。 除了可以使用mean,count,sum等常见聚合运算外,还可以使用自己创造的聚合运算,还可以调用分组对象上已经定义好的任何方法。 如quantile 可以计算Series 或 DataFrame列的样本分位数 。

df = DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],'key2' : ['one', 'two', 'one', 'two', 'one'],'data1' : np.random.randn(5),'data2' : np.random.randn(5)})
grouped=df.groupby('key1')
grouped['data1'].quantile(0.9)

注意: 虽然quantile 并没有明确的实现于 groupby ,但它是一个Series方法,所以这里是能用的,实际上,groupby 会高效的对Series进行切片,然后对各片调用piece.quantile(0.9),最后将这些结果组装成最终结果

输出
key1
a    1.668413
b   -0.523068
Name: data1, dtype: float64

 describe函数
实例:统计函数describe会对grouped对象中的各列都进行describe包含的函数操作。
            grouped.describe() # 注意,有些方法(如describe)也是可以用在这里的,即使严格来讲,它们并非聚合运算:
常见自带聚合函数
        常见的自带的部分聚合函数可以直接用,性能更快。


            
自定义聚合函数
    实例: 使用 自己的聚合函数,只需将其传入aggregate 或 agg 方法即可

# 使用 自己的聚合函数,只需将其传入aggregate 或 agg 方法即可
def peak_to_peak(arr):return arr.max()-arr.min()
grouped.agg(peak_to_peak)

输出
           data1     data2
key1                    
a     2.170488  1.300498
b     0.036292  0.487276
性能:
            自定义聚合函数要比表中那些经过优化的函数慢得多。这是因为在构造中间分组数据块时存在非常大的开销(函数调用、数据重排等)。

面向列的多函数应用
对于自定义或者自带的函数都可以用agg传入一次应用多个函数 。传入函数组成的list。所有的列都会应用这组函数。
实例

# 如果使用 你自己的聚合函数,只需将其传入aggregate 或 agg 方法即可
grouped=tips.groupby(['sex','smoker'])
def peak_to_peak(arr):return arr.max()-arr.min()
grouped.agg(peak_to_peak)
# # 可以对不同的列使用不同的聚合函数,或一次应用多个函数
# 如果传入一组函数 或函数名 ,得到的结果DataFrame 的列就会以 相应的函数命名
grouped_pct.agg(['mean','std',peak_to_peak]) #将自带mean函数等也可以用agg传入

输出
#tips数据的前3行
     total_bill   tip     sex smoker  day    time  size   tip_pct
0       16.99  1.01  Female     No  Sun  Dinner     2  0.059447
1       10.34  1.66    Male     No  Sun  Dinner     3  0.160542
2       21.01  3.50    Male     No  Sun  Dinner     3  0.166587
                         mean       std  peak_to_peak
sex    smoker                                  
Female No      0.156921  0.036421      0.195876
       Yes     0.182150  0.071595      0.360233
Male   No      0.160669  0.041849      0.220186
       Yes     0.152771  0.090588      0.674707

对不同的列进行不同的函数操作
传入元素为带着函数的元组的list
实例: 注意如果传入agg 的是一个由(name,function)元组组成的列表,则各元组的第一个元素就会被用作DataFrame的列名(可以将这种二元元组列表看做一个有序映射)

# 并非一定要接受GroupBy自动给出的那些列名,特别是lambda函数,它们的名称是'<lambda>',这样的辨识度就很低了(通过函数的name属性看看就知道了)。因此,如果传入agg 的是一个由(name,function)元组组成的列表,则各元组的第一个元素就会被用作DataFrame的列名(可以将这种二元元组列表看做一个有序映射):
grouped_pct=grouped['tip_pct']
grouped_pct.agg([('foo','mean'),('bar',np.std)]) # 如下面结果列中的列名即元组的第一个元素 .

输出
                          foo            bar
sex    smoker                    
Female No      0.156921  0.036421
            Yes     0.182150  0.071595
Male     No      0.160669  0.041849
            Yes     0.152771  0.090588

以'无层次索引'的形式返回聚合数据
        需要在groupby的时候就指定as_index=False。这样就不会根据依据的对象形成层次化索引。默认是为true 。参数 group_keys等价与as_index。
实例1
 asind=tips.groupby(['sex','smoker'],as_index=False).mean() # 唯一的分组键组成的索引(可能还是层次化的)。由于并不总是需要如此,所以你可以向groupby传入as_index=False以禁用该功能,这样在应用函数操作grouped对象时,就不会带这分组键作为索引了,而将补充整型值索引,注意 分组的依据将形成列体现在结果中。
print(asind)
                    输出
         sex smoker  total_bill          tip            size   tip_pct
0  Female     No   18.105185  2.773519  2.592593  0.156921
1  Female    Yes   17.977879  2.931515  2.242424  0.182150
2    Male     No   19.791237  3.113402  2.711340  0.160669
3    Male    Yes   22.284500  3.051167  2.500000  0.152771
实例2
 print(tips.groupby(['sex','smoker'],as_index=True).mean()) # 会形成层次化索引
输出
                              total_bill       tip        size        tip_pct
sex    smoker                                          
Female No       18.105185  2.773519  2.592593  0.156921
          Yes      17.977879  2.931515  2.242424  0.182150
Male   No       19.791237  3.113402  2.711340  0.160669
         Yes      22.284500  3.051167  2.500000  0.152771

分组级运算和转换

增加列名后缀,将同后缀的merge到一起,这样将运算的值也带到了后面,实现同放一起看了。
   函数:.add_prefix('mean_')
   实例:

 k1_means = df.groupby('key1').mean().add_prefix('mean_') # 对于聚合后运算对象结果中的列增加后缀名以区分不是原来的属性了
k1_means

原数据df[:3]为:
      data1     data2 key1 key2
0 -0.204708  1.393406    a  one
1  0.478943  0.092908    a  two
2 -0.519439  0.281746    b  one

输出: 
           mean_data1  mean_data2
key1                        
a       0.746672    0.910916
b      -0.537585    0.525384

print(df.head(2))
print(pd.merge(df,k1_means,left_on='key1',right_index=True)) # 将同后缀的merge到一起,这样成功将运算的值也带到了后面,实现同一个看了。

输出
 data1  data2 key1 key2
0  -0.20   1.39    a  one
1   0.48   0.09    a  two
   data1  data2 key1 key2  mean_data1  mean_data2
0  -0.20   1.39    a  one        0.75       0.910
1   0.48   0.09    a  two        0.75       0.910
4   1.97   1.25    a  one        0.75       0.910
2  -0.52   0.28    b  one       -0.54       0.525
3  -0.56   0.77    b  two       -0.54       0.525

拆分与组合apply
        含义: 最一般化的groupby 方法是apply ,apply会将待处理的对象拆分成多个片段,然后对各片段调用传入的函数,最后尝试将各片段组合到一起。
实例

tips=tips.round(2)
print(tips[:3])
# 小费 数据集,根据分组选出最高的 5个tip_pct值
#首先 编写一个选取指定列具有最大值的行的函数
def top(df,n=5,column='tip_pct'):return df.sort_index(by=column)[-n:]
# 如果对smoker 分组,并用该函数调用apply
print(tips.groupby('smoker').apply(top))

上面的运算实质是 top函数在DataFrame的各个片段上调用,然后结果由 pandas.concat 组装到一起,并以分组名称进行了标记。于是,最终结果有了一个层次化的索引,其内层索引值来源于 原 DataFrame
                    输出
       total_bill   tip     sex   smoker  day    time  size  tip_pct
0       16.99  1.01  Female     No  Sun  Dinner     2     0.06
1       10.34  1.66    Male     No  Sun  Dinner     3     0.16
2       21.01  3.50    Male     No  Sun  Dinner     3     0.17
            total_bill   tip     sex smoker   day    time  size  tip_pct
smoker                                                                  
No     185       20.69  5.00    Male     No   Sun  Dinner     5     0.24
       88        24.71  5.85    Male     No  Thur   Lunch     2     0.24
       51        10.29  2.60  Female     No   Sun  Dinner     2     0.25
       149        7.51  2.00    Male     No  Thur   Lunch     2     0.27
       232       11.61  3.39    Male     No   Sat  Dinner     2     0.29
Yes    109       14.31  4.00  Female    Yes   Sat  Dinner     2     0.28
       183       23.17  6.50    Male    Yes   Sun  Dinner     4     0.28
       67         3.07  1.00  Female    Yes   Sat  Dinner     1     0.33
       178        9.60  4.00  Female    Yes   Sun  Dinner     2     0.42
       172        7.25  5.15    Male    Yes   Sun  Dinner     2     0.71
                # 如果传给apply的函数能够接受其他参数或关键词,则可将这些内容放在函数名后面一并传入 
print(tips.groupby(['smoker','day']).apply(top,n=1,column='total_bill'))
                    输出
                        
                 total_bill    tip     sex smoker   day    time  size  tip_pct
smoker day                                                                    
No     Fri  94        22.75   3.25  Female     No   Fri  Dinner     2     0.14
       Sat  212       48.33   9.00    Male     No   Sat  Dinner     4     0.19
       Sun  156       48.17   5.00    Male     No   Sun  Dinner     6     0.10
       Thur 142       41.19   5.00    Male     No  Thur   Lunch     5     0.12
Yes    Fri  95        40.17   4.73    Male    Yes   Fri  Dinner     4     0.12
       Sat  170       50.81  10.00    Male    Yes   Sat  Dinner     3     0.20
       Sun  182       45.35   3.50    Male    Yes   Sun  Dinner     3     0.08
       Thur 197       43.11   5.00  Female    Yes  Thur   Lunch     4     0.12
   除这些基本用法之外,能否充分发挥apply的威力很大程度上取决于你的创造力。传入的那个函数能做什么全由你说了算,它只需返回一个pandas对象或标量值即可。
禁止分组键
        通常情况下,groupby 的分组键 会跟原始对象的索引共同构成 结果对象中的层次化索引。将group_keys=False传入groupby即可禁止这种效果。等价与as_index=False
   例子

print(tips.groupby('smoker').apply(top))
print("**"*6)
print(tips.groupby('smoker',group_keys=False).apply(top)) # 这个smoke的值就未出现在索引中了。
print("**"*6)
print(tips.groupby('smoker',as_index=dex=False).apply(top)) # group_keys等价与as_index

分位数和桶
        pandas有一些能根据指定面元或样本分位数将数据拆分成多块的工具(比如cut和qcut)。将这些函数跟groupby与apply结合起来,就能非常轻松地实现对数据集的桶(bucket)或分位数(quantile)分析了

注意:  由 cut 返回的 对象可直接用于groupby 。
例子cut

def get_stats(group):return {'min':group.min(),'max':group.max(),'count':group.count(),'mean':group.mean()} # 注意此用字典返回,方便后续用unstack
frame=DataFrame({'data1':np.random.randn(1000),'data2':np.random.randn(1000)})
factor=pd.cut(frame.data1,4) # 等长的桶
grouped=frame.data2.groupby(factor)
print(grouped.apply(get_stats).unstack())

输出
                           count       max      mean       min
data1                                               
(-2.956, -1.23]   96.0  1.670835 -0.041782 -3.399312
(-1.23, 0.489]   602.0  3.260383 -0.014862 -2.989741
(0.489, 2.208]   291.0  2.954439  0.091055 -3.745356
(2.208, 3.928]    11.0  1.765640  0.055158 -1.929776
例子qcut

# Return quantile numbers
grouping = pd.qcut(frame.data1, 10, labels=False) #qcut ,根据样本分位数 得到大小相等的桶,传入lbels=False 即可值获取分位数的编号。grouped = frame.data2.groupby(grouping) #  groupby的依据直接应用qcut划分得到的桶
# print(grouped.apply(get_stats))
grouped.apply(get_stats).unstack() # unstack 转化为桶。

输出               
       count       max      mean       min
data1                                     
0      100.0  2.146716 -0.061124 -3.018842
1      100.0  2.038456 -0.057383 -2.641014
2      100.0  2.285401  0.082387 -2.453248
3      100.0  2.903300 -0.057825 -2.901831
4      100.0  2.209647  0.007647 -2.251291
5      100.0  2.497837 -0.056052 -3.108915
6      100.0  2.228700 -0.044572 -1.866563
7      100.0  2.430878  0.033692 -3.333767
8      100.0  2.215585 -0.001622 -2.428129
9      100.0  1.716892 -0.079520 -2.494075
 填充缺失值
        对于groupby后得到的对象中缺失值的填充,apply去应用填充的函数或者关于相应列或行索引与填充值的字典映射
fill_mean=lambda g : g.fillna(g.mean())
data.groupby(group_key).apply(fill_mean) # 可以用分组平均值去填充NA值 
fill_values={'East':0.5,'West':-1} # 也可以在代码中预定义各组的填充值。其中East和west均为是分组依据中值(即groupby后形成的索引的一个值
fill_func=lambda g : g.fillna(fill_values[g.name]) # 由于分组具有一个name属性,所以此可以拿来用下。注意此用的g.name. 注意 fill_values里面的key要在groupby 中的值里。
data.groupby(group_key).apply(fill_func)

计算相关性
        列与列的相关性
            SeriesA.corr(SeriesB)
 实例
# Annual correlation of Apple with Microsoft
by_year.apply(lambda g: g['AAPL'].corr(g['MSFT']))
        dataframe与列的相关性
            dfA.corr(seriesB)

透视表

 含义
        透视表pivot tables是各种电子表格程序和其他数据分析软件中一种常见的数据汇总工具。 它根据一个或多个键对数据进行聚合,并根据行和列上的分组键将数据分配到各个矩形区域中。

在Python和pandas中,groupby功能以及(能够利用层次化索引的)重塑运算制作透视表。DataFrame有一个pivot_table方法,此外还有一个顶级的pandas.pivot_table函数,但pivot_table能更方便。除能为groupby提供便利之外,pivot_table还可以添加分项小计,也叫做margins。
           
  参数


 案例
        数据准备
print(tips.head(2))
            
   total_bill   tip     sex smoker  day    time  size  tip_pct
0       16.99  1.01  Female     No  Sun  Dinner     2     0.06
1       10.34  1.66    Male     No  Sun  Dinner     3     0.16

# 假设我想要根据day和smoker计算分组平均数(注意pivot_table的默认聚合类型为求平均),并将day和smoker放到行上:

tips=tips.round(2)
print(tips.pivot_table(index=['sex','smoker']))

输出
                           size            tip            tip_pct  total_bill
sex    smoker                                          
Female No      2.592593  2.773519  0.156852   18.105185
           Yes     2.242424  2.931515  0.182424   17.977879
Male   No      2.711340  3.113402  0.161031   19.791237
          Yes     2.500000  3.051167  0.152667   22.284500
 # 等价于
tips.groupby(['sex','smoker']).mean().round(2) #用groupby 做. 同上面的结果是一样的(只是排列顺序有差别)
 输出
                          total_bill   tip  size  tip_pct
sex    smoker                                 
Female No           18.11  2.77  2.59     0.16
           Yes          17.98  2.93  2.24     0.18
Male   No           19.79  3.11  2.71     0.16
          Yes          22.28  3.05  2.50     0.15
        # pivot_table相比groupby能更方便
# 假设我们只想聚合tip_pct和size,而且想根据time进行分组。我将smoker放到列上,把day放到行上:   注意此时用groupby 就不好做了,而此时用pivot_table 很好做
tips.pivot_table(['tip_pct','size'],index=['sex','day'],columns='smoker').round(2)# 注意参数index里表示行的依据

输出
                        size         tip_pct      
smoker         No   Yes      No   Yes
sex    day                           
Female Fri   2.50  2.00    0.16  0.21
       Sat   2.31  2.20    0.15  0.16
       Sun   3.07  2.50    0.16  0.24
       Thur  2.48  2.43    0.16  0.16
Male   Fri   2.00  2.12    0.14  0.14
       Sat   2.66  2.63    0.16  0.14
       Sun   2.88  2.60    0.16  0.17
       Thur  2.50  2.30    0.17  0.16
 还可以对这个表作进一步的处理,传入margins=True添加分项小计(默认也是求的平均)。这将会添加标签为All的行和列,其值对应于单个等级中所有数据的分组统计:
tips.pivot_table(['tip_pct','size'],index=['sex','day'],columns='smoker',margins=True) # 这里,All值为平均数:不单独考虑烟民与非烟民(All列),不单独考虑行分组两个级别中的任何单项(All行)。
 输出
                             size             tip_pct            
smoker         No   Yes   All      No   Yes   All
sex    day                                       
Female Fri   2.50  2.00  2.11    0.16  0.21  0.20
       Sat   2.31  2.20  2.25    0.15  0.16  0.16
       Sun   3.07  2.50  2.94    0.16  0.24  0.18
       Thur  2.48  2.43  2.47    0.16  0.16  0.16
Male   Fri   2.00  2.12  2.10    0.14  0.14  0.14
       Sat   2.66  2.63  2.64    0.16  0.14  0.15
       Sun   2.88  2.60  2.81    0.16  0.17  0.16
       Thur  2.50  2.30  2.43    0.17  0.16  0.17
All          2.67  2.41  2.57    0.16  0.16  0.16
  # 要使用其他的聚合函数而不是求平均,则将函数将其传给aggfunc即可。例如,使用count或len可以得到有关分组大小的交叉表(计数或频率):
tips.pivot_table('tip_pct',index=['sex','smoker'],columns='day',aggfunc=len,margins=True)
            输出

day             Fri   Sat   Sun  Thur    All
time   smoker
Dinner No       3.0  45.0  57.0   1.0  106.0Yes      9.0  42.0  19.0   NaN   70.0
Lunch  No       1.0   NaN   NaN  44.0   45.0Yes      6.0   NaN   NaN  17.0   23.0
All            19.0  87.0  76.0  62.0  244.0

# 如果存在空的组合(也就是NA),你可能会希望设置一个fill_value:
tips.pivot_table('size', index=['time', 'sex', 'smoker'],columns='day', aggfunc='sum', fill_value=0)
输出
  day                            Fri  Sat  Sun  Thur
time   sex    smoker                     
Dinner Female No        2   30   43     2
                      Yes       8   33   10     0
            Male      No        4   85  124     0
                    Yes      12   71   39     0
Lunch  Female No        3    0    0    60
                      Yes       6    0    0    17
          Male    No        0    0    0    50
                      Yes       5    0    0    23

交叉表(了解)

交叉表(cross-tabulation,简称crosstab)是一种用于计算分组频率的特殊透视表。 这个用的少,用到再查吧。

案例

联邦选举委员会数据库的例子(奥巴马与对手的选举数据分析)
    根据职业和老板统计赞助信息
    对出资额分组
    根据洲统计赞助信息

groupby分组聚合和运算2相关推荐

  1. 【Pandas分组聚合】进阶:透视表、交叉表(pivot_table() 、crosstab())

    Pandas透视表.交叉表 创建DataFrame结构 透视表 pivot_table() 单列聚合 多列聚合 交叉表 crosstab() 计算分组频率 两列分组后求第三列的统计指标 创建DataF ...

  2. Atitit  数据存储的分组聚合 groupby的实现attilax总结

    Atitit  数据存储的分组聚合 groupby的实现attilax总结 1. 聚合操作1 1.1. a.标量聚合 流聚合1 1.2. b.哈希聚合2 1.3. 所有的最优计划的选择都是基于现有统计 ...

  3. pandas数据分组聚合——groupby()、aggregate()、apply()、transform()和filter()方法详解

    数据分组 数据分组就是根据一个或多个键(可以是函数.数组或df列名)将数据分成若干组,然后对分组后的数据分别进行汇总计算,并将汇总计算后的结果进行合并,被用作汇总计算的函数称为聚合函数.数据分组的具体 ...

  4. pandas使用groupby函数进行分组聚合、使用agg函数指定聚合统计计算的数值变量、并自定义统计计算结果的名称(naming columns after aggregation)

    pandas使用groupby函数进行分组聚合.使用agg函数指定聚合统计计算的数值变量.并自定义统计计算结果的名称(naming columns after aggregation in dataf ...

  5. pandas使用groupby函数进行分组聚合并使用agg函数将每个分组特定变量对应的多个内容组合到一起输出(merging content within a specific column of g

    pandas使用groupby函数进行分组聚合并使用agg函数将每个分组特定变量对应的多个内容组合到一起输出(merging content within a specific column of g ...

  6. pandas使用groupby函数对dataframe进行分组统计、使用as_index参数设置分组聚合的结果中分组变量不是dataframe的索引(index)

    pandas使用groupby函数对dataframe进行分组统计.使用as_index参数设置分组聚合的结果中分组变量不是dataframe的索引(index) 目录

  7. pandas使用groupby函数按照多个分组变量进行分组聚合统计、使用agg函数计算分组的多个统计指标(grouping by multiple columns in dataframe)

    pandas使用groupby函数按照多个分组变量进行分组聚合统计.使用agg函数计算分组的多个统计指标(grouping by multiple columns in dataframe) 目录

  8. pandas使用groupby函数、agg函数获取每个分组聚合对应的标准差(std)实战:计算分组聚合单数据列的标准差(std)、计算分组聚合多数据列的标准差(std)

    pandas使用groupby函数.agg函数获取每个分组聚合对应的标准差(std)实战:计算分组聚合单数据列的标准差(std).计算分组聚合多数据列的标准差(std) 目录

  9. pandas使用groupby函数、agg函数获取每个分组聚合对应的均值(mean)实战:计算分组聚合单数据列的均值、计算分组聚合多数据列的均值

    pandas使用groupby函数.agg函数获取每个分组聚合对应的均值(mean)实战:计算分组聚合单数据列的均值.计算分组聚合多数据列的均值 目录

  10. python和R对dataframe的分组聚合操作:dplyr、groupby、agg、group_by、nunique、reset_index、rename、summarise、n_distinct

    python和R对dataframe的分组聚合操作:dplyr.groupby.agg.group_by.nunique.reset_index.rename.summarise.n_distinct ...

最新文章

  1. 不想被问年终奖?2018年春节自救攻略来了!
  2. 这代码水平,连 Bug 王都甘拜下风 | 每日趣闻
  3. IBM----Yacc 与 Lex 快速入门
  4. LeetCode 1845. 座位预约管理系统(set)
  5. GNS3桥接modem拨号and QOS限速
  6. python语言应用章节答案_智慧树APPPython语言应用第十单元章节测试答案
  7. 为什么关于反趋势交易的书以及文章很少?
  8. Unity移动端使用 Handheld.PlayFullScreenMovie播放视频参数
  9. Qt QDebug 打印自定义结构体
  10. 微型计算机原理及应用考试重点,微型计算机原理及应用考试重点.doc
  11. python卡方拟合优度检验_如何理解拟合优度检验 ?
  12. 【老骥伏枥-狗年大礼包】嵌入式linux逆向工程,手把手教你作黑Q-第一讲
  13. 基于JavaEE电子商务交易系统
  14. Git同时配置github和gitee
  15. 按键精灵通过抓抓工具来获取坐标位置
  16. 类型多样的游戏特效网页特效素材,速来收藏
  17. 电商API数据采集,教你如何获取商品详情数据
  18. gitee教程(超全,超详细,超长)
  19. java毕业设计苹果酒店住房管理源码+lw文档+mybatis+系统+mysql数据库+调试
  20. ue4中隐藏灯光和相机图标_[HDRP]物理灯光是什么?科普向

热门文章

  1. 南京商标注册流程是什么
  2. 上上下下左右左右BA
  3. 2019年新个税计算方法
  4. Allure趋势图本地显示
  5. 【01】MyBatis基础知识
  6. 系统集成项目管理工程师备考资料(口袋应试第二版)14
  7. ODM、JDM、OBM 、OEM概念的区别与理解
  8. python环境是什么_三分钟了解什么是Python?python环境搭建
  9. UNITY3D MMO开发指南(Lua)
  10. apple tv 开发_如何在Apple TV上禁用Siri和定位服务