讲解python中groupby()的应用及groupby案例分析

目录

    • 1.单类分组
    • 2.多类分组
        • 分组计算后重命名
        • 对分组计算进行for循环
        • 分组后调用自定义函数
    • 3.时间分组
      • (1) 按照【生日】的【年份】进行分组,看看有多少人是同龄?
      • (2) 同一年作为一个小组,小组内生日靠前的那一位作为小队长:
      • (3) 想要找到哪个月只有一个人过生日
    • 4. groupby之后对不同列运用聚合函数
      • 4.1 方法1
      • 4.2 方法2
      • 4.3 方法3
      • 4.4 方法4
      • 4.5 最后,回顾一下单个列的写法
    • 5. 其它应用案例

1.单类分组

A.groupby('性别')

首先,我们有一个变量A,数据类型是DataFrame,想要按照【性别】进行分组,得到的结果是一个Groupby对象,还没有进行任何的运算。

describe()

描述组内数据的基本统计量

A.groupby("性别").describe().unstack()
  • 只有数字类型的列数据才会计算统计

  • 示例里面数字类型的数据有两列 【班级】和【身高】

但是,我们并不需要统计班级的均值等信息,只需要【身高】,所以做一下小的改动:

A.groupby("性别")["身高"].describe().unstack()

unstack() 索引重排

2.多类分组

A.groupby( [“班级”,“性别”])

单独用groupby,我们得到的还是一个 Groupby 对象。

mean() 组内均值计算

DataFrame的很多函数可以直接运用到Groupby对象上。

A.groupby( ["班级","性别"]).agg([np.sum, np.mean, np.std]) # 一次计算了三个

我们还可以一次运用多个函数计算

agg() 分组多个运算

# 对sales进行操作,按4列进行分组,并求 [ 'item_id' ]列的频数
group = sales.groupby(['state_id', 'store_id', 'cat_id', 'dept_id'], as_index=False)['item_id'].count()

as_index=False,保持原来的数据索引结果不变,表示分组的四列[‘state_id’, ‘store_id’, ‘cat_id’, ‘dept_id’]不做索引,而是作为dataframe的列输出。

对于数据的分组和分组运算主要是指groupby函数的应用,具体函数的规则如下:

df.groupby([df[属性],df[属性]) (指分类的属性,数据的限定定语,可以有多个 ).mean()(对于数据的计算方式——函数名称)

分组计算后重命名
对分组计算进行for循环
分组后调用自定义函数
# 聚合后重命名,ak_dict是'filled_ntf'列经过CapacityAys.weibull_para计算后的结果
# 'filled_ntf_mean'是'filled_ntf'列经过mean()计算后的结果
ws_ym_mean_ak = temp.groupby(by=['year', 'month'], as_index=False)\
    .agg(ak_dict=('filled_ntf', CapacityAys.weibull_para), filled_ntf_mean=('filled_ntf', 'mean'))
    
for date, df in temp0.groupby(['year', 'month']): # date=('year', 'month')
    date # 'year', month数据,通过date[0]和date[1]获取
    df#分组后的数据

# as_index=True 就是要把['year', 'month']合并起来作为索引,调用自定义类函数CapacityAys().weibull_para
ak_value = temp.groupby(['year', 'month'], as_index=True)['filled_风速_mean_ntf'].agg(CapacityAys().weibull_para)

3.时间分组

时间序列可以直接作为index,或者有一列是时间序列,差别不是很大。 这里仅仅演示,某一列为时间序列。

为 A 新增一列【生日】,由于分隔符 “/” 的问题,我们查看列属性,【生日】的属性并不是日期类型

(1) 按照【生日】的【年份】进行分组,看看有多少人是同龄?

A["生日"] = pd.to_datetime(A["生日"],format ="%Y/%m/%d")  # 转化为时间格式

A.groupby(A["生日"].apply(lambda x:x.year)).count()  # 按照【生日】的【年份】分组

(2) 同一年作为一个小组,小组内生日靠前的那一位作为小队长:

A.sort_values("生日", inplace=True) # 按时间排序

A.groupby(A["生日"].apply(lambda x:x.year),as_index=False).first()

as_index=False  # 保持原来的数据索引结果不变

first() 保留第一个数据

Tail(n=1) 保留最后n个数据

再进一步:

(3) 想要找到哪个月只有一个人过生日

A.groupby(A["生日"].apply(lambda x:x.month),as_index=False) # 到这里是按月分组

A.groupby(A["生日"].apply(lambda x:x.month),as_index=False).filter(lambda x: len(x)==1)
  • filter() 对分组进行过滤,保留满足()条件的分组
  • 用 first(),tail()截取每组前后几个数据
  • 用 apply()对每组进行(自定义)函数运算
  • 用 filter()选取满足特定条件的分组

4. groupby之后对不同列运用聚合函数

4.1 方法1

这种方法会导致多级索引

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': lambda x: x.max() - x.min()})

              a                   b         c         d
            sum       max      mean       sum  <lambda>
group                                                  
0      0.864569  0.446069  0.466054  0.969921  0.341399
1      1.478872  0.843026  0.687672  1.754877  0.672401

4.2 方法2

def f(x):
    d = {}
    d['a_sum'] = x['a'].sum()
    d['a_max'] = x['a'].max()
    d['b_mean'] = x['b'].mean()
    d['c_d_prodsum'] = (x['c'] * x['d']).sum()
    return pd.Series(d, index=['a_sum', 'a_max', 'b_mean', 'c_d_prodsum'])

df.groupby('group').apply(f)

         a_sum     a_max    b_mean  c_d_prodsum
group                                           
0      0.864569  0.446069  0.466054     0.173711
1      1.478872  0.843026  0.687672     0.630494

这种方法很好。在groupby之后的每个子DF,可以运用聚合函数;
这里自己构建完成的Series
列索引是平铺的,比较直观;
** 也可以这样简写:**

df.groupby('group') \
  .apply(lambda x: pd.Series({
      'a_sum'       : x['a'].sum(),
      'a_max'       : x['a'].max(),
      'b_mean'      : x['b'].mean(),
      'c_d_prodsum' : (x['c'] * x['d']).sum()
  })
)

          a_sum     a_max    b_mean  c_d_prodsum
group                                           
0      0.530559  0.374540  0.553354     0.488525
1      1.433558  0.832443  0.460206     0.053313

4.3 方法3

In [26]: f = {'A':['sum','mean'], 'B':['prod']}

In [27]: df.groupby('GRP').agg(f)
Out[27]:
            A                   B
          sum      mean      prod
GRP
0    0.719580  0.359790  0.102004
1    0.454824  0.227412  0.034060

这其实是一种变形,把agg变成一个map单独传入
结果对于列来说,仍然是二级索引;

4.4 方法4

df.groupby('group').agg(
             a_sum=('a', 'sum'),
             a_mean=('a', 'mean'),
             b_mean=('b', 'mean'),
             c_sum=('c', 'sum'),
             d_range=('d', lambda x: x.max() - x.min())
)

          a_sum    a_mean    b_mean     c_sum   d_range
group                                                  
0      0.947337  0.473668  0.871939  0.838150  0.320543
1      0.604149  0.302074  0.656902  0.542985  0.057681

这种方法更加直观,我比较喜欢;

有个变种可以这样写:

4.5 最后,回顾一下单个列的写法

 In [84]: animals.groupby("kind").height.agg(
       ....:     min_height='min',
       ....:     max_height='max',
       ....: )
       ....: 
    Out[84]: 
          min_height  max_height
    kind                        
    cat          9.1         9.5
    dog          6.0        34.0

或者这样:

# 聚合单列
grouped_single = df.groupby('Team').agg({'Age': ['mean', 'min', 'max']})
grouped_single.columns = ['age_mean', 'age_min', 'age_max']
grouped_single = grouped_single.reset_index()

# 聚合多列
grouped_multiple = df.groupby(['Team', 'Pos']).agg({'Age': ['mean', 'min', 'max']})
grouped_multiple.columns = ['age_mean', 'age_min', 'age_max']
grouped_multiple = grouped_multiple.reset_index()

5. 其它应用案例

data_all_profile.groupby('is_turn').size()
Out[3]: 
is_turn
0     6470
1    38194
3    78764
dtype: int64
data_all_profile.groupby('is_turn').size().reset_index(name='count')
Out[4]: 
   is_turn  count
0        0   6470
1        1  38194
2        3  78764

参考链接:
[1]链接1 ;

你可能感兴趣的:(#,10.数据聚合与分组操作,大数据)