Pandas数据分析-Task6

Pandas数据分析-Task6

记录DataWhale的Pandas数据分析的学习过程,使用的教材为 joyful-pandas
Task6是pandas的连接相关的知识,内容基本可以分为三个部分,第一部分介绍了关系型连接,包括值连接merge()函数和索引连接join()函数;第二部分介绍了方向连接,包括拼接多个表的pd.concat()方法和拼接DataFrame和Series的appen(),assign()函数;第三部分介绍了常用的连接函数,包括比较函数compare()和组合函数combine()。 本篇文章中所有的代码示例中用到的原始文件都可以在 此链接中下载。

关系型连接

值连接-merge()

pandas中的连接和SQL中的基本概念一样,可以分为左连接left 、右连接right 、内连接inner 、外连接outer这四种模式。具体的意思也和SQL中的一致,不再赘述。pandas中使用merge函数完成连接操作,merge()函数有两个主要的参数:on参数和how参数,其中,on参数表示以某一列为键进行连接,how参数表示连接的具体模式(上面说到的四种之一)。例如:

#以姓名为键,连接两表
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'Name':['Si Li','Wu Wang'],'Gender':['F','M']})
df1.merge(df2,on='Name',how='outer')
>>>
>        Name   Age Gender
0  San Zhang  20.0    NaN
1      Si Li  30.0      F
2    Wu Wang   NaN      M

除了这种最简单的连接方式,还有一些特殊情况需要注意:
1 当要连接的列不具备相同的列名,可以通过left_on 和right_on 指定列进行连接。

#要连接的连个表的列名不通,一个为df1_name,另一个为df2_name
df1 = pd.DataFrame({'df1_name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'df2_name':['Si Li','Wu Wang'],'Gender':['F','M']})
df1.merge(df2,left_on='df1_name',right_on='df2_name',how='left')#通过left_on 和right_on 指定列连接
>>>
>    df1_name  Age df2_name Gender
0  San Zhang   20      NaN    NaN
1      Si Li   30    Si Li      F

2 除要连接的列以外,两个表中的其他列出现了重复的列名。通过suffixes 参数指定不同的名称。

#除作为键的Name列以外,两个表的Grade列的列名一样。
df1 = pd.DataFrame({'Name':['San Zhang'],'Grade':[70]})
df2 = pd.DataFrame({'Name':['San Zhang'],'Grade':[80]})
df1.merge(df2,on='Name',how='inner',suffixes=['_Chinese','_Math'])#suffixes 参数指定不同的名称。
>>>
        Name  Grade_Chinese  Grade_Math
0  San Zhang             70          80

3 键值的唯一性
作为连接条件的键可以为某一列,也可以为几列。有时键值并不是唯一的,当存在重复值时,表格所有的重复值之间都会进行笛卡尔连接,可能会得到错误的解。所以,在特殊情况下,需要保证键值的唯一性。merge 中提供了validate 参数来检查连接的唯一性模式。这里共有三种模式,即一对一连接one_to_one ,一对多连接one_to_many ,多对一连接many_to_one,多对多连接many_to_many。其中,第一个是指左右表的键都是唯一的,后面两个分别指左表键唯一和右表键唯一。

#键为多个列唯一值的例子:两位同学来自不同的班级,但是姓名相同。
df1 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],'Age':[20, 21],'Class':['one', 'two']})
df2 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],'Gender':['F', 'M'], 'Class':['two', 'one']})
df1.merge(df2,on=['Name','Class'],how='right')#同时将'Name','Class'做为键
>>>
>        Name  Age Class Gender
0  San Zhang   21   two      F
1  San Zhang   20   one      M
练一练

在这里插入图片描述
思路:validate='1:m’成立但是‘m:1’不成立,也即左表中键值必须唯一且右表中键值不唯一。

df1 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],'Age':[20, 21],'Class':['one', 'two']})#此时左表中键值已经唯一了。
df2 = pd.DataFrame({'Name':['San Zhang', 'San Zhang', 'San Zhang'],'Gender':['F', 'M','F'], 'Class':['two', 'one','one']})#增加了一个新的行,使得右表的键值不唯一。
df1.merge(df2,on=['Name','Class'],how='left',validate='1:m')
>>>
>        Name  Age Class Gender
0  San Zhang   20   one      M
1  San Zhang   20   one      F
2  San Zhang   21   two      F

df1.merge(df2,on=['Name','Class'],how='left',validate='m:1')
>>>pandas.errors.MergeError: Merge keys are not unique in right dataset; not a many-to-one merge

索引连接-join()

join()的用法和作用和merge()基本一致,唯一的区别在于jion()是将索引作为健,所以在单层索引表格中,join()的on参数可以不写,默认为索引。

df1 = pd.DataFrame({'Age':[20,30]}, index=pd.Series( ['San Zhang','Si Li'],name='Name'))
df2 = pd.DataFrame({'Gender':['F','M']},index=pd.Series( ['Si Li','Wu Wang'],name='Name'))
df1.join(df2,how='left')#单层索引连接,不用加on参数
>>>
>           Age Gender
Name                 
San Zhang   20    NaN
Si Li       30      F

与merge()类似,除了这种最简单的连接方式,还有一些特殊情况:
两个表中出现了重复的列名:与merge()函数类似,join()函数对重复的列指定左右后缀lsuffix 和rsuffix。

#两个表格列名相同,均为Grade
df1 = pd.DataFrame({'Grade':[70]},index=pd.Series(['San Zhang'], name='Name'))
df2 = pd.DataFrame({'Grade':[80]},index=pd.Series(['San Zhang'],name='Name'))
df1.join(df2,how='left',lsuffix='_math',rsuffix='phy')#lsuffix 和rsuffix对重复的列指定左右后缀.
>>>
>           Grade_math  Gradephy
Name                           
San Zhang          70        80

方向连接

表格间方向连接-concat()

concat()的作用是把两个表或者多个表按照纵向或者横向拼接,有三个参数 :axis, join, keys ,参数axis表示拼接方向,默认状态下的axis=0 ,表示纵向拼接多个表,常常用于多个样本的拼接;而axis=1 表示横向拼接多个表,常用于多个字段或特征的拼接

#默认纵向样本层面拼接
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'Name':['Wu Wang'], 'Age':[40]})
pd.concat([df1,df2])
>>>
>        Name  Age
0  San Zhang   20
1      Si Li   30
0    Wu Wang   40

#axis=1,横向特征拼接
df2 = pd.DataFrame({'Grade':[80, 90]})
df3 = pd.DataFrame({'Gender':['M', 'F']})
pd.concat([df1,df2,df3],axis=1)
>>>
>        Name  Age  Grade Gender
0  San Zhang   20     80      M
1      Si Li   30     90      F

参数join用来控制拼接后显示的内容,其默认值为join=inner 。在纵向拼接时,join=outer 表示保留所有的列,并将不存在的值设为缺失;join=inner 表示保留两个表都出现过的列。在横向拼接时,join=outer 表示保留所有的行;join=inner 表示只有两个表都出现过的行索引才保留。

df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'Grade':[80, 90]},index=[1,2])#注意这里的index
pd.concat([df1,df2],axis=1)
>>>
>        Name   Age  Grade
0  San Zhang  20.0    NaN
1      Si Li  30.0   80.0
2        NaN   NaN   90.0
pd.concat([df1,df2],axis=1,join='inner')#df1与df2共同出现的行索引只有1
>>>
>    Name  Age  Grade
1  Si Li   30     80

Series与表的连接

  • apped方法:把一个序列追加到表的行末,如果原表是默认整数序列的索引,那么可以使用ignore_index=True 对新序列对应索引的自动标号。
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]})
df2=pd.Series(['Wu Wang',40],index=['Name','Age'])
df1.append(df2,ignore_index=True)
>>>
>        Name  Age
0  San Zhang   20
1      Si Li   30
2    Wu Wang   40
  • assign方法:把一个序列追加到表的列末。

组合-combine()函数

combine 函数能够让两张表按照一定的规则进行组合,在进行规则比较时会自动进行列索引的对齐。对于传入的函数而言,每一次操作中输入的参数是来自两个表的同名Series ,依次传入的列是两个表列名的并集。

def choose_min(s1, s2): #s1代表的是df2中的列 排在前面的是被调用的列。
    res = s1.where(s1<s2, s2) #若s1>=s2,则变为s2的值
    res = res.mask(s1.isna()) # isna 表示是否为缺失值,返回布尔序列
    return res

df1 = pd.DataFrame({'A':[1,2], 'B':[3,4], 'C':[5,6]})
df2 = pd.DataFrame({'B':[5,6],'C':[7,8], 'D':[9,10]}, index=[1,2])
df1.combine(df2, choose_min)
>>>
>    A    B    C   D
0 NaN  NaN  NaN NaN
1 NaN  4.0  6.0 NaN
2 NaN  NaN  NaN NaN

练一练

在这里插入图片描述
思路:手动编写函数,使用mask方法即可。

df1 = pd.DataFrame({'A':[1,2], 'B':[3,np.nan]})
df2 = pd.DataFrame({'A':[5,6], 'B':[7,8]}, index=[1,2])
df1.combine_first(df2)
>>>
>     A    B
0  1.0  3.0
1  2.0  7.0
2  6.0  8.0

def myf(x1,x2):
    return x2.mask(x1.notnull(),x1)
df1.combine(df2,myf)
>>>
>     A    B
0  1.0  3.0
1  2.0  7.0
2  6.0  8.0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值