DataWhale Pandas数据分析 Task04:分组

练习

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
  1. 先过滤出所属Country数超过2个的汽车,即若该汽车的Country在总体数据集中出现次数不超过2则剔除,再按Country分组计算价格均值、价格变异系数、该Country的汽车数量,其中变异系数的计算方法是标准差除以均值,并在结果中把变异系数重命名为CoV
  2. 按照表中位置的前三分之一、中间三分之一和后三分之一分组,统计Price的均值。
  3. 对类型Type分组,对PriceHP分别计算最大值和最小值,结果会产生多级索引,请用下划线把多级列索引合并为单层索引。
  4. 对类型Type分组,对HP进行组内的min-max归一化。
  5. 对类型Type分组,计算Disp.HP的相关系数。
    答案:
# 1.1
df1 = df.copy()
gp = df1.groupby('Country').filter(lambda x: x.shape[0] > 2).groupby('Country')['Price']
gp.agg(['mean', ('CoV', lambda x: x.std()/x.mean()), 'size'])
# 参考答案中,size也可用count聚合函数
```python
# 1.2
item = np.empty(df1.shape[0])
a, b, c = df1.shape[0] // 3, df1.shape[0] // 3 * 2, df1.shape[0]
item[:a] = 0
item[a: b] = 1
item[b:c] = 2
df1.groupby(item)['Price'].mean()
# 1.3
res = df1.groupby('Type')[['Price', 'HP']].agg(['max', 'min'])
new_column = res.columns.map(lambda x: x[0]+'_'+x[1])
res.columns = new_column
res
# 1.3 参考答案(分别计算最大值、最小值)
res = df.groupby('Type').agg({'Price': ['max'], 'HP': ['min']})
res.columns = res.columns.map(lambda x:'_'.join(x))
res
# 1.4
df1.groupby('Type')['HP'].transform(lambda x: (x-x.min())/(x.max()-x.min()))
# 1.5
def corr(x):
    return x.corr().loc['Disp.', 'HP']
    
df1.groupby('Type')[['Disp.', 'HP']].apply(corr)
# 1.5 参考答案
df.groupby('Type')[['HP', 'Disp.']].apply(
    lambda x:np.corrcoef(x['HP'].values, x['Disp.'].values)[0,1])
# 1.利用np.corrcoef函数
# 2.pandas底层a用numpy实现,因此Series.value类型为np.array

Ex2:实现transform函数

  • groupby对象的构造方法是my_groupby(df, group_cols)
  • 支持单列分组与多列分组
  • 支持带有标量广播的my_groupby(df)[col].transform(my_func)功能
  • pandastransform不能跨列计算,请支持此功能,即仍返回Seriescol参数为多列
  • 无需考虑性能与异常处理,只需实现上述功能,在给出测试样例的同时与pandas中的transform对比结果是否一致
class my_groupby:
    def __init__(self, my_df, group_cols):
        self.my_df = my_df.copy()
        self.groups = my_df[group_cols].drop_duplicates()
        if isinstance(self.groups, pd.Series):
            self.groups = self.groups.to_frame()
        self.group_cols = self.groups.columns.tolist()
        self.groups = {i: self.groups[i].values.tolist() for i in self.groups.columns}
        self.transform_col = None
    def __getitem__(self, col):
        self.pr_col = [col] if isinstance(col, str) else list(col)
        return self
    def transform(self, my_func):
        self.num = len(self.groups[self.group_cols[0]])
        L_order, L_value = np.array([]), np.array([])
        for i in range(self.num):
            group_df = self.my_df.reset_index().copy()
            for col in self.group_cols:
                group_df = group_df[group_df[col]==self.groups[col][i]]
            group_df = group_df[self.pr_col]
            if group_df.shape[1] == 1:
                group_df = group_df.iloc[:, 0]
            group_res = my_func(group_df)
            if not isinstance(group_res, pd.Series):
                group_res = pd.Series(group_res,index=group_df.index,name=group_df.name)
            L_order = np.r_[L_order, group_res.index]
            L_value = np.r_[L_value, group_res.values]
        self.res = pd.Series(pd.Series(L_value, index=L_order).sort_index().values,index=self.my_df.reset_index().index, name=my_func.__name__)
        return self.res

my_groupby(df, 'Type')

单列分组

def f(s):
    res = (s-s.min())/(s.max()-s.min())
    return res
my_groupby(df, 'Type')['Price'].transform(f).head()
df.groupby('Type')['Price'].transform(f).head()

多列分组

my_groupby(df, ['Type','Country'])['Price'].transform(f).head()
df.groupby(['Type','Country'])['Price'].transform(f).head()

标量广播

my_groupby(df, 'Type')['Price'].transform(lambda x:x.mean()).head()
df.groupby('Type')['Price'].transform(lambda x:x.mean()).head()

跨列计算

my_groupby(df, 'Type')['Disp.', 'HP'].transform(lambda x: x['Disp.']/x.HP).head()

心得体会

  • 分组是SQL中也很重要的内容,相对来说pandas的接口更加容易调用
  • 最后一题真的难,想要像元昊大佬写出优美的代码还有很大差距呢
  • 辛苦助教!今天过圣诞早点配女朋友!第五章之后会对前几章的函数方法做一个大的汇总便于之后查看!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值