感谢datawhale开展的每月组队学习,教材ref:第四章:分组
分组模式及其对象
分组的一般模式
分组依据的本质
🔫 练一练
请根据上下四分位数分割,将体重分为high、normal、low三组,统计身高的均值。
计算三分位的边界在哪里
weight_tertile = list(df.Weight.quantile([.33, .66]))
确定分组依据
我们可以写一个function去把Weight转换成 low,normal和high,根据我们上面得到的分位数边界
- 普通function写法(因为我lambda用的不是很熟练,先普通func写出来可以帮助缕一下思路
def split_weight(x): if x <= weight_tertile[0]: return "low" if x <= weight_tertile[1]: return "normal" return "hight"
- lambda 写法
lambda x: "low" if x<=weight_tertile[0] else ("normal" if x<=weight_tertile[1] else "hight")
数据来源:[‘Height’]
操作及其返回结果:平均值# 请根据上下四分位数分割,将体重分为high、normal、low三组,统计身高的均值。 # lambda df.groupby(df.Weight.apply(lambda x: "low" if x<=weight_tertile[0] else ("normal" if x<=weight_tertile[1] else "hight")))['Height'].mean() # self-defined func df.groupby(df.Weight.apply(split_weight))['Height'].mean()
有个有点愚蠢的问题,分三份的话应该断开两下对吧?那位置应该在33.33333%和66.666666%?
Groupby object
🔫 练一练
上一小节介绍了可以通过 drop_duplicates 得到具体的组类别,现请用 groups 属性完成类似的功能。
直接把zzg
分组的三大操作
聚合函数
内置聚合函数
agg方法
🔫 练一练
请使用【b】中的传入字典的方法完成【a】中等价的聚合任务。
gb.agg({'Height':['sum','idxmax','skew'], 'Weight':['sum','idxmax','skew']})
变换 和 过滤
变换函数 和 transform method
我怎么感觉transform和apply一样的
组索引与过滤
跨列分组
🔫 练一练
在 groupby
对象中还定义了 cov
和 corr
函数,从概念上说也属于跨列的分组处理。请利用之前定义的 gb
对象,使用apply
函数实现与 gb.cov()
同样的功能并比较它们的性能。
练习
Ex1:汽车数据集
现有一份汽车数据集,其中 Brand, Disp., HP 分别代表汽车品牌、发动机蓄量、发动机输出。
In [45]: df = pd.read_csv('data/car.csv')
In [46]: df.head(3)
Out[46]:
Brand Price Country Reliability Mileage Type Weight Disp. HP
0 Eagle Summit 4 8895 USA 4.0 33 Small 2560 97 113
1 Ford Escort 4 7402 USA 2.0 33 Small 2345 114 90
2 Ford Festiva 4 6319 Korea 4.0 37 Small 1845 81 63
-
先过滤出所属
Country
数超过2个的汽车,即若该汽车的Country
在总体数据集中出现次数不超过2则剔除,再按Country
分组计算价格均值、价格变异系数、该Country
的汽车数量,其中变异系数的计算方法是标准差除以均值,并在结果中把变异系数重命名为CoV
。先处理一下问题的前半部分吧。按country来分组,可以稍微看一下
用groupby object 的 filter method去把个数大于2 的取出来car_df.groupby('Country').filter(lambda x: x.shape[0]>2)
返回的结果 – 未被过滤的组对应的每一行重新拼起来成为一个dataframe
那我们就接着对这个dataframe(给名字 filtered_df)继续做后半部分操作filted_df.groupby('Country')['Price'].agg(['mean', ('Cov', lambda x: x.std()/x.mean()), 'count'])
-
按照表中位置的前三分之一、中间三分之一和后三分之一分组,统计
Price
的均值。divide = ['First']*20+['Second']*20+['Last']*20 car_df.groupby(divide)['Price'].mean()
-
对类型
Type
分组,对Price
和HP
分别计算最大值和最小值,结果会产生多级索引,请用下划线把多级列索引合并为单层索引。temp = car_df.groupby('Type').agg({'Price':'max', 'HP':'min'}) temp.columns = ['Price_max', 'HP_min']
-
对类型
Type
分组,对HP
进行组内的min-max
归一化。def normalize(x): min_val, max_val = min(x), max(x) res = (x - min_val)/(max_val - min_val) return res car_df.groupby('Type')['HP'].apply(normalize)
-
对类型
Type
分组,计算Disp.
与HP
的相关系数。car_df.groupby('Type')['Disp.','HP'].apply(lambda x:np.corrcoef(x['HP'].values, x['Disp.'].values)[0,1])
Ex2: 实现transform函数
groupby
对象的构造方法是my_groupby(df, group_cols)
- 支持单列分组与多列分组
- 支持带有标量广播的
my_groupby(df)[col].transform(my_func)
功能 pandas
的transform
不能跨列计算,请支持此功能,即仍返回Series
但col
参数为多列- 无需考虑性能与异常处理,只需实现上述功能,在给出测试样例的同时与
pandas
中的transform
对比结果是否一致唉transform好像还没有搞得很清楚
dei不起
我放弃了