import numpy as np
import pandas as pd
分组的三个要素:分组依据、数据来源、操作及其返回结果
一般模式:df.group(分组依据)[数据来源].使用操作
df = pd.read_csv('data/learn_pandas.csv')
df.groupby('Gender')['Height'].mean()
#按照性别统计身高的平均值
Gender
Female 159.19697
Male 173.62549
Name: Height, dtype: float64
df.head(1)
School | Grade | Name | Gender | Height | Weight | Transfer | Test_Number | Test_Date | Time_Record | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Shanghai Jiao Tong University | Freshman | Gaopeng Yang | Female | 158.9 | 46.0 | N | 1 | 2019/10/5 | 0:04:34 |
1.多维度分组,只需要在groupby中传入相应列名的列表
df.groupby(['School','Gender'])['Height'].mean()
School Gender
Fudan University Female 158.776923
Male 174.212500
Peking University Female 158.666667
Male 172.030000
Shanghai Jiao Tong University Female 159.122500
Male 176.760000
Tsinghua University Female 159.753333
Male 171.638889
Name: Height, dtype: float64
2.复杂逻辑分组
先写出分组条件
condition = df.Weight > df.Weight.mean()
df.groupby(condition)['Height'].mean()
Weight
False 159.034646
True 172.705357
Name: Height, dtype: float64
根据上下四分数分割,将体重分为high、normal、low三组,统计身高的均值
思路:首先尝试将体重分为三类,使用了if函数,但是发现无法将这个条件与Weight序列结合起来,因为apply具有迭代的作用,尝试使用apply,先将这个条件定义为一个函数。在这个过程中我在定义函数的时候将return写成了print,导致我的返回值出现了问题,这一点需要注意。
data = df.copy()
def my_condition(x):
if x <= df.Weight.quantile(0.25):
return('low')
elif x>= df.Weight.quantile(0.75):
return('high')
else:
return('normal')
new = data.Weight.apply(my_condition)
data.groupby(new)['Height'].mean()
Weight
high 174.511364
low 154.119149
normal 162.465217
Name: Height, dtype: float64
3.随机传入字母序列
item = np.random.choice(list('abc'),df.shape[0])
item.shape
(200,)
df.shape
(200, 10)
df.groupby(item)['Height'].mean()
a 163.770667
b 162.486885
c 163.285106
Name: Height, dtype: float64
此处我的理解是,我们在做groupby的时候只需要保持与原数据框的行数一致的序列,在做groupby的时候会将这个条件与原数据框自动按顺序拼接。
df.groupby([condition,item])['Weight'].mean()
Weight
False a 47.541667
b 46.558140
c 48.000000
True a 69.500000
b 70.571429
c 74.928571
Name: Weight, dtype: float64
由此可以看出,之前传入列名只是一种简便的记号,事实上等价于传入的是一个或多个列,最后分组的依据来自于数据来源组合的unique值
4.通过drop_duplicates了解具体的组类别
df[['School','Gender']].drop_duplicates()
School | Gender | |
---|---|---|
0 | Shanghai Jiao Tong University | Female |
1 | Peking University | Male |
2 | Shanghai Jiao Tong University | Male |
3 | Fudan University | Female |
4 | Fudan University | Male |
5 | Tsinghua University | Female |
9 | Peking University | Female |
16 | Tsinghua University | Male |
df.groupby([df['School'],df['Gender']])['Height'].mean()
School Gender
Fudan University Female 158.776923
Male 174.212500
Peking University Female 158.666667
Male 172.030000
Shanghai Jiao Tong University Female 159.122500
Male 176.760000
Tsinghua University Female 159.753333
Male 171.638889
Name: Height, dtype: float64
gb = df.groupby(['School','Grade'])
gb
1.通过ngroups属性,得到分组个数
gb.ngroups
16
2.通过groups属性,返回组名映射到组索引列表的字典
会返回分组的组别及其包含的值
res = gb.groups
res.keys()
dict_keys([('Fudan University', 'Freshman'), ('Fudan University', 'Junior'), ('Fudan University', 'Senior'), ('Fudan University', 'Sophomore'), ('Peking University', 'Freshman'), ('Peking University', 'Junior'), ('Peking University', 'Senior'), ('Peking University', 'Sophomore'), ('Shanghai Jiao Tong University', 'Freshman'), ('Shanghai Jiao Tong University', 'Junior'), ('Shanghai Jiao Tong University', 'Senior'), ('Shanghai Jiao Tong University', 'Sophomore'), ('Tsinghua University', 'Freshman'), ('Tsinghua University', 'Junior'), ('Tsinghua University', 'Senior'), ('Tsinghua University', 'Sophomore')])
上一小节介绍了可以通过 drop_duplicates 得到具体的组类别,现请用 groups 属性完成类似的功能。
思路:groups可以获取分组的组合,然后获取到key值,将key值转换为数据框,但是index的显示与drop_duplicates的不一致
df_demo = df.groupby(['School','Gender'])
res = df_demo.groups
pd.DataFrame(res.keys(),columns=['School','Gender'])
School | Gender | |
---|---|---|
0 | Fudan University | Female |
1 | Fudan University | Male |
2 | Peking University | Female |
3 | Peking University | Male |
4 | Shanghai Jiao Tong University | Female |
5 | Shanghai Jiao Tong University | Male |
6 | Tsinghua University | Female |
7 | Tsinghua University | Male |
3.size在DataFrame的属性时,返回的是表长乘以表宽的大小,但在groupby对象上表示统计每个组的元素个数
gb.size()
School Grade
Fudan University Freshman 9
Junior 12
Senior 11
Sophomore 8
Peking University Freshman 13
Junior 8
Senior 8
Sophomore 5
Shanghai Jiao Tong University Freshman 13
Junior 17
Senior 22
Sophomore 5
Tsinghua University Freshman 17
Junior 22
Senior 14
Sophomore 16
dtype: int64
4.get_group方法获取所在组对应的行,但是必须知道组的具体名字
gb.get_group(('Fudan University','Freshman')).iloc[:3,:3]
School | Grade | Name | |
---|---|---|---|
15 | Fudan University | Freshman | Changqiang Yang |
28 | Fudan University | Freshman | Gaoqiang Qin |
63 | Fudan University | Freshman | Gaofeng Zhao |
聚合
1.依据性别分组,统计全国人口寿命的平均值
返回一个标量值,可以是平均值、中位数、组容量 size
变换
2.依据季节分组,对每一个季节的温度进行组内标准化
做了原序列的标准化处理,也就是说每组返回的是一个 Series 类型
过滤
3.依据班级分组,筛选出组内数学分数的平均值超过80分的班级
既不是标量也不是序列,返回的整个组所在行的本身,即返回了 DataFrame 类型
聚合函数是逐列处理的,而不能够 多列数据同时处理
max/min/mean/median/count/idxmax/idxmin/nunique/quantile/sum/std/var/size
all/any
mad:返回所请求轴的值的平均绝对偏差,每个数据点与平均值之间的平均距离。
skew(偏度)
sem:计算输入数据平均值的标准误差
prod: 非NA值的元素的乘积
gb = df.groupby('Gender')['Height']
gb.nunique()
Gender
Female 99
Male 47
Name: Height, dtype: int64
这些聚合函数当传入的数据来源包含多个列时,将按照列进行迭代计算
gb = df.groupby('Gender')[['Height','Weight']]
gb.max()
Height | Weight | |
---|---|---|
Gender | ||
Female | 170.2 | 63.0 |
Male | 193.9 | 89.0 |
解决以下问题:
(1)无法同时使用多个函数
(2)无法对特定的列使用特定的聚合函数
(3)无法使用自定义的聚合函数
(4)无法直接对结果的列名在聚合前进行自定义命名
1.使用多个函数
用列表的形式把内置聚合函数对应的字符串传入
gb.agg(['sum','idxmax','skew'])
Height | Weight | |||||
---|---|---|---|---|---|---|
sum | idxmax | skew | sum | idxmax | skew | |
Gender | ||||||
Female | 21014.0 | 28 | -0.219253 | 6469.0 | 28 | -0.268482 |
Male | 8854.9 | 193 | 0.437535 | 3929.0 | 2 | -0.332393 |
列索引为多级索引,第一层为数据源,第二层为使用的聚合方法
2.对特定的列使用特定的聚合函数
通过构造字典传入 agg 中实现,其中字典以列名为键,以聚合字符串或字符串列表为值
gb.agg({
'Height':['mean','max'],'Weight':'count'})
Height | Weight | ||
---|---|---|---|
mean | max | count | |
Gender | |||
Female | 159.19697 | 170.2 | 135 |
Male | 173.62549 | 193.9 | 54 |
请使用【b】中的传入字典的方法完成【a】中等价的聚合任务。
gb.agg({
'Height':['sum', 'idxmax', 'skew'],'Weight':['sum', 'idxmax', 'skew']})
Height | Weight | |||||
---|---|---|---|---|---|---|
sum | idxmax | skew | sum | idxmax | skew | |
Gender | ||||||
Female | 21014.0 | 28 | -0.219253 | 6469.0 | 28 | -0.268482 |
Male | 8854.9 | 193 | 0.437535 | 3929.0 | 2 | -0.332393 |
传入函数的参数是之前数据源中的列,逐列进行计算
gb.agg(lambda x: x.mean()-x.min())
Height | Weight | |
---|---|---|
Gender | ||
Female | 13.79697 | 13.918519 |
Male | 17.92549 | 21.759259 |
在 groupby 对象中可以使用 describe 方法进行统计信息汇总,请同时使用多个聚合函数,完成与该方法相同的功能
#使用describe方法
gb.describe()
Height | Weight | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | mean | std | min | 25% | 50% | 75% | max | count | mean | std | min | 25% | 50% | 75% | max | |
Gender | ||||||||||||||||
Female | 132.0 | 159.19697 | 5.053982 | 145.4 | 155.675 | 159.6 | 162.825 | 170.2 | 135.0 | 47.918519 | 5.405983 | 34.0 | 44.0 | 48.0 | 52.00 | 63.0 |
Male | 51.0 | 173.62549 | 7.048485 | 155.7 | 168.900 | 173.4 | 177.150 | 193.9 | 54.0 | 72.759259 | 7.772557 | 51.0 | 69.0 | 73.0 | 78.75 | 89.0 |
其中包含有count、mean、std、min、quantile(0.25)、quantile(0.5)、quantile(0.75)、max,直接使用使用多个函数的方法agg
25%,50%,75%没有找到直接可以使用quantile的方法,所以使用了函数定义,之后发现可以直接使用lambda
def my_quantile_1(x):
return x.quantile(0.25)
def my_quantile_2(x):
return x.quantile(0.5)
def my_quantile_3(x):
return x.quantile(0.75)
gb.agg(['count','mean','std','min',('25%',lambda x:x.quantile(0.25)),('50%',lambda x:x.quantile(0.5)),('75%',lambda x:x.quantile(0.75)),'max'])
Height | Weight | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | mean | std | min | 25% | 50% | 75% | max | count | mean | std | min | 25% | 50% | 75% | max | |
Gender | ||||||||||||||||
Female | 132 | 159.19697 | 5.053982 | 145.4 | 155.675 | 159.6 | 162.825 | 170.2 | 135 | 47.918519 | 5.405983 | 34.0 | 44.0 | 48.0 | 52.00 | 63.0 |
Male | 51 | 173.62549 | 7.048485 | 155.7 | 168.900 | 173.4 | 177.150 | 193.9 | 54 | 72.759259 | 7.772557 | 51.0 | 69.0 | 73.0 | 78.75 | 89.0 |
对聚合结果的列名进行重命名,只需要将上述函数的位置改写成元组,元组的第一个元素为新的名字,第二个位置为原来的函数,包括聚合字符串和自定义函数【针对每一列需要定义一个新名字时针对它使用元组(新名称,函数)】
gb.agg([('range', lambda x: x.max()-x.min()), ('my_sum', 'sum')])
Height | Weight | |||
---|---|---|---|---|
range | my_sum | range | my_sum | |
Gender | ||||
Female | 24.8 | 21014.0 | 29.0 | 6469.0 |
Male | 38.2 | 8854.9 | 38.0 | 3929.0 |
gb.agg({
'Height':[('my_func',my_func),'sum'],
'Weight': lambda x:x.max()})
Height | Weight | ||
---|---|---|---|
my_func | sum | ||
Gender | |||
Female | 159.6 | 21014.0 | 63.0 |
Male | 173.4 | 8854.9 | 89.0 |
使用对一个或者多个列使用单个聚合的时候,重命名需要加方括号,否则就不知道是新的名字还是手误输错的内置函数字符串【不加大括号意味着对所有的列进行修改】
gb.agg([('my_sum', 'sum')])
Height | Weight | |
---|---|---|
my_sum | my_sum | |
Gender | ||
Female | 21014.0 | 6469.0 |
Male | 8854.9 | 3929.0 |
gb.agg({
'Height': [('my_func', my_func), 'sum'],'Weight': [('range', lambda x:x.max())]})
Height | Weight | ||
---|---|---|---|
my_func | sum | range | |
Gender | |||
Female | 159.6 | 21014.0 | 63.0 |
Male | 173.4 | 8854.9 | 89.0 |
变换函数的返回值为同长度的序列,最常用的内置变换函数是累计函数:
cumcount:
cumsum:
cumprod:
cummax:
cummin:
使用方式和聚合函数类似,只不过完成的是组内累计操作
gb = df.groupby('Gender')[['Height','Weight']]
gb.cummax().head()
Height | Weight | |
---|---|---|
0 | 158.9 | 46.0 |
1 | 166.5 | 70.0 |
2 | 188.9 | 89.0 |
3 | NaN | 46.0 |
4 | 188.9 | 89.0 |
在 groupby 对象中, rank 方法也是一个实用的变换函数,请查阅它的功能并给出一个使用的例子
groupby.rank:对DataFrame某列的数据进行聚类 然后对其它列的属于同类数据进行数值大小排序
method: ‘average’(在相等分组中,为各个值分配平均排名);‘min’(使用整个分组的最小排名);‘max’;‘first’(按值在原始数据中的出现顺序分配排名)
思路:在将rank后的结果存到原DataFrame的时候,出现了错误,理论上应该可以直接赋值。之后发现是我在定义demo的时候没有将它转换为DataFrame,之后再使用数据框的loc将排序的结果存储为新的列
demo = pd.DataFrame(df[['Gender','Height','Weight']])
demo.groupby(['Gender']).rank(method='first',ascending=False).head()
demo.loc[:,'rank_H'] = demo.groupby(['Gender'])['Height'].rank(method='min',ascending=False)
demo.loc[:,'rank_W'] = demo.groupby(['Gender'])['Weight'].rank(method='max',ascending=False)
demo.head()
Gender | Height | Weight | rank_H | rank_W | |
---|---|---|---|---|---|
0 | Female | 158.9 | 46.0 | 74.0 | 91.0 |
1 | Male | 166.5 | 70.0 | 47.0 | 38.0 |
2 | Male | 188.9 | 89.0 | 2.0 | 1.0 |
3 | Female | NaN | 41.0 | NaN | 123.0 |
4 | Male | 174.0 | 74.0 | 25.0 | 25.0 |
被调用的自定义函数, 其传入值为数据源的序列 ,与 agg 的传入类型是一致的,其最后的返回结果是行列索引与数据源一致的 DataFrame
例:对身高和体重进行分组标准化,即减去组均值后除以组的标准差:
gb.transform(lambda x : (x-x.mean())/x.std()).head()
Height | Weight | |
---|---|---|
0 | -0.058760 | -0.354888 |
1 | -1.010925 | -0.355000 |
2 | 2.167063 | 2.089498 |
3 | NaN | -1.279789 |
4 | 0.053133 | 0.159631 |
对于 transform 方法无法像 agg 一样,通过传入字典来对指定列使用特定的变换,如果需要在一次 transform 的调用中实现这种功能,请给出解决方案。
思路:我考虑的是定义一个函数,将数据的列做不同的处理,然后再用transform去调用函数,但是在用transform调用函数的时候出现了错误
gb = pd.DataFrame(df[['Height','Weight']])
def my_func(x):
x.iloc[:,:1] = x.iloc[:,:1].cumsum()
x.iloc[:,1:2] = x.iloc[:,1:2].cumcount()
return x
transform 只能返回同长度的序列,但事实上还可以返回一个标量,这会使得结果被广播到其所在的整个组
思考:在使用的时候,我想测试一下不使用groupby是否成功,最后还想会报错:“transforms cannot produce aggregated results”,也就是我们在使用transform之前需要时聚合的结果,因为transform不产生聚合结果
例:构造两列新特征来分别表示样本所在性别组的身高均值和体重均值
gb1 = df.groupby('Gender')[['Height','Weight']]
gb2 = pd.DataFrame(df[['Height','Weight']])
gb1.transform('mean').head()
Height | Weight | |
---|---|---|
0 | 159.19697 | 47.918519 |
1 | 173.62549 | 72.759259 |
2 | 173.62549 | 72.759259 |
3 | 159.19697 | 47.918519 |
4 | 173.62549 | 72.759259 |
gb2.transform('mean').head() ##报错
(1).过滤在分组中是对于组的过滤,而索引是对于行的过滤
(2).组过滤作为行过滤的推广,指的是如果对一个组的全体所在行进行统计的结果返回 True 则会被保留, False 则该组会被过滤,最后把所有未被过滤的组其对应的所在行拼接起来作为 DataFrame 返回
1.filter:进行组的筛选
定义函数的输入参数为数据源构成的 DataFrame 本身,所有表方法和属性都可以在自定义函数中相应地使用,同时只需保证自定义函数的返回为布尔值即可
例:在原表中通过过滤得到所有容量大于100的组
gb = df.groupby('Gender')[['Height','Weight']]
gb.filter(lambda x:x.shape[0]>100).head()
Height | Weight | |
---|---|---|
0 | 158.9 | 46.0 |
3 | NaN | 41.0 |
5 | 158.0 | 51.0 |
6 | 162.5 | 52.0 |
7 | 161.9 | 50.0 |
从概念上说,索引功能是组过滤功能的子集,请使用 filter 函数完成 loc[.] 的功能,这里假设 ” . “是元素列表
condition = df.Gender == 'Female'
df.groupby(condition).filter(lambda x :x.name).head(2)
School | Grade | Name | Gender | Height | Weight | Transfer | Test_Number | Test_Date | Time_Record | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Shanghai Jiao Tong University | Freshman | Gaopeng Yang | Female | 158.9 | 46.0 | N | 1 | 2019/10/5 | 0:04:34 |
3 | Fudan University | Sophomore | Xiaojuan Sun | Female | NaN | 41.0 | N | 2 | 2020/1/3 | 0:04:08 |
解决多列数据同时处理并且返回值为标量的问题
apply 的自定义函数传入参数与 filter 完全一致,只不过后者只允许返回布尔值
def BMI(x):
Heigth = x['Height']/100
Weight = x['Weight']
BMI_value = Weight/Heigth**2
return BMI_value.mean()
gb.apply(BMI)
Gender
Female 18.860930
Male 24.318654
dtype: float64
apply 方法还可以返回一维 Series 和二维 DataFrame ,但它们产生的数据框维数和多级索引的层数应当如何变化?
1.标量情况
结果得到的是Series,索引与agg的结果一致
gb = df.groupby(['Gender','Test_Number'])[['Height','Weight']]
gb.apply(lambda x: 0)
Gender Test_Number
Female 1 0
2 0
3 0
Male 1 0
2 0
3 0
dtype: int64
gb.apply(lambda x:[0,0]) # 虽然是列表,但是作为返回值仍然看作标量
Gender Test_Number
Female 1 [0, 0]
2 [0, 0]
3 [0, 0]
Male 1 [0, 0]
2 [0, 0]
3 [0, 0]
dtype: object
2.Series情况
得到的是 DataFrame ,行索引与标量情况一致,列索引为 Series 的索引
gb.apply(lambda x : pd.Series([0,0],index=['a','b']))
a | b | ||
---|---|---|---|
Gender | Test_Number | ||
Female | 1 | 0 | 0 |
2 | 0 | 0 | |
3 | 0 | 0 | |
Male | 1 | 0 | 0 |
2 | 0 | 0 | |
3 | 0 | 0 |
3.DataFrame情况
得到的是 DataFrame ,行索引最内层在每个组原先 agg 的结果索引上,再加一层返回的 DataFrame 行索引,同时分组结果 DataFrame 的列索引和返回的 DataFrame 列索引一致
gb.apply(lambda x: pd.DataFrame(np.ones((2,2)),
index = ['a','b'],
columns=pd.Index([('w','x'),('y','z')])))
w | y | |||
---|---|---|---|---|
x | z | |||
Gender | Test_Number | |||
Female | 1 | a | 1.0 | 1.0 |
b | 1.0 | 1.0 | ||
2 | a | 1.0 | 1.0 | |
b | 1.0 | 1.0 | ||
3 | a | 1.0 | 1.0 | |
b | 1.0 | 1.0 | ||
Male | 1 | a | 1.0 | 1.0 |
b | 1.0 | 1.0 | ||
2 | a | 1.0 | 1.0 | |
b | 1.0 | 1.0 | ||
3 | a | 1.0 | 1.0 | |
b | 1.0 | 1.0 |
注意:apply 函数的灵活性是以牺牲一定性能为代价换得的,除非需要使用跨列处理的分组处理,否则应当使用其他专门设计的 groupby 对象方法,同时,在使用聚合函数和变换函数时,也应当优先使用内置函数
在 groupby 对象中还定义了 cov 和 corr 函数,从概念上说也属于跨列的分组处理。请利用之前定义的 gb 对象,使用apply函数实现与 gb.cov() 同样的功能并比较它们的性能
思路:cov是求协方差,首先需要了解cov的公式。Cov(X,Y)=E(XY)-E(X)E(Y)
gb = df.groupby('Gender')[['Height','Weight']]
gb.cov()
Height | Weight | ||
---|---|---|---|
Gender | |||
Female | Height | 25.542739 | 24.838146 |
Weight | 24.838146 | 29.224655 | |
Male | Height | 49.681137 | 47.803901 |
Weight | 47.803901 | 60.412648 |
#参考
gb.apply(lambda x:pd.DataFrame([[x[i].cov(x[j]) for j in x.columns] for i in x.columns],index=x.columns,columns=x.columns))
Height | Weight | ||
---|---|---|---|
Gender | |||
Female | Height | 25.542739 | 24.838146 |
Weight | 24.838146 | 29.224655 | |
Male | Height | 49.681137 | 47.803901 |
Weight | 47.803901 | 60.412648 |
Brand, Disp., HP 分别代表汽车品牌、发动机蓄量、发动机输出
df = pd.read_csv('data/car.csv')
df.head(3)
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 。
思路:首先找到Country出现的次数大于2的国家,然后再通过query找到Country的值,注意使用query时,一定要加@然后使用外部参数;因为需要对特定的列进行特定的运算,所以我们使用agg
df_1= pd.DataFrame(df.groupby('Country')['Country'].size()>2)
value = list(df_1.query('Country == True').index)
df_1t = df.query('Country in @value')
df_1t.head(2)
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 |
def my_func_var(x):
x = x.std()/x.mean()
return x
df_2t = df_1t.groupby('Country')[['Price','Brand']]
df_2t.agg({
'Price':['mean',('Cov',my_func_var)], #此处也可以直接使用lambda x :x.std()/x.mean()
'Brand': 'count'})
Price | Brand | ||
---|---|---|---|
mean | Cov | count | |
Country | |||
Japan | 13938.052632 | 0.387429 | 19 |
Japan/USA | 10067.571429 | 0.240040 | 7 |
Korea | 7857.333333 | 0.243435 | 3 |
USA | 12543.269231 | 0.203344 | 26 |
2.按照表中位置的前三分之一、中间三分之一和后三分之一分组,统计 Price 的均值。
思路:先通过quantile找到对应位置的值,接着使用函数将组别分类好,其中在找到索引值之后将索引值作为一列添加进data中,之后就是使用groupby进行分组求均值。
ind = pd.Series(df.index)
data = df.copy()
data.loc[:,'new'] = ind
def my_condition(x):
if x <= ind.quantile(1/3):
return('low')
elif x>= ind.quantile(2/3):
return('high')
else:
return('normal')
new = data.new.apply(my_condition)
data.groupby(new)['Price'].mean()
new
high 15420.65
low 9069.95
normal 13356.40
Name: Price, dtype: float64
3.对类型 Type 分组,对 Price 和 HP 分别计算最大值和最小值,结果会产生多级索引,请用下划线把多级列索引合并为单层索引。
思路:因为是列产生了多级索引,所以我们的作用范围应该是列,然后是在用agg对Price和HP分别使用计算的时候,发现对函数如果不是列表,不会展示多级索引
df_3 = df.groupby('Type')[['Price','HP']]
df_t = df_3.agg({
'Price':['max'],'HP':'min'})
df_t.columns = df_t.columns.map(lambda x :(x[0]+'_'+x[1]))
df_t
Price_max | HP_min | |
---|---|---|
Type | ||
Compact | 18900 | 95 |
Large | 17257 | 150 |
Medium | 24760 | 110 |
Small | 9995 | 63 |
Sporty | 13945 | 92 |
Van | 15395 | 106 |
4.对类型 Type 分组,对 HP 进行组内的 min-max 归一化
思路:最开始想到的是使用transform,但是transform没有分组的效果。之后使用了apply,直接定义函数
df_4 = df.groupby('Type')['HP'].apply(lambda x : x.min()-x.max())
df_4
Type
Compact -47
Large -20
Medium -80
Small -50
Sporty -133
Van -44
Name: HP, dtype: int64
5.对类型 Type 分组,计算 Disp. 与 HP 的相关系数
思路:分组后使用corr()求相关系数,在这个过程中在写groupby的数据来源时没有加上[],会有警告
df_5 = df.groupby('Type')[['Disp.','HP']]
df_5.corr()
Disp. | HP | ||
---|---|---|---|
Type | |||
Compact | Disp. | 1.000000 | 0.586087 |
HP | 0.586087 | 1.000000 | |
Large | Disp. | 1.000000 | -0.242765 |
HP | -0.242765 | 1.000000 | |
Medium | Disp. | 1.000000 | 0.370491 |
HP | 0.370491 | 1.000000 | |
Small | Disp. | 1.000000 | 0.603916 |
HP | 0.603916 | 1.000000 | |
Sporty | Disp. | 1.000000 | 0.871426 |
HP | 0.871426 | 1.000000 | |
Van | Disp. | 1.000000 | 0.819881 |
HP | 0.819881 | 1.000000 |