【DSwithPython】DataFrame的合并、分组聚合与数据透视表
⽂章⽬录
前⾔
本节主要介绍数据处理过程中Pandas的常见模块与DataFrame的常见处理⽅法,建议参数问题可以查查在API reference中有各个功能的详细参数与具体介绍
⼀、DataFrame的合并
1.1 按列名合并 (pd.merge())
  如果需要将两个DataFrame合并,我们可以⽤pandas中的merge功能
<(df1,df2,how='inner',on=None,left_index=False,right_index=False,left_on=None,right_on=None,suffixes=('_x', '_y'))常⽤的参数:
  df1和df2是两个DataFrame,how是连接⽅式,on是按哪⼀列进⾏合并,也可以传⼊⼀个list,⽤Multi-index来合并,如果需要合并的列在两张表名字不同,可以⽤left_on和right_on参数,如果想⽤index来合
并,可以选择left_index=True或者right_index=True。如果两张表中的列名是⼀样的,新表中来⾃df1的列名会⾃动在最后添加'_x',来⾃df2的列名会⾃动在最后添加'_y',可以在suffixes中修改。
如何合并?
  假设我们有两个DataFrame,分别是学⽣students和职⼯staff,那我们有⼏种合并⽅式?
在这⾥插⼊图⽚描述
  假设我们以Students为df1,staff为df2
  (注意:此处P2包含了Student的数据和Staff的数据,直⽩来说P1+P2不等于Student)
  1.只要交集部分P2,可以⽤内连接,how='inner'
  2.要整个图形P1+P2+P3, 可以⽤外连接,how='outer'
  3.只要包含所有学⽣部分P1+P2,可以⽤左连接,how='left'
  4.只要包含所有职⼯部分P2+P3,可以⽤右连接,how='right'
  例如,在学校中有的⼈既是⽼师,有是职⼯,我们想要得到所有的⼈员名单,可以⽤outer模式来合并,空值会⽤NaN代替:
import pandas as pd
import numpy as np
staff_df=pd.DataFrame([{'Name':'Kelly','Role':'Director of HR'},
{'Name':'Mike','Role':'Course Liasion'},
{'Name':'Sally','Role':'Grader'},])
staff_df=staff_df.set_index('Name')
student_df = pd.DataFrame([{'Name':'James','School':'Business'},
{'Name':'Mike','School':'Law'},
{'Name':'Sally','School':'Engineering'}])
student_df=student_df.set_index('Name')
(staff_df,student_df,how='outer',left_index=True,right_index=True)
df1
在这⾥插⼊图⽚描述
  如果我们想要查看所有学⽣,并看看他们是否有教职,那就把student_df看作df1并⽤inner连接
(staff_df,student_df,how='inner',left_index=True,right_index=True)
df1
在这⾥插⼊图⽚描述
  如果学⽣有姓和名,可以⽤list来做on的参数连接
staff_df = pd.DataFrame([{'First Name':'Kelly','Last Name':'Desjardins',
'Role':'Director of HR'},
{'First Name':'Sally','Last Name':'Brooks',
'Role':'Course liasion'},
{'First Name':'James','Last Name':'Wilde',
'Role':'Grader'}])
student_df = pd.DataFrame([{'First Name':'James','Last Name':'Hammond',
'School':'Business'},
{'First Name':'Mike','Last Name':'Smith',
'School':'Law'},
{'First Name':'Sally','Last Name':'Brooks',
'School':'Engineering'}])
<(staff_df, student_df, how='inner', on=['First Name','Last Name'])
在这⾥插⼊图⽚描述
  如果有两列的名字是相同的,df1的列名会添加_x,df2则添加_y,当然也可以在suffixes参数中调整例如suffixes=('_a','_b')
staff_df = pd.DataFrame([{'Name':'Kelly','Role':'Director of HR',
'Location':'State Street'},
{'Name':'Sally','Role':'Course liasion',
'Location':'Washington Avenue'},
{'Name':'James','Role':'Grader',
'Location':'Washington Avenue'}])
student_df = pd.DataFrame([{'Name':'James','School':'Business',
'Location':'1024 Billiard Avenue'},
{'Name':'Mike','School':'Law',
'Location':'Fraternity House #22'},groupby是什么函数
{'Name':'Sally','School':'Engineering',
'Location':'512 Wilson Crescent'}])
<(staff_df, student_df, how='left', on='Name',suffixes=('_a','_b'))
在这⾥插⼊图⽚描述
1.2 相同列添加⾏数 (pd.concat()功能)
  例如,我们将同⼀个指标的2011年、2012年和2013年的数据合并到⼀张表中,可以⽤pd.concat()功能,如下:
frames =[df_2011, df_2012, df_2013]
at(frames)
print(len(df_2011)+len(df_2012)+len(df_2013))
df
在这⾥插⼊图⽚描述
在这⾥插⼊图⽚描述
⼆、应⽤ (.apply()功能)
  DataFrame和Series都可以应⽤.apply()功能,语法为:df.apply()Series.apply() ,在apply中的参数主要是函数,可以是def定义函数,也可以是lambda函数。为了⽤好apply()功能,需要了解以下问题:
apply()传⼊参数到底是什么?
  对于Series使⽤apply()功能是将Series中的每⼀个元素作为传⼊参数放⼊apply中的函数中,返回单值。
  ⽽对DataFrame使⽤apply()功能,是将DataFrame中的每⼀个Series作为传⼊参数放⼊apply中的函数中,返回Series。
  注意:前⾯我们讲到,DataFrame中的row和columns实际上只是名字不同⽽已,在DataFrame中的格式和地位都是⼀样的,所以DataFrame可以传⼊每⼀⾏的Series(对列进⾏apply,利⽤apply()功能中的参数axis=1)也可以传⼊每⼀列的Series(对⾏进⾏apply,利⽤axis=0,这个是默认值,即如果不加axis参数,apply()功能会将按列传⼊Series),⽤两个例⼦来说明:
import pandas as pd
import numpy as np
dic={'a':[5,6,7],'b':[6,7,8],'c':[8,9,0]}
df=pd.DataFrame(dic)
print(df)
f =lambda x: x.max()+ x.min()
def show_series(row):
print(row)
print(df.apply(f,axis=1))
print(df.apply(f,axis=0))
df.apply(show_series)
在这⾥插⼊图⽚描述
apply与dict
  我们知道python的def设计函数的时候可以设定默认参数,参数中有args=()和**kwarge,前者表⽰可以传⼊tuple,后者表⽰可以传⼊dict,那么我们在设计的时候,利⽤这⼀特性,传⼊字典,这可以帮我们进⼀步了解apply()的使⽤,例如我们要设置少数民族加分政策,汉族加0分,回族加10分,藏族加5分(不代表现实⽣活中真实数据):
data=[{'Name':'张','Nationality':'汉','Score':400},
{'Name':'李','Nationality':'回','Score':450},
{'Name':'王','Nationality':'汉','Score':460}]
df=pd.DataFrame(data)
def add_extra2(nationality,**kwargs):
return kwargs[nationality]
df['extra']=df.Nationality.apply(add_extra2,汉=0,回=10,藏=5)
df
在这⾥插⼊图⽚描述
  在这⾥,我们给a的属性是⼀个dict,对于DataFrame的Nationality列进⾏apply,传⼊的就是每⼀个Nationality的元素,查询字典kwargs中对应的值并返回⼀个单值,传给df[‘extra’]。
三、分组 (.groupby())
3.1 groupby的原理与返回值
  Pandas模块中.groupby() 功能背后的思想是,它获取⼀些DataFrame,根据⼀些键值将其拆分(split)为块,对这些块应⽤(apply)计算,然后将结果合并(combine)回另⼀个DataFrame。在pandas中,这称为“split-apply-combine”模式,其语法为:
.
groupby()返回的是⼀个tuple,其中第⼀个值是⽤于分类的key值,通常记作group,第⼆个值是当前key值所对应的DataFrame,通常记作frame。本质上.group()和迭代器计算是很像的,例如以下两段代码,所实现的功能是⼀样的,但是.groupby()在计算效率上⽐普通的迭代器要快上不少:
%%timeit -n 3
for group, frame upby('STNAME'):
avg = np.average(frame['CENSUS2010POP'])
# And print the results
print('Counties in state '+ group +
' have an average population of '+str(avg))
在这⾥插⼊图⽚描述
%%timeit -n 3
for state in df['STNAME'].unique():
avg = np.average(df.where(df['STNAME']==state).dropna()['CENSUS2010POP'])
print('Counties in state '+ state +
' have an average population of '+str(avg))
在这⾥插⼊图⽚描述
  接下来通过介绍主要分组依据⽤到的参数by,就可以对groupby()有良好的理解
在by中设定规则,你可以传⼊列名,函数,list,dict或者Series
  ⾸先,最常规的就是像上⾯的例⼦中⽤DataFrame的列名。
  第⼆是⽤函数,要注意,在调⽤函数的时候,传⼊函数中的数据是DataFrame的index,所以要确保之前已经⽤set_index()功能实现了对index的设置,例如,我们要根据美国的某个州的第⼀个字母来分组,如果第⼀个字母为[A-L]则返回0,为[M-P]返回1,其他则返回2:
df = df.set_index('STNAME')
def set_batch_number(item):
if item[0]<'M':
return0
if item[0]<'Q':
return1
return2
for group, frame upby(set_batch_number):
print('There are '+str(len(frame))+' records in group '+str(group)+' for processing.')
在这⾥插⼊图⽚描述
  第三是⽤list,这⽤于多重分类的时候,⽐如我们要按某商品的‘cancellation_policy’和‘review_scores_value’进⾏分类,可以⽤如下⽅法查看分类的依据:
ad_csv("datasets/listings.csv")
dicts=["cancellation_policy","review_scores_value"]
for group, frame upby(dicts):
print(group)
在这⾥插⼊图⽚描述
  如果DataFrame是有多重index的,我们可以直接⽤多重index进⾏分组,这时需要添加level参数,level参数⽤于确认index在groupby中的先后顺序
import pandas as pd
ad_csv("datasets/listings.csv")
df=df.set_index(["cancellation_policy","review_scores_value"])
for group, frame upby(level=(0,1)):
print(group)
在这⾥插⼊图⽚描述
  第四,⽤Series或者Dict,他和list是很像的,但这往往是对列进⾏分组,即需要添加axis=1,分组时key值是按分组分组,在分组后会将组名改为key值对应的value值
ad_csv("datasets/listings.csv")
dicts={"cancellation_policy":1,"review_scores_value":2}
for group, frame upby(dicts,axis=1):
print(group,frame)
在这⾥插⼊图⽚描述
3.2 分组后数据聚合 (.agg())
  agg的语法为:
  或者
  注:列名可以紧跟在groupby()后,也可以在agg()内⽤dict来表⽰
  在将DataFrame分组后,我们可以对分组后的值进⾏计算,主要包括以下⼏种:
函数作⽤
np.min求最⼩值
np.max求最⼤值
np.sum求和
np.std求标准差
np.var求⽅差
np.size分组⼤⼩
(当然,忽略np.,直接⽤mean或者min也是可以的,想要⽤np.nanmean或者np.nanmax也是可以的)
(注意求平均值不能⽤np.average,因为他不会忽略NaN值,所以如果数据中有NaN,那么np.average就会给你返回NaN)
  例如,我们要求某商品按’cancellation_policy’分类后,计算’review_scores_value’的平均值和⽅差,并计
算’reviews_per_month’的平均值,我们可以⽤agg函数:
'reviews_per_month':np.nanmean})
在这⾥插⼊图⽚描述
  这⾥我们就能看到多重标签了,在下⽂会介绍stack()和unstack()来展开、压缩或转换这些多重标签。
3.3 分组后数据转换 (.transform())
  我们经过对聚合函数agg的练习发现,他对分组进⾏运算后得到⼀个单⼀的值(平均数、最⼩数、中位数等等)但如果我们要将这个数应⽤到同⼀组的所有值上⾯呢?
  第⼀种⽅法是⽤map函数,是可以的,但是我们可以⼀步到位,就是第⼆种⽅法,不⽤.agg()⽽⽤.transform(),他与.agg()最⼤的区别在于:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。