pandas数据分组groupby()和统计函数agg()

数据分组

  • 使用 groupby() 方法进行分组
  • group.size()查看分组后每组的数量
  • group.groups 查看分组情况
  • group.get_group('名字') 根据分组后的名字选择分组数据

pandas数据离散化

数据离散化中的分组 cut()qcut()
这两个也很好用

准备数据

# 一个Series其实就是一条数据,Series方法的第一个参数是data,第二个参数是index(索引),如果没有传值会使用默认值(0-N)
# index参数是我们自定义的索引值,注意:参数值的个数一定要相同。
# 在创建Series时数据并不一定要是列表,也可以将一个字典传进去。
from pandas import Series, DataFrame

# 使用字典创建
index_list = ['001', '002', '003', '004', '005', '006', '007', '008', '009', '010']
name_list = ['李白', '王昭君', '诸葛亮', '狄仁杰', '孙尚香', '妲己', '周瑜', '张飞', '王昭君', '大乔']
age_list = [25, 28, 27, 25, 30, 29, 25, 32, 28, 26]
gender_list = ['F', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M']
salary_list = ['10k', '12.5k', '20k', '14k', '12k', '17k', '18k', '21k', '22k', '21.5k']
marital_list = ['NO', 'NO', 'YES', 'YES', 'NO', 'NO', 'NO', 'YES', 'NO', 'YES']
dic = {
    '姓名': Series(data=name_list, index=index_list),
    '年龄': Series(data=age_list, index=index_list),
    '薪资': Series(data=salary_list, index=index_list),
    '性别': Series(data=gender_list, index=index_list),
    '婚姻状况': Series(data=marital_list, index=index_list)
}
df = DataFrame(dic)

# 写入csv,path_or_buf为写入文本文件
df.to_csv(path_or_buf='./People.csv', encoding='utf_8_sig')
print('end')

  • 上面代码会在当前目录下生成一个 People.csv 文件
import pandas as pd
df = pd.read_csv('./People.csv')
df.head()

在这里插入图片描述

# 根据 '性别列' 进行分组, 得到的是一个分组后的对象
groups = df.groupby('性别')
print(groups)
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000002953DAEBC88>

size()

使用groupby的size方法可以查看分组后每组的数量, 并返回一个含有分组大小的Series

print(groups.size())
性别
F    5
M    5
dtype: int64

可以只对一列数据进行分组, 只保留想要的数据

例如: 通过性别, 只对年龄进行分组

group = df['年龄'].groupby(df['性别'])
# 查看分组
print(group.groups)
# 根据分组后的名字选择分组
print(group.get_group('F'))
{'F': Int64Index([0, 2, 3, 6, 7], dtype='int64'), 'M': Int64Index([1, 4, 5, 8, 9], dtype='int64')}
0    25
2    27
3    25
6    25
7    32
Name: 年龄, dtype: int64
  • 代码df['年龄'].groupby(df['性别'])的逻辑是:取出df中’年龄’列数据,并且对该列数据根据df[‘性别’]列数据进行分组操作
  • 这个代码也可写成df.groupby(df['性别'])['年龄'], 他的逻辑是: 将df数据通过df[‘性别’]进行分组,然后再取出分组后的’年龄’列数据。两种写法达到的效果是一样的
  • group.groups的结果是一个字典,字典的key是分组后每个组的名字,对应的值是分组后的数据,此方法方便我们产看分组的情况
  • group.get_group('F')这个方法可以根据具体分组的名字获取,每个组的数据

对分组进行遍历

import pandas as pd
df = pd.read_csv('./People.csv')
groups = df.groupby('性别')
# print(groups)
for group_name,group_df in groups:
    print('分组的名称:', group_name, '分组的数据', group_df.shape)
    print('-'*10)

分组的名称: F 分组的数据 (5, 6)
----------
分组的名称: M 分组的数据 (5, 6)
----------
- 将分组后的对象groups进行遍历,可以获取到group_name每个组的名字,group_df每个组的数据


import pandas as pd
df = pd.read_csv('./People.csv')
groups = df.groupby('性别')
for group_name,group_df in groups:
    f_mean = group_df['年龄'].mean()
    f_max = group_df['年龄'].max()
    f_min = group_df['年龄'].min()
    print('{}组的最大年龄是{},最小年龄是{},平均年龄是{}'.format(group_name,f_max,f_min,f_mean))

F组的最大年龄是32,最小年龄是25,平均年龄是26.8
M组的最大年龄是30,最小年龄是26,平均年龄是28.2

按多列进行分组

  • 当需要按照多列进行分组的时候, groupby 方法里面我们传入一个列表, 列表分别存储分组依据的列名
  • 注意: 列表中列名的顺序, 确定了先按XXXX列分组, 然后在按照YYYY列分组, 不同的顺序产生的分组名字是不同的
df = pd.read_csv('./People.csv')
group=df.groupby(['性别', '婚姻状况'])
df1 = group.size()
print(df1)

性别  婚姻状况
F   NO      2
    YES     3
M   NO      4
    YES     1
dtype: int64
  • group.size()返回的结果中发现索引值是多层的, 所以对于多索引值的获取, 只需要从外往里一层一层的取就可以啦, 就像我们睡觉之前,需要先脱外衣再脱掉内衣是一样的
size = df1['F'][ 'NO']
print(size)

2

pandas 常用统计函数

  • count() 统计列表中非空手机开的个数
  • nunique() 统计非重复的数据个数
  • sum() 统计列表中所有数值的和
  • mean() 计算列表中数据的平均值
  • median() 统计列表中数据中位数
  • max() 求列表中数据的最大值
  • min() 求列表中数据的最小值

对分组后的数据进行统计 agg()

import pandas as pd
df = pd.read_csv('./People.csv')
groups = df.groupby('性别')
for group_name,group_df in groups:
    f_se = group_df['年龄'].agg(['max','min','mean'])
    print('{}组的最大年龄是{},最小年龄是{},平均年龄是{}'.format(group_name,f_se[0],f_se[1],f_se[2]))

F组的最大年龄是32.0,最小年龄是25.0,平均年龄是26.8
M组的最大年龄是30.0,最小年龄是26.0,平均年龄是28.2
  • 在使用 agg() 函数时, 我们可以将多个统计函数一起放在一个 agg() 函数中
  • 如果是统计函数是pandas 提供的, 只需要将函数名字以字符串的形式存储到列表中即可
  • 例如: 将 max() 改成 ‘max’

自定义统计函数

当使用自定义的统计函数时
先创建统计函数

# 自定义的统计函数
def my_peak_range(df):
    """
    返回最大值与最小之间的范围
    """
    return df.max() - df.min()

# 使用
for group_name,group_df in groups:
    f_se = group_df['年龄'].agg(['max','min','mean',my_peak_range])
    print(f_se[0],f_se[1],f_se[3])
32.0 25.0 7.0
30.0 26.0 4.0
  • 注意: 自定义函数名字传入agg() 函数时, 不需要转换成字符串

补充: 在这个数据中, 性别是什么的人总年龄最高

import pandas as pd
df = pd.read_csv('./People.csv')
groups = df.groupby('性别')
gende=groups.sum().sort_values(by='年龄',ascending=False).index.to_list()[0]
"""
这行代码, 先按性别进行分组, 然后吧每组中的数据求和得到总的年龄, 在按照年龄排序
再取出index,最后使用to_list()转换为列表,取出第一个数据
"""

print(gende)
M
  • 开始按照性别分组, 组量太少, 数据也比较少, 本来准备算薪资总数, 但是单位忘记换了, 就这样吧
### 如何在 Pandas GroupBy 结果中添加列名 当使用 `groupby` 对数据进行分组并应用聚合操作后,有时会发现生成的结果缺少显式的列名。为了确保结果具有清晰的表头,可以通过以下方式来设置或修改列名。 #### 使用 rename 方法重命名 Series 或 DataFrame 的索引名称 如果通过 `groupby().agg()` 得到的是一个 Series,则可以直接转换成 DataFrame 并利用 `rename_axis` 来指定新的轴标签[^1]: ```python import pandas as pd import numpy as np # 创建示例数据集 df = pd.DataFrame({ 'A': ['foo', 'bar', 'foo', 'bar'] * 3, 'B': np.random.randint(0, 100, size=12), }) # 执行 groupby agg 操作 result_series = df.groupby('A')['B'].sum() # 将 Series 转换为 DataFrame 并设置新列名为 "Sum" result_df_with_header = result_series.to_frame(name='Sum') print(result_df_with_header) ``` #### 设置多级索引后的列名 对于更复杂的场景,比如执行多个聚合函数时产生的 MultiIndex 列情况,可以先获取原始列名再重新定义它们[^3]: ```python # 应用多个聚合函数 multi_agg_result = df.groupby('A')['B'].agg([np.size, np.sum, np.mean]) # 获取当前列级别名称 current_columns = multi_agg_result.columns.tolist() new_column_names = ["Count", "Total", "Average"] # 替换原有的列名 final_result = multi_agg_result.set_axis(new_column_names, axis=1) print(final_result) ``` #### 处理复杂嵌套结构的情况 如果有更加复杂的嵌套结构(例如由多重键组成的分组),则可以在调用 `unstack()` 后调整层次化的列名[^5]: ```python complex_grouping = ( df.assign(DummyColumn=1) # 添加辅助列用于 unstack .pivot_table( index=['DummyColumn'], columns=['A'], values='B', aggfunc=[len], fill_value=0 ) .droplevel(level=0, axis=1) # 移除不必要的层级 .reset_index(drop=True) .set_axis(['Foo_Count', 'Bar_Count'], axis=1) # 自定义最终列名 ) print(complex_grouping) ``` 以上三种方法可以根据实际需求灵活运用,在不同的情况下都能有效地为 `groupby` 分组统计的结果添加合适的表头。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值