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、agg和 aggregate效果一样,可以使用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
- 输入输出的形状相同(数据行数相同)
- 常用于创建新列或原地转换
- 适合广播操作(如计算组内标准化值)