第六章 连接

一、关系型连接

连接:

  • 左连接,右连接=>两者效果相同,只是列位置不一样
  • inner(&)outer(||,全连接)

如果出现两次,则结果为笛卡尔集,即有4个记录

类型 函数 参数 例子 备注
值连接 merge on: 连接的键;how:连接方式 df1.merge(df2, on='Name', how='left') 出现重复元素时,需要on的参数值为多个,使其结果唯一
left_on 和 right_on :指定要连接的列 df1.merge(df2, left_on='df1_name', right_on='df2_name', how='left') 想要连接的列不具备相同的列名
suffixes:指定前缀 df1.merge(df2, on='Name', how='left', suffixes=['_Chinese','_Math']) 两个表中的列出现了重复的列名
validate:检查连接的唯一性模式 df1.merge(df2, on=['Class','Name'], how='left',validate='1:m') 共有三种模式,即一对一连接 1:1 ,一对多连接 1:m ,多对一连接 m:1 连接,第一个是指左右表的键都是唯一的,后面两个分别指左表键唯一和右表键唯一
索引连接 join on: 连接的键;how:连接方式 df1.join(df2, how='left')
lsuffix;rsuffix df1.join(df2, how='left', lsuffix='_Chinese', rsuffix='_Math')

练一练

上面以多列为键的例子中,错误写法显然是一种多对多连接,而正确写法是一对一连接,请修改原表,使得以多列为键的正确写法能够通过 validate='1:m' 的检验,但不能通过 validate='m:1' 的检验。

df1 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],
                    'Age':[20, 21],
                    'Class':['one', 'two']})
df2 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],
                    'Subject':['Chinese', 'Math'],
                    'Class':['one', 'two']})
df1.merge(df2, on=['Class','Name'], how='left',validate='1:m')
'''
    Name       Age  Class   Subject
0   San Zhang   20  one     Chinese
1   San Zhang   20  one     Math
2   San Zhang   21  two     NaN
'''

二、方向连接

分类 函数 参数 例子 备注
合并两个表 concat axis:拼接方向,axis=0 ,表示纵向拼接多个表,常常用于多个样本的拼接;而 axis=1 表示横向拼接多个表,常用于多个字段或特征的拼接; pd.concat([df1, df2])
join:连接形式(inner,outer) pd.concat([df1, df2], axis=1, join='inner') 横向连接
keys:在新表中指示来自于哪一张旧表的名字 pd.concat([df1, df2], keys=['one', 'two']) 可以通过 keys 参数产生多级索引进行标记
合并序列和表 append ignore_index=True对新序列对应索引的自动标号 df1.append(s, ignore_index=True) append 中,如果原表是默认整数序列的索引,那么可以使用 ignore_index=True 对新序列对应索引的自动标号,否则必须对 Series 指定 name属性。
assign s = pd.Series([80, 90])<br />df1.assign(Grade=s) assign 返回的是一个临时副本; [xx]会在原表的基础上进行修改

三、类连接操作

函数 例子 备注
compare df1.compare(df2) 比较两个表或者序列的不同处并将其汇总展示;otherself 分别指代传入的参数表和被调用的表自身;值相同则会被填充为缺失值 NaN;想要完整显示表中所有元素的比较情况,可以设置 keep_shape=True
combine def choose_min(s1, s2):
print('s1', s1)
print('s2',s2)
s2 = s2.reindex_like(s1)
res = s1.where(s1<s2, s2)
res = res.mask(s1.isna()) # isna表示是否为缺失值,返回布尔序列
return res<br />df1.combine(df2, choose_min)
让两个表按照一定的规则进行组合,在进行比较时会自动进行列索引的对齐。传入函数的参数是来自两个表的同名Series
df1.combine(df2, choose_min, overwrite=False) overwrite=False可以保留 被调用表 中未出现在传入的参数表中的列(例子里df1的A没有出现在参数df2的表里),而不会设置未缺失值
combine_first 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)
其功能是在对两张表组合时,若第二张表中的值在第一张表中对应索引位置的值不是缺失状态,那么就使用第一张表的值填充

练一练

  1. 请在上述代码的基础上修改,保留 df2 中4个未被 df1 替换的相应位置原始值。
def choose_min(s1, s2):
    
    s2 = s2.reindex_like(s1)
    res = s1.where(s1<s2, s2) #在Python规定,np.nan与数字比较,都会返回False,也就是说它既比任何数字大,又比任何数字小。这里表示如果遇到数字,则会填充数字
    # 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   9.0
2 NaN  6.0  8.0  10.0
'''
  1. 除了 combine 之外, pandas 中还有一个 combine_first 方法,其功能是在对两张表组合时,若第二张表中的值在第一张表中对应索引位置的值不是缺失状态,那么就使用第一张表的值填充。下面给出一个例子,请用 combine 函数完成相同的功能。
def choose_first(s1, s2):
    s2 = s2.reindex_like(s1)
    res = s1.mask(s1.isna(), s2) 
    return res
df1.combine(df2, choose_first)
'''
     A    B
0  1.0  3.0
1  2.0  7.0
2  6.0  8.0
'''

四、练习

Ex1:美国疫情数据集

现有美国4月12日至11月16日的疫情报表(在 /data/us_report 文件夹下),请将 New YorkConfirmed, Deaths, Recovered, Active 合并为一张表,索引为按如下方法生成的日期字符串序列:

In [61]: date = pd.date_range('20200412', '20201116').to_series()

In [62]: date = date.dt.month.astype('string').str.zfill(2
   ....:        ) +'-'+ date.dt.day.astype('string'
   ....:        ).str.zfill(2) +'-'+ '2020'
   ....: 

In [63]: date = date.tolist()

In [64]: date[:5]
Out[64]: ['04-12-2020', '04-13-2020', '04-14-2020', '04-15-2020', '04-16-2020']

import os
fileList = os.listdir("../data/us_report")
df = pd.read_csv("../data/us_report/"+fileList[0],usecols=[0,5,6,7,8])
for i in range(1,len(fileList)):
    df = pd.concat([df, pd.read_csv("../data/us_report/"+fileList[i],usecols=[0,5,6,7,8])])
df = df.set_index(['Province_State'])
date = pd.date_range('20200412', '20201116').to_series()
date = date.dt.month.astype('string').str.zfill(2) +'-'+ date.dt.day.astype('string').str.zfill(2) +'-'+ '2020'
date = date.tolist()
df = df.loc['New York']
df['date'] = date
df.reset_index().drop(columns='Province_State').set_index('date')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容