一、关系型连接
连接:
- 左连接,右连接=>两者效果相同,只是列位置不一样
- 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) |
比较两个表或者序列的不同处并将其汇总展示;other 和 self 分别指代传入的参数表和被调用的表自身;值相同则会被填充为缺失值 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) |
其功能是在对两张表组合时,若第二张表中的值在第一张表中对应索引位置的值不是缺失状态,那么就使用第一张表的值填充。 |
练一练
- 请在上述代码的基础上修改,保留
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
'''
- 除了
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 York
的 Confirmed, 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')