Pandas从入门到精通(6)- 连接
1. 课程内容
SQL中最常见的操作莫过于将好几张表连接(JOIN)起来查看某些字段,与之类似,Pandas具有功能全面且性能强大连接操作。而且因为我们的DataFrame中有列-columns和索引-index。在Pandas中的连接操作感觉比SQL中要丰富的多。
本期我们就来串一串这些连接方法,主要有:
- 关系型连接
- 针对列进行的merge 方法
- 针对索引的join方法
- 方向连接
- 横向或者纵向拼接-concat方法
- 其他append/assign方法
这些方法大部分的参数都类似,实际操作中最常用的是merge和concat
下面我们将主要精力放在这两个函数上
1.1 merge
merge()函数 基本语法:
pd.merge(df1, df2, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True)
其中:
- df1,df2为需要merge的两张表(DataFrame)
- on - 列(名称)连接,必须在左(df1)和右(df2)DataFrame对象中存在(找到)。
- left_on - 左侧DataFrame中的列用作键,可以是列名或长度等于DataFrame长度的数组。
- right_on - 来自右的DataFrame的列作为键,可以是列名或长度等于DataFrame长度的数组。
left_index - 如果为True,则使用左侧DataFrame中的索引(行标签)作为其连接键。 在具有MultiIndex(分层)的DataFrame的情况下,级别的数量必须与来自右DataFrame的连接键的数量相匹配。 - right_index - 与右DataFrame的left_index具有相同的用法。
- sort - 按照字典顺序通过连接键对结果DataFrame进行排序。默认为True,设置为False时,在很多情况下大大提高性能。
- how - 它是left, right, outer以及inner之中的一个,默认为内inner。 含义分别是左连接 left 、右连接 right 、内连接 inner 、外连接 outer ,它们的区别可以用如下示意图表示:
使用merge时,如果没有指定 on = 哪一列,则默认以重叠列名当做链接键, 当然也可以按照多键连接,只需要'on'参数后传入多键列表即可。
1.2 join索引连接
在上面的Merge中,主要是针对columns进行连接,如果在merge中指定on = index, 即按照索引来连接,是否可以呢?答案是可以的。但是这种情况最好直接用join来做。pandas 中利用 join 函数来处理索引连接,它的参数选择要少于 merge ,除了必须的 on 和 how 之外,可以对重复的列指定左右后缀 lsuffix 和 rsuffix 。其中, on 参数指索引名,单层索引时省略参数表示按照当前索引连接。
1.3 方向连接concat
前面介绍了关系型连接,其中最重要的参数是 on 和 how ,但有时候用户并不关心以哪一列为键来合并,只是希望把两个表或者多个表按照纵向或者横向拼接,为这种需求, pandas 中提供了 concat 函数来实现。
在 concat 中,最常用的有三个参数,它们是 axis, join, keys ,分别表示拼接方向,连接形式,以及在新表中指示来自于哪一张旧表的名字。这里需要特别注意, join 和 keys 与之前提到的 join 函数和键的概念没有任何关系。
在默认状态下的 axis=0 ,表示纵向拼接多个表,常常用于多个样本的拼接;而 axis=1 表示横向拼接多个表,常用于多个字段或特征的拼接。
1.4 其他连接操作
其他类似的连接操作还有append,combine等,比较简单,这里不在介绍
2. 作业练习题
1:美国疫情数据集
现有美国4月12日至11月16日的疫情报表,请将 New York
的 Confirmed, Deaths, Recovered, Active
合并为一张表,索引为按如下方法生成的日期字符串序列:
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']
解答:
第一步查看原始数据。原始数据存在一个文件夹中,每个文件是用日期进行命名的csv文件,选择其中一份查看
image.png
import pandas as pd
path = './us_report/'
file_name = '04-12-2020.csv'
df = pd.read_csv(path + file_name)
df.head()
image.png
第二步:需求分析
现在需要做两件事:
1) 将每份csv文件中的New York州的'Confirmed','Deaths','Recovered','Active'数据提取出来
2)将提取出来的数据合并成一个大的DataFrame, 并且以文件名中的日期作为Index
第三步:解决思路
- 从每份文档中提取信息是一个重复的操作,适合使用一个函数来完成
- 这个函数干两件事:提取文件名中的日期和New York州的数据。这个都很简单:
state = 'New York'
need_col = ['Confirmed','Deaths','Recovered','Active']
def file_process(f):
f_index = [f.split('.')[0]] # 注意index必须要是一个列表的形式
f_path = path + f
f_df = pd.read_csv(f_path)
new_df = f_df[f_df['Province_State'] == state][need_col]
new_df.index = f_index
return new_df
# 使用一个文件调试,看看是否能够正确的提取信息
file_process('05-01-2020.csv')
image.png
OK,程序可以跑
- 遍历整个文件夹,对每份文件调用相同的函数之后在合并信息,搞定!
# 读取所有样本
df1 = file_process('04-12-2020.csv')
for file in os.listdir(path)[1:]:
df1 = pd.concat([df1, file_process(file)])
df1
结果如下:
image.png
在这里,使用函数的好处是如果需求有变,例如将New York换成其他州,或者需要其他信息的时候,只要在函数外面定义相应的值即可。由于函数的主体和其他部分是解耦的,当有需求改动的时候,只需要做较小的改动即可完成!
参考:开源内容Joyful Pandas, 作者 DataWhale耿远昊
另外,更多精彩内容也可以微信搜索,并关注公众号:‘Python数据科学家之路“ ,期待您的到来和我交流