23、数据分组

1、聚合(aggregate)

1.1、groupby的使用

groupby 语句会把所有结果放入一个DataFrame中返回

df = pd.read_csv('data/gapminder.tsv', sep='\t')
df.groupby('year')['lifeExp'].mean()
years = df['year'].unique()
1.2、聚合函数agg和 aggregate

1、aggaggregate效果一样,可以使用Numpy库的mean函数

import numpy as np
print(df.groupby('year')['lifeExp'])
# <pandas.core.groupby.generic.SeriesGroupBy object at 0x15a9a0f50>
df.groupby('continent')['lifeExp'].agg(np.mean)
#continent
#Africa      48.865330
#Americas    64.658737
#Asia        60.064903
#Europe      71.903686
#Oceania     74.326208
#Name: lifeExp, dtype: float64

2、可以使用自定义函数
自定义函数可以有多个参数,第一个参数接受来自DataFrame分组这之后的值, 其余参数可自定义

def my_mean_diff(values, diff_value):
    n = len(values)
    sum = 0
    for value in values:
        sum += value
    mean = sum / n
    return (mean - diff_value)
global_mean = df['lifeExp'].mean() # 第二个参数
df.groupby('year')['lifeExp'].agg(my_mean_diff, diff_value=global_mean)

3、可以传入多个函数

df.groupby('year')['lifeExp'].agg([np.mean, np.std, np.min, np.max])
#          mean        std    amin   amax
#year                                    
#1952  49.05762  12.225956  28.801  72.67

4、可以传入字典(reset_index设置前面的0为列序号)

df.groupby('year').agg({'lifeExp': 'mean', 'pop': 'median'}).rename(columns={'lifeExp': '平均寿命', 'pop': '人口'}).reset_index()
#   year      平均寿命         人口
#0  1952  49.05762  3943953.0

2、转换(transform)

  • transform 需要把DataFrame中的值传递给一个函数, 而后由该函数"转换"数据。
  • uaggregate(聚合) 返回单个聚合值,但transform 不会减少数据量
2.1、使用transform计算

1、计算z-score x - 平均值/标准差

def my_zscore(x):
    return (x - x.mean() / x.std()) # 其中x为每一组数据
df.groupby('year')['lifeExp'].transform(my_zscore)
#0       24.788420
#1       26.120881
#2       27.565475
#3       29.268830
#4       31.023194
#          ...    
#1699    56.362851
#1700    54.662368
#1701    41.184620
#1702    34.639173
#1703    37.936821

2、transform分组填充缺失值

# 加载数据
# random_state 值(没有意义),采样出来的数据是一样的
tips_10 = pd.read_csv('data/tips.csv').sample(10, random_state=42)
# 构建缺失 random.permutation 序列乱序
tips_10.loc[np.random.permutation(tips_10.index)[:4], 'total_bill'] = np.NaN
count_sex = tips_10.groupby('sex').count() # 统计非NaN数据个数
print(count_sex)
print('----')
print(tips_10)
def fill_na_mean(x):
    avg = x.mean()
    return x.fillna(avg)
total_bill_group_mean = tips_10.groupby('sex')['total_bill'].transform(fill_na_mean) # 对total_bill进行数据填充
print('----')
print(total_bill_group_mean.head(1))
#        total_bill  tip  smoker  day  time  size
#sex                                             
#Female           2    3       3    3     3     3
#Male             4    7       7    7     7     7
#----
#     total_bill   tip     sex smoker   day    time  size
#192         NaN  2.56    Male    Yes  Thur   Lunch     2
#124       12.48  2.52  Female     No  Thur   Lunch     2
#9           NaN  3.23    Male     No   Sun  Dinner     2
#101         NaN  3.00  Female    Yes   Fri  Dinner     2
#----
#24    19.82
#Name: total_bill, dtype: float64

3、query的使用

weight_loss = pd.read_csv('data/weight_loss.csv')
# 只查看1月份数据  query 类似SQL的where条件
weight_loss.query('Month == "Jan"')

3、过滤(filter)

1、调用filter 方法,传入一个返回布尔值的函数,返回False的数据会被过滤掉

print(total_bill_group_mean.head(1))
#%%
tips = pd.read_csv('data/tips.csv')
tips['size'].value_counts() # 过滤前的用餐人数
tips_filtered = tips.groupby('size').filter(lambda x: x['size'].count()>30)
print(tips_filtered['size'].value_counts()) # 过滤后的相同用餐人数次数
#2    156
#3     38
#4     37
#Name: size, dtype: int64

4、groupby对象DataFrameGroupBy

1、使用分组对象

grouped = tips_10.groupby('sex')
print(grouped.groups)
# {'Female': [198, 124, 101], 'Male': [24, 6, 153, 211, 176, 192, 9]}
female = grouped.get_group('Female') # 获取Female分组
#分组遍历
for sex_group in grouped:
    print(sex_group)

2、多个分组 (已经deprecated)

#性别时间分别数据的平均值分组
group_avg = tips_10.groupby(['sex','time']).mean()
# 分别查看分组之后结果的列名和行索引
group_avg.columns
group_avg.index

5、apply、agg、transform区别对比

5.1、apply
  • 最灵活通用,可以应用任意函数到DataFrame或Series
  • 返回结果形状灵活(可以是标量、Series、DataFrame)
  • 可以逐行(axis=1)或逐列(axis=0)操作
  • 功能最强大但速度可能较慢
5.2、agg
  • 专门用于聚合操作,常与groupby一起使用
  • 主要用于聚合计算(求和、平均、计数等)
  • 支持多个聚合函数
  • 返回汇总结果(通常维度会降低)
5.3、transform
  • 输入输出的形状相同(数据行数相同)
  • 常用于创建新列或原地转换
  • 适合广播操作(如计算组内标准化值)
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容