Pandas练习题 (三)

import numpy as np
import pandas as pd

Ex1:汽车数据集

现有一份汽车数据集,其中Brand, Disp., HP分别代表汽车品牌、发动机蓄量、发动机输出。

data =[['Eagle Summit 4',8895,'USA',4.0,33,'Small',2560,97,113],['Ford Escort 4',7402,'USA',2.0,33,'Small',2345,114,90],['Ford Festiva 4',6319,'Korea',4.0,37,'Small',1845,81,63]]
df = pd.DataFrame(data = data, index = np.arange(3),columns= ['Brand','Price','Country','Reliability','Mileage','Type','Weight','Disp.','HP'])

df.to_csv('.//car.csv')

1.先过滤出所属Country数超过2个的汽车,即若该汽车的Country在总体数据集中出现次数不超过2则剔除,再按Country分组计算价格均值、价格变异系数、该Country的汽车数量,其中变异系数的计算方法是标准差除以均值,并在结果中把变异系数重命名为CoV。

gb = df.groupby(['Country'])
gbMoreT = gb.filter(lambda x:x.shape[0]>=1)
gb = gb['Price']
gb.mean()
gb.count()
gb.std()/gb.mean()
Country
Korea         NaN
USA      0.129559
Name: Price, dtype: float64

# gb.agg([('a','std')])
gb.agg([('CoV',lambda x : x.std()/x.mean())])
CoV
Country
KoreaNaN
USA0.129559
# ERROR
gb = df.groupby(['Country'])
print(type(gb))
gb = gb.filter(lambda x:x.shape[0]>=1)
print(type(gb))
gb = gb['Price']
print(type(gb))
gb.agg([('CoV',lambda x : x.std()/x.mean()),'mean','count'])
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

AttributeError: 'CoV' is not a valid function for 'Series' object
gb = df.groupby(['Country'])
print(type(gb))
gb = gb['Price']
print(type(gb))
gb.agg([('CoV',lambda x : x.std()/x.mean()),'mean','count'])
pandas.core.groupby.generic.DataFrameGroupBy
pandas.core.groupby.generic.SeriesGroupBy
CoVmeancount
Country
KoreaNaN6319.01
USA0.1295598148.52

== 注意 == 经过gb.filter后,变量的type()是会改变的。

# 答案
df.groupby('Country').filter(lambda x:x.shape[0]>=1).groupby('Country')['Price'].agg([('CoV', lambda x: x.std()/x.mean()), 'mean', 'count'])

# 要理解为什么要进行两次的`groupby('Country')`的原因。
CoVmeancount
Country
KoreaNaN6319.01
USA0.1295598148.52

2. 按照表中位置的前三分之一、中间三分之一和后三分之一分组,统计Price的均值。

df
BrandPriceCountryReliabilityMileageTypeWeightDisp.HP
0Eagle Summit 48895USA4.033Small256097113
1Ford Escort 47402USA2.033Small234511490
2Ford Festiva 46319Korea4.037Small18458163
# 自己写的
condition = df.index>0
condition1 = df.index > len(df)/3
condition2 = df.index >len(df)/3*2
df.groupby([condition,condition1,condition2])['Price'].mean()
False  False  False    8895
True   False  False    7402
       True   False    6319
Name: Price, dtype: int64
# 答案
df = pd.read_csv('.//car.csv')
condition = ['Head']*1+['Mid']*1+['Tail']*1
df.groupby(condition)['Price'].mean()
# num = int(df.shape[0]/3)
# condition = ['Head']*num+['mile']*num +['tail']*num
# df.groupby(condition)['Price'].mean()
Head    8895
Mid     7402
Tail    6319
Name: Price, dtype: int64

3.对类型Type分组,对Price和HP分别计算最大值和最小值,结果会产生多级索引,请用下划线把多级列索引合并为单层索引。

# 自己写的
# 会给我一个警告
gb = df.groupby('Type')['Price','HP']
gb = gb.agg(['max','min'])
gbcol = gb.columns.map(lambda x:x[0]+'_'+x[1])
gb.columns = gbcol
gb
/opt/conda/lib/python3.6/site-packages/ipykernel_launcher.py:3: FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead.
  This is separate from the ipykernel package so we can avoid doing imports until
Price_maxPrice_minHP_maxHP_min
Type
Small8895631911363
res = df.groupby('Type').agg({'Price': ['max'], 'HP': ['min']})
res.columns = res.columns.map(lambda x:'_'.join(x))
res
Price_maxHP_min
Type
Small889563

gb = df.groupby('Type')['Price','HP']给我警告的原因
gb = df.groupby('Type')]['Price','HP']]

gb = df.groupby('Type')[['Price','HP']]
gb = gb.agg(['max','min'])
gbcol = gb.columns.map(lambda x:x[0]+'_'+x[1])
gb.columns = gbcol
gb
Price_maxPrice_minHP_maxHP_min
Type
Small8895631911363

4.对类型Type分组,对HP进行组内的min-max归一化。

gb = df.groupby('Type')['HP']
gb =gb.agg(lambda x : (x-x.min())/(x.max()-x.min()))
gb
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

ValueError: Must produce aggregated value

因为是要对每一列进行操作,所以使用agg会报错

gb = df.groupby('Type')['HP']
gb =gb.transform(lambda x : (x-x.min())/(x.max()-x.min()))
gb
def normalize(s):
    s_min, s_max = s.min(), s.max()
    res = (s - s_min)/(s_max - s_min)
    return res
df.groupby('Type')['HP'].transform(normalize).head()
0    1.00
1    0.54
2    0.00
Name: HP, dtype: float64

5.对类型Type分组,计算Disp.与HP的相关系数。

# 自己写的
gb = df.groupby('Type')
def Correlation (s):
    cov = np.cov(s['Disp.'],s['HP'])[0,1]
    std1 =s['Disp.'].std()
    std2 =s['HP'].std()
    return cov/(std1*std2)
gb.apply(Correlation)
Type
Small    0.524613
dtype: float64
# 答案
df.groupby('Type')[['HP', 'Disp.']].apply(lambda x:np.corrcoef(x['HP'].values, x['Disp.'].values)[0,1])
Type
Small    0.524613
dtype: float64

协方差 ;np.cov
相关系数 : np.corrcoef

r ( X , Y ) = C o v ( X , Y ) V a r ( X ) , V a r ( Y ) r(X,Y)=\frac{Cov(X,Y)}{\sqrt[]{Var(X),Var(Y)}} r(X,Y)=Var(X),Var(Y) Cov(X,Y)

Ex2:实现transform函数

  • groupby对象的构造方法是my_groupby(df, group_cols)
  • 支持单列分组与多列分组
  • 支持带有标量广播的my_groupby(df)[col].transform(my_func)功能
  • pandas的transform不能跨列计算,请支持此功能,即仍返回Series但col参数为多列
  • 无需考虑性能与异常处理,只需实现上述功能,在给出测试样例的同时与pandas中的transform对比结果是否一致
# 答案
def f(s):
    res = s.min()
    return res

class my_groupby:
    '`my_df`是要分组的数据源,`group_cols`是分组的依据'
    def __init__(self, my_df, group_cols):# 初始化时一定会使用该方法 __init__()
        self.my_df = my_df.copy()#保存本实例的list()
        self.groups = my_df[group_cols].drop_duplicates()#保存要分类的组名列表,可以知道组数。
        if isinstance(self.groups, pd.Series):#判断类型
            self.groups = self.groups.to_frame()#to_frame()函数用于将系列对象转换为DataFrame
        self.group_cols = self.groups.columns.tolist()#?? 为什么要这么写?直接self.gropu_cols = group_cols
                                                     # 这里不直接等于的原因是为了把group_cols 转变为list的形式
        self.groups = {i: self.groups[i].values.tolist() for i in self.groups.columns}#把值转变为列表,做成了一种字典的形式
#         self.groups = {i: self.groups[i].tolist() for i in self.groups.columns}
        self.transform_col = None
    def __getitem__(self, col):# 当使用[]的方法的时候会使用 __getitem__的方法
        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]]#选行的操作 
                #这里是取了一个并集,ag:group_df 初始 5行,第一次循环4行符合条件,接下来继续在四行的基础上判断,类似于一个于的概念
            group_df = group_df[self.pr_col] #选列
            if group_df.shape[1] == 1:
                group_df = group_df.iloc[:, 0]# group_df 的数据类型 DataFrame -> Series  
            group_res = my_func(group_df)#对该类下每种值进行了计算
            print(type(group_res)) 
            if not isinstance(group_res, pd.Series):#因为要组合成DataFrame的对象,所以必须要转换类型  
                                                  #如果使用的是聚合函数,也就是没有在两个列上使用的话,一定不是Series类型的。
                                                    #如果是两列之间的运算,因为列是Series对象,所以列和列之间的运算也是Series对象
                group_res = pd.Series(group_res,index=group_df.index,name=group_df.name)#对于Series附上相应的index 和name 用于确定位置。同时也完成了广播的功能。
            L_order = np.r_[L_order, group_res.index]# r_ 结合np。array,变成一行的数据,方便后面的处理
            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
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值