Pandas基础3

第3章 分组

import numpy as np
import pandas as pd
df = pd.read_csv('data/table.csv',index_col='ID')
df.head()
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1102S_1C_1Fstreet_21927332.5B+
1103S_1C_1Mstreet_21868287.2B+
1104S_1C_1Fstreet_21678180.4B-
1105S_1C_1Fstreet_41596484.8B+

一、SAC过程

1. 内涵

SAC指的是分组操作中的split-apply-combine过程

其中split指基于某一些规则,将数据拆成若干组,apply是指对每一组独立地使用函数

combine指将每一组的结果组合成某一类数据结构

2. apply过程

在该过程中,我们实际往往会遇到四类问题:

整合(Aggregation)——即分组计算统计量(如求均值、求每组元素个数)

变换(Transformation)——即分组对每个单元的数据进行操作(如元素标准化)

过滤(Filtration)——即按照某些规则筛选出一些组(如选出组内某一指标小于50的组)

综合问题——即前面提及的三种问题的混合

二、groupby函数

1. 分组函数的基本内容:

(a)根据某一列分组

grouped_single = df.groupby('School')
grouped_single
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001F596F7BE48>

经过groupby后会生成一个groupby对象,该对象本身不会返回任何东西,只有当相应的方法被调用才会起作用

例如取出某一个组:

grouped_single.get_group('S_1').head()
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1102S_1C_1Fstreet_21927332.5B+
1103S_1C_1Mstreet_21868287.2B+
1104S_1C_1Fstreet_21678180.4B-
1105S_1C_1Fstreet_41596484.8B+

(b)根据某几列分组

grouped_mul = df.groupby(['School','Class'])
grouped_mul.get_group(('S_1','C_1'))#输入一个元组
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1102S_1C_1Fstreet_21927332.5B+
1103S_1C_1Mstreet_21868287.2B+
1104S_1C_1Fstreet_21678180.4B-
1105S_1C_1Fstreet_41596484.8B+

(c)组容量与组数

grouped_single.size()
School
S_1    15
S_2    20
dtype: int64
grouped_mul.size()
School  Class
S_1     C_1      5
        C_2      5
        C_3      5
S_2     C_1      5
        C_2      5
        C_3      5
        C_4      5
dtype: int64
grouped_single.ngroups
2
grouped_mul.ngroups
7

(d)组的遍历

for name,group in grouped_single:
    print(name)
    display(name)
    display(group)
S_1



'S_1'
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1102S_1C_1Fstreet_21927332.5B+
1103S_1C_1Mstreet_21868287.2B+
1104S_1C_1Fstreet_21678180.4B-
1105S_1C_1Fstreet_41596484.8B+
1201S_1C_2Mstreet_51886897.0A-
1202S_1C_2Fstreet_41769463.5B-
1203S_1C_2Mstreet_61605358.8A+
1204S_1C_2Fstreet_51626333.8B
1205S_1C_2Fstreet_61676368.4B-
1301S_1C_3Mstreet_41616831.5B+
1302S_1C_3Fstreet_11755787.7A-
1303S_1C_3Mstreet_71888249.7B
1304S_1C_3Mstreet_21957085.2A
1305S_1C_3Fstreet_51876961.7B-
S_2



'S_2'
SchoolClassGenderAddressHeightWeightMathPhysics
ID
2101S_2C_1Mstreet_71748483.3C
2102S_2C_1Fstreet_61616150.6B+
2103S_2C_1Mstreet_41576152.5B-
2104S_2C_1Fstreet_51599772.2B+
2105S_2C_1Mstreet_41708134.2A
2201S_2C_2Mstreet_519310039.1B
2202S_2C_2Fstreet_71947768.5B+
2203S_2C_2Mstreet_41559173.8A+
2204S_2C_2Mstreet_11757447.2B-
2205S_2C_2Fstreet_71837685.4B
2301S_2C_3Fstreet_41577872.3B+
2302S_2C_3Mstreet_51718832.7A
2303S_2C_3Fstreet_71909965.9C
2304S_2C_3Fstreet_61648195.5A-
2305S_2C_3Mstreet_41877348.9B
2401S_2C_4Fstreet_21926245.3A
2402S_2C_4Mstreet_71668248.7B
2403S_2C_4Fstreet_61586059.7B+
2404S_2C_4Fstreet_21608467.7B
2405S_2C_4Fstreet_61935447.6B

(e)level参数(用于多级索引)和axis参数

df.set_index(['Gender','School']).groupby(level=1,axis=0).get_group('S_1').head()
ClassAddressHeightWeightMathPhysics
GenderSchool
MS_1C_1street_11736334.0A+
FS_1C_1street_21927332.5B+
MS_1C_1street_21868287.2B+
FS_1C_1street_21678180.4B-
S_1C_1street_41596484.8B+

2. groupby对象的特点

(a)查看所有可调用的方法

由此可见,groupby对象可以使用相当多的函数,灵活程度很高

print([attr for attr in dir(grouped_single) if not attr.startswith('_')])
['Address', 'Class', 'Gender', 'Height', 'Math', 'Physics', 'School', 'Weight', 'agg', 'aggregate', 'all', 'any', 'apply', 'backfill', 'bfill', 'boxplot', 'corr', 'corrwith', 'count', 'cov', 'cumcount', 'cummax', 'cummin', 'cumprod', 'cumsum', 'describe', 'diff', 'dtypes', 'expanding', 'ffill', 'fillna', 'filter', 'first', 'get_group', 'groups', 'head', 'hist', 'idxmax', 'idxmin', 'indices', 'last', 'mad', 'max', 'mean', 'median', 'min', 'ndim', 'ngroup', 'ngroups', 'nth', 'nunique', 'ohlc', 'pad', 'pct_change', 'pipe', 'plot', 'prod', 'quantile', 'rank', 'resample', 'rolling', 'sem', 'shift', 'size', 'skew', 'std', 'sum', 'tail', 'take', 'transform', 'tshift', 'var']

(b)分组对象的head和first

对分组对象使用head函数,返回的是每个组的前几行,而不是数据集前几行

grouped_single.head()
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1102S_1C_1Fstreet_21927332.5B+
1103S_1C_1Mstreet_21868287.2B+
1104S_1C_1Fstreet_21678180.4B-
1105S_1C_1Fstreet_41596484.8B+
2101S_2C_1Mstreet_71748483.3C
2102S_2C_1Fstreet_61616150.6B+
2103S_2C_1Mstreet_41576152.5B-
2104S_2C_1Fstreet_51599772.2B+
2105S_2C_1Mstreet_41708134.2A

first显示的是以分组为索引的每组的第一个分组信息

grouped_single.first()
ClassGenderAddressHeightWeightMathPhysics
School
S_1C_1Mstreet_11736334.0A+
S_2C_1Mstreet_71748483.3C

(c)分组依据

对于groupby函数而言,分组的依据是非常自由的,只要是与数据框长度相同的列表即可,同时支持函数型分组

df.groupby(np.random.choice(['a','b','c'],df.shape[0])).get_group('a').head()
#相当于将np.random.choice(['a','b','c'],df.shape[0])当做新的一列进行分组
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1105S_1C_1Fstreet_41596484.8B+
1201S_1C_2Mstreet_51886897.0A-
1204S_1C_2Fstreet_51626333.8B
1302S_1C_3Fstreet_11755787.7A-
2104S_2C_1Fstreet_51599772.2B+
np.random.choice(['a','b','c'],df.shape[0])
array(['b', 'b', 'a', 'c', 'a', 'a', 'a', 'c', 'b', 'c', 'a', 'c', 'b',
       'a', 'b', 'a', 'c', 'a', 'c', 'c', 'b', 'c', 'a', 'c', 'a', 'a',
       'a', 'c', 'b', 'a', 'b', 'b', 'c', 'c', 'a'], dtype='<U1')

从原理上说,我们可以看到利用函数时,传入的对象就是索引,因此根据这一特性可以做一些复杂的操作

df[:5].groupby(lambda x:print(x)).head()
1101
1102
1103
1104
1105
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1102S_1C_1Fstreet_21927332.5B+
1103S_1C_1Mstreet_21868287.2B+
1104S_1C_1Fstreet_21678180.4B-
1105S_1C_1Fstreet_41596484.8B+

根据奇偶行分组

df.groupby(lambda x:'奇数行' if not df.index.get_loc(x)%2==1 else '偶数行').get_group('奇数行').head()
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1103S_1C_1Mstreet_21868287.2B+
1105S_1C_1Fstreet_41596484.8B+
1202S_1C_2Fstreet_41769463.5B-
1204S_1C_2Fstreet_51626333.8B

如果是多层索引,那么lambda表达式中的输入就是元组,下面实现的功能为查看两所学校中男女生分别均分是否及格

注意:此处只是演示groupby的用法,实际操作不会这样写

math_score = df.set_index(['Gender','School'])['Math'].sort_index()
grouped_score = df.set_index(['Gender','School']).sort_index().\
            groupby(lambda x:(x,'均分及格' if math_score[x].mean()>=60 else '均分不及格'))
for name,_ in grouped_score:print(name)
(('F', 'S_1'), '均分及格')
(('F', 'S_2'), '均分及格')
(('M', 'S_1'), '均分及格')
(('M', 'S_2'), '均分不及格')
math_score[('F', 'S_1')]
(F, S_1)    32.5
(F, S_1)    80.4
(F, S_1)    84.8
(F, S_1)    63.5
(F, S_1)    33.8
(F, S_1)    68.4
(F, S_1)    87.7
(F, S_1)    61.7
Name: Math, dtype: float64

(d)groupby的[]操作

可以用[]选出groupby对象的某个或者某几个列,上面的均分比较可以如下简洁地写出:

df.groupby(['Gender','School'])['Math'].mean()>=60
Gender  School
F       S_1        True
        S_2        True
M       S_1        True
        S_2       False
Name: Math, dtype: bool

用列表可选出多个属性列:

df.groupby(['Gender','School'])[['Math','Height']].mean()
MathHeight
GenderSchool
FS_164.100000173.125000
S_266.427273173.727273
MS_163.342857178.714286
S_251.155556172.000000

(e)连续型变量分组

例如利用cut函数对数学成绩分组:

bins = [0,40,60,80,90,100]
cuts = pd.cut(df['Math'],bins=bins) #可选label添加自定义标签
df.groupby(cuts)['Math'].size()#count()也行
Math
(0, 40]       7
(40, 60]     10
(60, 80]      9
(80, 90]      7
(90, 100]     2
Name: Math, dtype: int64

三、聚合、过滤和变换

1. 聚合(Aggregation)

(a)常用聚合函数

所谓聚合就是把一堆数,变成一个标量,因此mean/sum/size/count/std/var/sem/describe/first/last/nth/min/max都是聚合函数

为了熟悉操作,不妨验证标准误sem函数,它的计算公式是: 组 内 标 准 差 组 容 量 \frac{组内标准差}{\sqrt{组容量}} ,下面进行验证:

group_m = grouped_single['Math']
group_m.std().values/(np.sqrt(group_m.count().values)) == group_m.sem().values
array([ True,  True])

(b)同时使用多个聚合函数

group_m.agg(['sum','mean','std','max'])
summeanstdmax
School
S_1956.263.74666723.07747497.0
S_21191.159.55500017.58930595.5

利用元组进行重命名

group_m.agg([('rename_sum','sum'),('rename_mean','mean')])
rename_sumrename_mean
School
S_1956.263.746667
S_21191.159.555000

指定哪些函数作用哪些列

grouped_mul.agg({'Math':['mean','max'],'Height':'var'})#字典
MathHeight
meanmaxvar
SchoolClass
S_1C_163.7887.2183.3
C_264.3097.0132.8
C_363.1687.7179.2
S_2C_158.5683.354.7
C_262.8085.4256.0
C_363.0695.5205.7
C_453.8067.7300.2

(c)使用自定义函数

grouped_single['Math'].agg(lambda x:print(x.head(), '\n间隔'))
#可以发现,agg函数的传入是分组逐列进行的,有了这个特性就可以做许多事情
1101    34.0
1102    32.5
1103    87.2
1104    80.4
1105    84.8
Name: Math, dtype: float64 
间隔
2101    83.3
2102    50.6
2103    52.5
2104    72.2
2105    34.2
Name: Math, dtype: float64 
间隔





School
S_1    None
S_2    None
Name: Math, dtype: object

官方没有提供极差计算的函数,但通过agg可以容易地实现组内极差计算

group_m.agg(lambda x: x.max()-x.min())
School
S_1    65.5
S_2    62.8
Name: Math, dtype: float64

(d)利用NamedAgg函数进行多个聚合

注意:不支持lambda函数,但是可以使用外置的def函数

def R1(x):
    return x.max()-x.min()
def R2(x):
    return x.max()-x.median()
grouped_single['Math'].agg(min_score1=pd.NamedAgg(column='col10', aggfunc='min'),
                           max_score1=pd.NamedAgg(column='col2', aggfunc='max'),
                           jicha_score1=pd.NamedAgg(column='col1', aggfunc=R1),
                           range_score2=pd.NamedAgg(column='col3', aggfunc=R2))
min_score1max_score1jicha_score1range_score2
School
S_131.597.065.533.5
S_232.795.562.839.4
grouped_single['Math'].get_group('S_2').median()
56.1

(e)带参数的聚合函数

判断是否组内数学分数至少有一个值在50-52之间:

def f(s,low,high):
    return s.between(low,high).max()
grouped_single['Math'].agg(f,50,52)
School
S_1    False
S_2     True
Name: Math, dtype: bool
grouped_single['Math'].get_group('S_1').between(20,34)#包括边界
ID
1101     True
1102     True
1103    False
1104    False
1105    False
1201    False
1202    False
1203    False
1204     True
1205    False
1301     True
1302    False
1303    False
1304    False
1305    False
Name: Math, dtype: bool

没看懂如果需要使用多个函数,并且其中至少有一个带参数,则使用wrap技巧:

def f_test(s,low,high):
    return s.between(low,high).max()
def agg_f(f_mul,name,*args,**kwargs):
    def wrapper(x):
        return f_mul(x,*args,**kwargs)
    wrapper.__name__ = name
    return wrapper
new_f = agg_f(f_test,'at_least_one_in_50_52',50,52)
grouped_single['Math'].agg([new_f,'mean']).head()
at_least_one_in_50_52mean
School
S_1False63.746667
S_2True59.555000

2. 过滤(Filteration)

filter函数是用来筛选某些组的(务必记住结果是组的全体),因此传入的值应当是布尔标量

grouped_single[['Math','Physics']].filter(lambda x:(x['Math']>32).all())
MathPhysics
ID
210183.3C
210250.6B+
210352.5B-
210472.2B+
210534.2A
220139.1B
220268.5B+
220373.8A+
220447.2B-
220585.4B
230172.3B+
230232.7A
230365.9C
230495.5A-
230548.9B
240145.3A
240248.7B
240359.7B+
240467.7B
240547.6B

3. 变换(Transformation)

(a)传入对象

transform函数中传入的对象是组内的列,并且返回值需要与列长完全一致

grouped_single[['Math','Height']].transform(lambda x:x-x.min()).head()
MathHeight
ID
11012.514
11021.033
110355.727
110448.98
110553.30

如果返回了标量值,那么组内的所有元素会被广播为这个值

grouped_single[['Math','Height']].transform(lambda x:x.mean())
MathHeight
ID
110163.746667175.733333
110263.746667175.733333
110363.746667175.733333
110463.746667175.733333
110563.746667175.733333
120163.746667175.733333
120263.746667175.733333
120363.746667175.733333
120463.746667175.733333
120563.746667175.733333
130163.746667175.733333
130263.746667175.733333
130363.746667175.733333
130463.746667175.733333
130563.746667175.733333
210159.555000172.950000
210259.555000172.950000
210359.555000172.950000
210459.555000172.950000
210559.555000172.950000
220159.555000172.950000
220259.555000172.950000
220359.555000172.950000
220459.555000172.950000
220559.555000172.950000
230159.555000172.950000
230259.555000172.950000
230359.555000172.950000
230459.555000172.950000
230559.555000172.950000
240159.555000172.950000
240259.555000172.950000
240359.555000172.950000
240459.555000172.950000
240559.555000172.950000

(b)利用变换方法进行组内标准化

grouped_single[['Math','Height']].transform(lambda x:(x-x.mean())/x.std())
MathHeight
ID
1101-1.288991-0.214991
1102-1.3539901.279460
11031.0162870.807528
11040.721627-0.686923
11050.912289-1.316166
12011.4409430.964839
1202-0.0106890.020975
1203-0.214350-1.237510
1204-1.297658-1.080200
12050.201640-0.686923
1301-1.397322-1.158855
13021.037953-0.057681
1303-0.6086740.964839
13040.9296221.515426
1305-0.0886870.886183
21011.3499680.073242
2102-0.509116-0.833560
2103-0.401096-1.112576
21040.718903-0.973068
2105-1.441501-0.205774
2201-1.1629231.398568
22020.5085481.468322
22030.809867-1.252084
2204-0.7024150.142996
22051.4693590.701028
23010.724588-1.112576
2302-1.526780-0.136020
23030.3607311.189306
23042.043571-0.624298
2305-0.6057660.980044
2401-0.8104361.328814
2402-0.617136-0.484790
24030.008244-1.042822
24040.463065-0.903314
2405-0.6796741.398568

(c)利用变换方法进行组内缺失值的均值填充

df_nan = df[['Math','School']].copy().reset_index()
df_nan.loc[np.random.randint(0,df.shape[0],25),['Math']]=np.nan
df_nan.groupby('School').head()
IDMathSchool
01101NaNS_1
11102NaNS_1
21103NaNS_1
3110480.4S_1
41105NaNS_1
15210183.3S_2
162102NaNS_2
172103NaNS_2
18210472.2S_2
192105NaNS_2
df_nan.groupby('School').transform(lambda x: x.fillna(x.mean())).join(df.reset_index()['School']).head()
IDMathSchool
0110178.75S_1
1110278.75S_1
2110378.75S_1
3110480.40S_1
4110578.75S_1

四、apply函数

1. apply函数的灵活性

可能在所有的分组函数中,apply是应用最为广泛的,这得益于它的灵活性:

对于传入值而言,从下面的打印内容可以看到是以分组的表传入apply中:

df.groupby('School').apply(lambda x:print(x.head(1)))
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1101    S_1   C_1      M  street_1     173      63  34.0      A+
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
2101    S_2   C_1      M  street_7     174      84  83.3       C

apply函数的灵活性很大程度来源于其返回值的多样性:

① 标量返回值

df[['School','Math','Height']].groupby('School').apply(lambda x:x.max())
SchoolMathHeight
School
S_1S_197.0195
S_2S_295.5194

② 列表返回值

df[['School','Math','Height']].groupby('School').apply(lambda x:x-x.min()).head()
MathHeight
ID
11012.514.0
11021.033.0
110355.727.0
110448.98.0
110553.30.0

③ 数据框返回值

df[['School','Math','Height']].groupby('School')\
    .apply(lambda x:pd.DataFrame({'col1':x['Math']-x['Math'].max(),
                                  'col2':x['Math']-x['Math'].min(),
                                  'col3':x['Height']-x['Height'].max(),
                                  'col4':x['Height']-x['Height'].min()})).head()
col1col2col3col4
ID
1101-63.02.5-2214
1102-64.51.0-333
1103-9.855.7-927
1104-16.648.9-288
1105-12.253.3-360

2. 用apply同时统计多个指标

此处可以借助OrderedDict工具进行快捷的统计:

from collections import OrderedDict
def f(df):
    data = OrderedDict()
    data['M_sum'] = df['Math'].sum()
    data['W_var'] = df['Weight'].var()
    data['H_mean'] = df['Height'].mean()
    return pd.Series(data)
grouped_single.apply(f)
M_sumW_varH_mean
School
S_1956.2117.428571175.733333
S_21191.1181.081579172.950000

五、问题与练习

【问题一】 什么是fillna的前向/后向填充,如何实现?

向前和向后填充,使用 ffill和 bfill

fillna(method=‘ffill’)

fillna(method=‘bfill’)

【问题二】 下面的代码实现了什么功能?请仿照设计一个它的groupby版本。

s = pd.Series ([0, 1, 1, 0, 1, 1, 1, 0])
s1 = s.cumsum()
s.mul(s1).diff().where(lambda x: x < 0).ffill().add(s1,fill_value =0)
0    0.0
1    1.0
2    2.0
3    0.0
4    1.0
5    2.0
6    3.0
7    0.0
dtype: float64

【问题三】 如何计算组内0.25分位数与0.75分位数?要求显示在同一张表上。

【问题四】 既然索引已经能够选出某些符合条件的子集,那么filter函数的设计有什么意义?

【问题五】 整合、变换、过滤三者在输入输出和功能上有何异同?

【问题六】 在带参数的多函数聚合时,有办法能够绕过wrap技巧实现同样功能吗?

def R1(x):
    return np.percentile(x,25)
def R2(x):
    return np.percentile(x,75)
print(grouped_single.agg(percentile_25=pd.NamedAgg(column='Math', aggfunc=R1),
                           percentile_75=pd.NamedAgg(column='Math', aggfunc=R2)))

        percentile_25  percentile_75
School                              
S_1             41.85         85.000
S_2             47.50         72.225

过滤是筛选组更大局,针对组的全体。

聚合主要还是对每个组,转换使用时是对组内每个对象;过滤是筛选组。

  1. 练习

【练习一】: 现有一份关于diamonds的数据集,列分别记录了克拉数、颜色、开采深度、价格,请解决下列问题:

df=pd.read_csv('data/Diamonds.csv')
df.head()
caratcolordepthprice
00.23E61.5326
10.21E59.8326
20.23E56.9327
30.29I62.4334
40.31J63.3335

(a) 在所有重量超过1克拉的钻石中,价格的极差是多少?

(b) 若以开采深度的0.2\0.4\0.6\0.8分位数为分组依据,每一组中钻石颜色最多的是哪一种?该种颜色是组内平均而言单位重量最贵的吗?

© 以重量分组(0-0.5,0.5-1,1-1.5,1.5-2,2+),按递增的深度为索引排序,求每组中连续的严格递增价格序列长度的最大值。

(d) 请按颜色分组,分别计算价格关于克拉数的回归系数。(单变量的简单线性回归,并只使用Pandas和Numpy完成)

df.query('carat>1')['price'].max()-df.query('carat>1')['price'].min()
bins = df['depth'].quantile(np.linspace(0,1,6)).tolist()
cuts =pd.cut(df['depth'],bins=bins)
df['cuts']=cuts
df.groupby('cuts')['color'].describe()


countuniquetopfreq
cuts
(43.0, 60.8]112947E2259
(60.8, 61.6]118317G2593
(61.6, 62.1]104037G2247
(62.1, 62.7]101377G2193
(62.7, 79.0]102737G2000
j=0
df['junjia']=df['price']/df['carat']
for i in df.groupby(['cuts' ,'color'])['junjia'].mean().groupby(['cuts']).idxmax().values:
    if i[1]==df.groupby('cuts')['color'].describe()['top'][j]:
        print(df.groupby('cuts')['color'].describe()['top'].index[j],sep=' ')
        print(i[1])

        j += 1
(62.1, 62.7]
G
(62.7, 79.0]
G
df = pd.read_csv('data/Diamonds.csv')
df.head()
df_r = df.query('carat>1')['price']
df_r.max()-df_r.min()

bins = df['depth'].quantile(np.linspace(0,1,6)).tolist()
cuts = pd.cut(df['depth'],bins=bins) #可选label添加自定义标签
df['cuts'] = cuts
df.head()

color_result = df.groupby('cuts')['color'].describe()
color_result


df['均重价格']=df['price']/df['carat']
color_result['top'] == [i[1] for i in df.groupby(['cuts'
                                ,'color'])['均重价格'].mean().groupby(['cuts']).idxmax().values]

df = df.drop(columns='均重价格')
cuts = pd.cut(df['carat'],bins=[0,0.5,1,1.5,2,np.inf]) #可选label添加自定义标签
df['cuts'] = cuts
df.head()

def f(nums):
    if not nums:        
        return 0
    res = 1                            
    cur_len = 1                        
    for i in range(1, len(nums)):      
        if nums[i-1] < nums[i]:        
            cur_len += 1                
            res = max(cur_len, res)     
        else:                       
            cur_len = 1                 
    return res

for name,group in df.groupby('cuts'):
    group = group.sort_values(by='depth')
    s = group['price']
    print(name,f(s.tolist()))
(0.0, 0.5] 8
(0.5, 1.0] 8
(1.0, 1.5] 7
(1.5, 2.0] 11
(2.0, inf] 7
for name,group in df[['carat','price','color']].groupby('color'):
    L1 = np.array([np.ones(group.shape[0]),group['carat']]).reshape(2,group.shape[0])
    L2 = group['price']
    result = (np.linalg.inv(L1.dot(L1.T)).dot(L1)).dot(L2).reshape(2,1)
    print('当颜色为%s时,截距项为:%f,回归系数为:%f'%(name,result[0],result[1]))
当颜色为D时,截距项为:-2361.017152,回归系数为:8408.353126
当颜色为E时,截距项为:-2381.049600,回归系数为:8296.212783
当颜色为F时,截距项为:-2665.806191,回归系数为:8676.658344
当颜色为G时,截距项为:-2575.527643,回归系数为:8525.345779
当颜色为H时,截距项为:-2460.418046,回归系数为:7619.098320
当颜色为I时,截距项为:-2878.150356,回归系数为:7761.041169
当颜色为J时,截距项为:-2920.603337,回归系数为:7094.192092

【练习二】:有一份关于美国10年至17年的非法药物数据集,列分别记录了年份、州(5个)、县、药物类型、报告数量,请解决下列问题:

pd.read_csv('data/Drugs.csv').head()
YYYYStateCOUNTYSubstanceNameDrugReports
02010VAACCOMACKPropoxyphene1
12010OHADAMSMorphine9
22010PAADAMSMethadone2
32010VAALEXANDRIA CITYHeroin5
42010PAALLEGHENYHydromorphone5

(a) 按照年份统计,哪个县的报告数量最多?这个县所属的州在当年也是报告数最多的吗?

(b) 从14年到15年,Heroin的数量增加最多的是哪一个州?它在这个州是所有药物中增幅最大的吗?若不是,请找出符合该条件的药物。

df = pd.read_csv('data/Drugs.csv')
df.head()
YYYYStateCOUNTYSubstanceNameDrugReports
02010VAACCOMACKPropoxyphene1
12010OHADAMSMorphine9
22010PAADAMSMethadone2
32010VAALEXANDRIA CITYHeroin5
42010PAALLEGHENYHydromorphone5
idx=pd.IndexSlice
for i in range(2010,2018):
    county = (df.groupby(['COUNTY','YYYY']).sum().loc[idx[:,i],:].idxmax()[0][0])
    state = df.query('COUNTY == "%s"'%county)['State'].iloc[0]
    state_true = df.groupby(['State','YYYY']).sum().loc[idx[:,i],:].idxmax()[0][0]
    if state==state_true:
        print('在%d年,%s县的报告数最多,它所属的州%s也是报告数最多的'%(i,county,state))
    else:
        print('在%d年,%s县的报告数最多,但它所属的州%s不是报告数最多的,%s州报告数最多'%(i,county,state,state_true))
在2010年,PHILADELPHIA县的报告数最多,它所属的州PA也是报告数最多的
在2011年,PHILADELPHIA县的报告数最多,但它所属的州PA不是报告数最多的,OH州报告数最多
在2012年,PHILADELPHIA县的报告数最多,但它所属的州PA不是报告数最多的,OH州报告数最多
在2013年,PHILADELPHIA县的报告数最多,但它所属的州PA不是报告数最多的,OH州报告数最多
在2014年,PHILADELPHIA县的报告数最多,但它所属的州PA不是报告数最多的,OH州报告数最多
在2015年,PHILADELPHIA县的报告数最多,但它所属的州PA不是报告数最多的,OH州报告数最多
在2016年,HAMILTON县的报告数最多,它所属的州OH也是报告数最多的
在2017年,HAMILTON县的报告数最多,它所属的州OH也是报告数最多的
df_b = df[(df['YYYY'].isin([2014,2015]))&(df['SubstanceName']=='Heroin')]
df_add = df_b.groupby(['YYYY','State']).sum()
(df_add.loc[2015]-df_add.loc[2014]).idxmax()
DrugReports    OH
dtype: object
df_b = df[(df['YYYY'].isin([2014,2015]))&(df['State']=='OH')]
df_add = df_b.groupby(['YYYY','SubstanceName']).sum()
display((df_add.loc[2015]-df_add.loc[2014]).idxmax()) #这里利用了索引对齐的特点
display((df_add.loc[2015]/df_add.loc[2014]).idxmax())
DrugReports    Heroin
dtype: object



DrugReports    Acetyl fentanyl
dtype: object
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值