第四章 分组

全文知识架构

分组模式及其对象

分组模式及其对象

【练一练】

请根据上下四分位数分割,将体重分为high、normal、low三组,统计身高的均值。

high = df['Weight'].quantile(0.75)
low = df['Weight'].quantile(0.25)
level = df['Weight'].mask(df['Weight']>high, 'high').mask(df['Weight']<low, 'low').mask((low<=df['Weight'])&(df['Weight']<=high), 'normal')
df.groupby(level)['Weight'].mean()

【练一练】

上一小节介绍了可以通过drop_duplicates得到具体的组类别,现请用groups属性完成类似的功能。

gb = df.groupby(['School', 'Gender'])
gb.groups.keys()

聚合函数

聚合函数

【练一练】

请查阅文档,明确all/any/mad/skew/sem/prod函数的含义。

  • all 返回所有的值是否为真的结果
  • any 返回所有值中是否有真值的结果
  • mad 根据平均值计算绝对距离差
  • skew 偏度(skewness),是统计数据分布偏斜方向和程度的度量
  • sem 返回所请求轴上的平均值的无偏标准误差
  • prod 累乘

【练一练】

请使用【b】中的传入字典的方法完成【a】中等价的聚合任务。

gb.agg({'Height':['sum', 'idxmax', 'skew'], 'Weight':['sum', 'idxmax', 'skew']})

【练一练】

groupby对象中可以使用describe方法进行统计信息汇总,请同时使用多个聚合函数,完成与该方法相同的功能。

# 本来想使用传入函数列表的方法,发现通过函数列表方法不支持给函数传入参数
gb.agg([('count',lambda x: x.count()), ('mean', lambda x: x.mean()), ('std', lambda x: x.std()), ('min', lambda x: x.min()), ('25%',lambda x: x.quantile(0.25)),
        ('50%',lambda x: x.quantile(0.5)),('75%',lambda x: x.quantile(0.75))])

变换和过滤

变换和过滤

【练一练】

groupby对象中,rank方法也是一个实用的变换函数,请查阅它的功能并给出一个使用的例子。

# 这个操作 是 对DataFrame某列的数据进行聚类 然后对其它列的属于同类数据进行数值大小排序
gb.rank(method='min', ascending=True) # method可以指定max或min,ascending可指定True or False

【练一练】

对于transform方法无法像agg一样,通过传入字典来对指定列使用特定的变换,如果需要在一次transform的调用中实现这种功能,请给出解决方案。

func_dict = {'Height':'max', 'Weight':'min'}
def my_transform(s, transform_dict=func_dict):
    name = s.name
    for key, func in transform_dict.items():
        if key in [name]:
            function = getattr(s, func)
            return function()
gb.transform(my_transform)

跨列分组

跨列分组

【练一练】

请尝试在apply传入的自定义函数中,根据组的某些特征返回相同长度但索引不同的Series,会报错吗?

def test_func(x):
    if x['Weight'].shape[0] > 10:
        return pd.Series([1,1],index=['a123','b12312'])
    else:
        return pd.Series([0,0],index=['c123123','12312d'])
gb.apply(test_func)
# 会报错

【练一练】

请尝试在apply传入的自定义函数中,根据组的某些特征返回相同大小但列索引不同的DataFrame,会报错吗?如果只是行索引不同,会报错吗?

def test_func(x):
    if x['Weight'].shape[0] > 10:
        return pd.DataFrame(np.ones((2,2)), index = ['a','b'], columns=pd.Index([('w','x'),('y','z')]))
    else:
        return pd.DataFrame(np.ones((2,2)), index = ['c','d'], columns=pd.Index([('w','d'),('y','z')]))
gb.apply(test_func)
# 以上两种情况都不会报错

五、练习

Ex1:公司员工数据集

现有一份公司员工数据集:

  1. 分别只使用queryloc选出年龄不超过四十岁且工作部门为DairyBakery的男性。
  2. 选出员工ID号 为奇数所在行的第1、第3和倒数第2列。
  3. 按照以下步骤进行索引操作:
  • 把后三列设为索引后交换内外两层
  • 恢复中间一层
  • 修改外层索引名为Gender
  • 用下划线合并两层行索引
  • 把行索引拆分为原状态
  • 修改索引名为原表名称
  • 恢复默认索引并将列保持为原表的相对位置
# 问题1
dpt = ['Dairy', 'Bakery']
df.loc[(df.age<=40)&df.department.isin(dpt)&(df.gender=='M')].head(3)
# 问题2
df.iloc[(df.EmployeeID%2==1).values,[0,2,-2]].head()
# 问题三
# 把后三列设为索引
df_ = df.set_index(['department', 'job_title', 'gender'])
# 交换内外两层
df_ = df_.swaplevel(0,2, axis=0)
# 恢复中间一层
df_ = df_.reset_index(level=1, drop=False)
# 把外层索引名改为Gender
df_.rename_axis(index={'gender':'Gender'})
# 用下划线合并两层索引
df_.index = df_.index.map(lambda x:'_'.join(x))
# 拆分为原状态
df_.index = df_.index.map(lambda x:tuple(x.split('_')))
# 修改索引名为原表名称
df_ = df_.rename_axis(index=['gender','department'])
# 恢复默认
df_ = df_.reset_index().reindex(df.columns, axis=1)
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容