第3章 panda 分组

第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')
经过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_2','C_4'))
SchoolClassGenderAddressHeightWeightMathPhysics
ID
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
(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 i,group  in grouped_single:   #组名,分组
    print(i)
    display(group.head())
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+
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
(e)level参数(用于多级索引)和axis参数
df.set_index(['Gender','School']).groupby(level=0,axis=0).get_group('F').head()  #level多级索引级别
ClassAddressHeightWeightMathPhysics
GenderSchool
FS_1C_1street_21927332.5B+
S_1C_1street_21678180.4B-
S_1C_1street_41596484.8B+
S_1C_2street_41769463.5B-
S_1C_2street_51626333.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(2)
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1102S_1C_1Fstreet_21927332.5B+
2101S_2C_1Mstreet_71748483.3C
2102S_2C_1Fstreet_61616150.6B+
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('b').head()   #a,b,c抽随机抽35次对应每行进行分组
#相当于将np.random.choice(['a','b','c'],df.shape[0])当做新的一列进行分组

SchoolClassGenderAddressHeightWeightMathPhysics
ID
1103S_1C_1Mstreet_21868287.2B+
1105S_1C_1Fstreet_41596484.8B+
1301S_1C_3Mstreet_41616831.5B+
1302S_1C_3Fstreet_11755787.7A-
1303S_1C_3Mstreet_71888249.7B
从原理上说,我们可以看到利用函数时,传入的对象就是索引,因此根据这一特性可以做一些复杂的操作
df[:5].groupby(lambda x:print(x)).head(2)

1101
1102
1103
1104
1105
SchoolClassGenderAddressHeightWeightMathPhysics
ID
1101S_1C_1Mstreet_11736334.0A+
1102S_1C_1Fstreet_21927332.5B+
根据奇偶行分组
df.groupby(lambda x:'奇数行' if not df.index.get_loc(x)%2==1 else '偶数行').groups
# df.index.get_loc(1101)  通过索引获得行号
{'偶数行': Int64Index([1102, 1104, 1201, 1203, 1205, 1302, 1304, 2101, 2103, 2105, 2202,
             2204, 2301, 2303, 2305, 2402, 2404],
            dtype='int64', name='ID'),
 '奇数行': Int64Index([1101, 1103, 1105, 1202, 1204, 1301, 1303, 1305, 2102, 2104, 2201,
             2203, 2205, 2302, 2304, 2401, 2403, 2405],
            dtype='int64', name='ID')}
如果是多层索引,那么lambda表达式中的输入就是元组,下面实现的功能为查看两所学校中男女生分别均分是否及格
注意:此处只是演示groupby的用法,实际操作不会这样写
math_score = df.set_index(['Gender','School'])['Math'].sort_index()
grouped_score = df.set_index(['Gender','School']).groupby(lambda x:(x,'均分及格' if math_score[x].mean()>=60 else '均分不及格'))  #x为分组
for name,_ in grouped_score:print(name)
print(math_score)
(('F', 'S_1'), '均分及格')
(('F', 'S_2'), '均分及格')
(('M', 'S_1'), '均分及格')
(('M', 'S_2'), '均分不及格')
Gender  School
F       S_1       32.5
        S_1       80.4
        S_1       84.8
        S_1       63.5
        S_1       33.8
        S_1       68.4
        S_1       87.7
        S_1       61.7
        S_2       50.6
        S_2       72.2
        S_2       68.5
        S_2       85.4
        S_2       72.3
        S_2       65.9
        S_2       95.5
        S_2       45.3
        S_2       59.7
        S_2       67.7
        S_2       47.6
M       S_1       34.0
        S_1       87.2
        S_1       97.0
        S_1       58.8
        S_1       31.5
        S_1       49.7
        S_1       85.2
        S_2       83.3
        S_2       52.5
        S_2       34.2
        S_2       39.1
        S_2       73.8
        S_2       47.2
        S_2       32.7
        S_2       48.9
        S_2       48.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'].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']
print(group_m.std().values/np.sqrt(group_m.count().values)== group_m.sem().values)
print(group_m.std().values)  #组内标准差
print(np.sqrt(group_m.count().values)) #组容量 
print(group_m.std().values/np.sqrt(group_m.count().values))
[ True  True]
[23.07747407 17.58930521]
[3.87298335 4.47213595]
[5.95857818 3.93308821]
(b)同时使用多个聚合函数
group_m.agg(['sum','mean','std'])
summeanstd
School
S_1956.263.74666723.077474
S_21191.159.55500017.589305
利用元组进行重命名
group_m.agg([('Sum','sum'),('Mean','mean')])
SumMean
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,'间隔'))
#可以发现,agg函数的传入是分组逐列进行的,有了这个特性就可以做许多事情
1101    34.0
1102    32.5
1103    87.2
1104    80.4
1105    84.8
1201    97.0
1202    63.5
1203    58.8
1204    33.8
1205    68.4
1301    31.5
1302    87.7
1303    49.7
1304    85.2
1305    61.7
Name: Math, dtype: float64 间隔
2101    83.3
2102    50.6
2103    52.5
2104    72.2
2105    34.2
2201    39.1
2202    68.5
2203    73.8
2204    47.2
2205    85.4
2301    72.3
2302    32.7
2303    65.9
2304    95.5
2305    48.9
2401    45.3
2402    48.7
2403    59.7
2404    67.7
2405    47.6
Name: Math, dtype: float64 间隔





School
S_1   NaN
S_2   NaN
Name: Math, dtype: float64
官方没有提供极差计算的函数,但通过agg可以容易地实现组内极差计算
grouped_single['Math'].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='col1',aggfunc='min'),
                           max_score1=pd.NamedAgg(column='col2', aggfunc='max'),
                           range_score2=pd.NamedAgg(column='col3', aggfunc=R2))
        
min_score1max_score1range_score2
School
S_131.597.033.5
S_232.795.539.4
(e)带参数的聚合函数
判断是否组内数学分数至少有一个值在50-52之间:
def f(s,low,high):
    return s.between(low,high).any()
grouped_single['Math'].agg(f,50,52)
School
S_1    False
S_2     True
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()).head()
MathPhysics
ID
210183.3C
210250.6B+
210352.5B-
210472.2B+
210534.2A

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()).head()
MathHeight
ID
1101-1.288991-0.214991
1102-1.3539901.279460
11031.0162870.807528
11040.721627-0.686923
11050.912289-1.316166
(c)利用变换方法进行组内缺失值的均值填充
df_nan = df[['Math','School']].copy().reset_index()
df_nan.loc[np.random.randint(0,df.shape[0],5),['Math']]=np.nan
df_nan
IDMathSchool
0110134.0S_1
1110232.5S_1
21103NaNS_1
3110480.4S_1
4110584.8S_1
51201NaNS_1
6120263.5S_1
7120358.8S_1
8120433.8S_1
9120568.4S_1
10130131.5S_1
111302NaNS_1
12130349.7S_1
13130485.2S_1
14130561.7S_1
152101NaNS_2
16210250.6S_2
17210352.5S_2
18210472.2S_2
19210534.2S_2
20220139.1S_2
21220268.5S_2
22220373.8S_2
23220447.2S_2
24220585.4S_2
25230172.3S_2
262302NaNS_2
27230365.9S_2
28230495.5S_2
29230548.9S_2
30240145.3S_2
31240248.7S_2
32240359.7S_2
33240467.7S_2
34240547.6S_2
df_nan.groupby('School').transform(lambda x: x.fillna(x.mean())).join(df.reset_index()['School']).head()   #缺失值填充
IDMathSchool
0110134.000S_1
1110232.500S_1
2110357.025S_1
3110480.400S_1
4110584.800S_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

五、问题与练习

1. 问题

【问题一】 rolling和expanding方法从原理上说都是一种transform方法,请问它们有什么区别?
【问题二】 什么是fillna的前向/后向填充,如何实现?
向前和向后填充,使用 ffill和 bfill
fillna(method='ffill')
fillna(method='bfill')
【问题三】 下面的代码实现了什么功能?请仿照设计一个它的groupby版本。
s = pd.Series ([0, 1, 1, 0, 1, 1, 1, 0])
s1 = s.cumsum()   #([0,1,2,2,3,4,5,5])
result = s.mul(s1).diff().where(lambda x: x < 0).ffill().add(s1,fill_value =0)  #相乘作差集,
s1
print(s.mul(s1))
print(s.mul(s1).diff())
result
0    0
1    1
2    2
3    0
4    3
5    4
6    5
7    0
dtype: int64
0    NaN
1    1.0
2    1.0
3   -2.0
4    3.0
5    1.0
6    1.0
7   -5.0
dtype: float64





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分位数?要求显示在同一张表上。
def R1(x):
    return np.percentile(x,25)
def R2(x):
    return np.percentile(x,75)
print(grouped_single['Math'].agg(percentile_25=pd.NamedAgg(column='col1',aggfunc=R1),
         percentile_75=pd.NamedAgg(column='col2', aggfunc=R2)))

        percentile_25  percentile_75
School                              
S_1             41.85         85.000
S_2             47.50         72.225
【问题五】 idxmax和nunique是什么函数,它具有哪些功能和应用?
获取最大值的索引,返回的是唯一值的个数

2. 练习

【练习一】: 现有一份关于diamonds的数据集,列分别记录了克拉数、颜色、开采深度、价格,请解决下列问题:
df=pd.read_csv('data/Diamonds.csv')
pd.read_csv('data/Diamonds.csv').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完成)
dd=df.loc[df['carat']>1]
dd['price'].max()-dd['price'].min()

17561
display(df.head())

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

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

df['均重价格']=df['price']/df['carat']
color_result['top'] == [i[1] for i in df.groupby(['cuts' ,'color'])['均重价格'].mean().groupby(['cuts']).idxmax().values]
caratcolordepthpricecuts均重价格
00.23E61.5326(60.8, 61.6]1417.391304
10.21E59.8326(43.0, 60.8]1552.380952
20.23E56.9327(43.0, 60.8]1421.739130
30.29I62.4334(62.1, 62.7]1151.724138
40.31J63.3335(62.7, 79.0]1080.645161
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
cuts
(43.0, 60.8]    False
(60.8, 61.6]    False
(61.6, 62.1]    False
(62.1, 62.7]     True
(62.7, 79.0]     True
Name: top, dtype: bool
df = df.drop(columns='均重价格')
cuts = pd.cut(df['carat'],bins=[0,0.5,1,1.5,2,np.inf]) #可选label添加自定义标签
df['cuts'] = cuts

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
【练习二】:有一份关于美国10年至17年的非法药物数据集,列分别记录了年份、州(5个)、县、药物类型、报告数量,请解决下列问题:
df=pd.read_csv('data/Drugs.csv')
pd.read_csv('data/Drugs.csv').head()
YYYYStateCOUNTYSubstanceNameDrugReports
02010VAACCOMACKPropoxyphene1
12010OHADAMSMorphine9
22010PAADAMSMethadone2
32010VAALEXANDRIA CITYHeroin5
42010PAALLEGHENYHydromorphone5
(a) 按照年份统计,哪个县的报告数量最多?这个县所属的州在当年也是报告数最多的吗?
(b) 从14年到15年,Heroin的数量增加最多的是哪一个州?它在这个州是所有药物中增幅最大的吗?若不是,请找出符合该条件的药物。
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()
display((df_add.loc[2015]-df_add.loc[2014]).idxmax() ) 

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())
df_b.head()
DrugReports    OH
dtype: object



DrugReports    Heroin
dtype: object



DrugReports    Acetyl fentanyl
dtype: object
YYYYStateCOUNTYSubstanceNameDrugReports
108432014OHADAMSBuprenorphine17
108442014OHADAMSHeroin93
108512014OHALLENFentanyl4
108522014OHALLENHydrocodone40
109302014OHADAMSMorphine2
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值