目录
Part 1前言
Part2 Pandas 数据合并函数
1 df.append() 实现数据追加
(1)向表中追加相同结构的表
(2)向表中追加不同结构的表
(3)向数据中添加一行
2 pd.concat() 实现数据连接
(1)多个相同结构数据纵向合并
(2)多个结构不同的数据纵向合并
(3)多个数据横向合并
(4)不同类型数据合并
Part3 合并文件夹中所有数据
第一步:读取文件路径
第二步:根据获取的路径读取所有数据
第三步:使用pd.concat()函数合并数据
Part4 总结
Part5 Python教程
在实际应用中,数据可能分散在不同的文件中,如下图所示。
为了处理或者分析需要把这些分散的数据合并到一个文件中或者放在一起分析,此时就需要使用函数来将它们合并在一起。除了上述情况以外,在处理一份数据时也经常需要分批分开处理,那么处理后的数据就需要拼合在一起。本期文章我们就学习如何使用 Pandas 的数据合并函数,顺便分享一个合并文件夹中多个文件的小案例。
本教程基于 pandas 1.5.3 版本书写。
本文中所有 Python 代码均在集成开发环境 Visual Studio Code (VScode) 中使用交互式开发环境 Jupyter Notebook 中编写,本文分享的代码请使用 Jupyter Notebook 打开。
点给原文链接即可查看如何获取本文所有演示代码以及演示用的数据:
Python 教学 | Pandas 数据合并(含目录文件合并案例)
数据合并即简单的拼接数据,但也主要分为两大类,三小种情况。首先是数据纵向拼接,即存两小种情况,一种是几份相同结构的数据进行合并,合并后表格结构(字段名称、数量)不变,数据量增加;另一种是几份字段不完全一样的数据进行拼接,合并后数据的字段数量和数据量都会增加。还有一类就是数据横向拼接,主要目的是扩充数据字段,但前提是纵向拼接的数据须保证统一顺序,因此这种情况并不多见。
在 Pandas 中,可以使用使用append()
函数实现纵向的数据合并,该函数基本语法和参数含义如下。
data.append(other, ignore_index=False, verify_integrity=False, sort=False)
以上就是append()
函数的用法和参数列表,代表将数据other
追加到数据data
的尾端(数据 data 是函数调用方),该函数会返回一个追加数据后的新对象,并不会直接修改合并数据中的任何一项。函数内各个参数的含义如下表所示。
参数名称 | 含义 |
---|---|
other | 必要的参数,代表要追到调用方的数据,该参数值可以是一个 DataFrame,也可以是一个含有多个 DataFrame 的列表,为后者时,表示一次性将列表中的所有 DataFrame 都追加到调用方。other 参数也可以是一个表示一行数据的 Series 或字典,此时表示向调用方的尾端追加一行数据。 |
ignore_index | 常用参数,表示是否对返回的新对象重置索引,默认为 False,即保持原数据的索引,但可能造成行索引值重复。设置为 True,表示对追加后的数据重置索引。 |
verify_integrity | 追加的所有数据中存在重复的行索引时,是否报错,默认为 False,不报错。 |
sort | 是否对追加后返回的新对象进行排序,默认值为 False,不排序。 |
从本文前言部分图中所示的文件中读取几个表格用作演示,代码如下。
## 读取三份演示数据
data_安徽 = pd.read_excel('./电子商务专题数据库企业规模(注册资金)分布情况(截止2020年04月)/安徽.xlsx')
data_北京 = pd.read_excel('./电子商务专题数据库企业规模(注册资金)分布情况(截止2020年04月)/北京.xlsx')
data_福建 = pd.read_excel('./电子商务专题数据库企业规模(注册资金)分布情况(截止2020年04月)/福建.xlsx')
# 查看安徽省样例数据
data_安徽
① 将data_北京
追到data_安徽
中,追加得到的数据使用data_沪皖
为变量名。
# 导入 warnings 过滤警告信息
import warnings
warnings.filterwarnings('ignore') # 始终忽略警告信息
# 合并(追加)数据
data_沪皖 = data_安徽.append(data_北京)
data_沪皖
注意,如上图所示,由于没有设置ignore_index=True
,所以合并后的数据索引值并没有重置,而是保留了原来的行索引,如果希望合并后的数据索引值重置为 0,1,2,3,4,5……只需设置上述参数即可,将在下文演示。
如果你使用 df.append() 函数,大概率会收到一个警告信息:FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead. 大概意思是说 df.append() 受到大家的反对,将会在未来的一个 pandas 版本中移除这个函数,可以使用 pd.concat() 函数来代替。这个警告信息从 pandas 1.3.0 版本就存在了,不过目前仍有很多人觉得这个函数好用,如果我们使用 pandas 时希望继续使用这个函数,但又不想被警告信息骚扰,可以使用 Python 的标准库 warnings 过滤警告信息,可见上述代码的前两行。
如何查看已安装的 pandas(或其他第三方库)的版本呢?可以在导入 pandas 之后使用代码
print(pd.__version__)
进行查看(极少部分库不支持),目前 pandas 的最新大版本为 2.0,次新大版本为 1.5 。
也可以一次性将多个数据追加到一个数据中,只需要将待追加的所有数据放在列表中传给other
参数即可。
② 将上文中读取的数据data_北京
和data_福建
一次性追加到data_安徽
中,追加得到的数据使用data_沪闽皖
为变量名,且重置数据索引。
# 一次性将多个数据追加到一个数据中,相当于合并多个数据
data_沪闽皖 = data_安徽.append([data_北京, data_福建], ignore_index=True)
data_沪闽皖
先读取一份与上文中数据data_安徽
结构不完全一致的表格,代码和数据如下。
## 读取与 data_安徽 结构不完全一致的数据表
data_专利 = pd.read_excel('./工业互联网全国各省市分年度专利申请、专利授权情况(2000-2020.03).xlsx')
data_专利
③ 将数据data_专利
追加到结构不完全一致的数据data_安徽
中,新生成的数据使用data_合并
作为变量名。
# 合并两份不完全一致的数据
data_合并 = data_安徽.append(data_专利)
data_合并
观察上图可知,如果两份数据的字段名称信息不完全一致,那么只有共同的字段才会合并在一起。
在上文介绍参数时提到过,df.append()
函数还可以实现向数据表中追加一行数据(只能在数据表的最末端添加数据)。例如向上文中数据data_安徽
的末端追加一行可以使用下面的代码。
## 向数据中追加一行
# 方法 1:追加 Series
data_安徽.append(pd.Series(['340000', '安徽', '1亿以上', '--'],
index=['省份代码', '省份名', '企业规模(注册资金)', '企业数量'],
name=4))
# 方法 2:追加字典
data_安徽.append({'省份代码':'340000', '省份名':'安徽',
'企业规模(注册资金)':'1亿以上', '企业数量':'--'},
ignore_index=True)
上述代码中的两种当时都可以向数据中追加一行,这种操作虽然稍麻烦些,但是当需要增加单条数据时会比较方便。需要注意的是,追加一行数据时最好主动设置参数ignore_index=True
,如果是以字典的方式追加,则必须设置参数ignore_index=True
,否则无法追加(因为字典对象作为一行数据时,没有行索引,追加后只能重置索引,否则程序会报错)。
上一节中,介绍了如何使用append()
函数实现纵向数据合并,上文提到,使用append()
函数可能会出现警告,警告中希望我们使用pandas.concat()
函数来进行数据的合并。确实,在 pandas 中,使用 concat()
函数也可以合并数据,而且更受官方的推荐,下面我们就来学习这个函数的用法。
# 只介绍常用参数,这里的 pd 是导入 pandas 时起的别名
pd.concat(objs, axis=0, ignore_index=False, join='outer')
pd.concat()
函数的作用是将参数objs
中的所有数据连接在一起,并返回连接后的数据对象,不会修改objs
中的任何数据。其中各主要参数的用法和含义如下表所示。
参数名称 | 含义 |
---|---|
objs | 必要的参数,必须是一个包含 DataFrame 或 Series 的列表(只要是可迭代对象即可),pd.concat() 函数会将列表中的对象连接合并在一起。 |
axis | 连接的轴,默认为 0 ,表示纵向连接;为 1 时表示横向连接,这是df.append() 函数所没有的功能。 |
ignore_index | 常用参数,表示是否对返回的新对象重置索引,默认为 False,即保持原数据的索引,但可能造成行索引值重复。设置为 True,表示对连接后的数据重置索引。 |
join | 合并的方式,默认值为 'outer',表示返回合并的数据并集;设置为 'inner' 时返回的合并后数据的交集。 |
与介绍df.apppend()
函数一样,这里使用上文中已经读入的几个变量data_安徽
、data_北京
、data_福建
来做演示。
④ 使用pd.concat()
函数将data_安徽``、data_北京
、data_福建
合并为一张表,合并后的新数据取变量名为concat_沪闽皖
。
# 下面代码中,含有三个数据的列表就是 objs 参数,由于是必要参数且位于首位,所以直接位置参数,省略参数名称。
# 另外,axis 参数默认值为 0 ,表示数据纵向合并,所以这里不需要在设置 axis 参数
concat_沪闽皖 = pd.concat([data_安徽, data_北京, data_福建], ignore_index=True)
concat_沪闽皖
可以发现pd.concat()
与df.append()
在用法上的一大区别就是append()
的调用方是数据,是将参数other
指向的数据追加到调用方中,而concat()
的调用方是pandas,作用是将参数objs
指向的数据合并在一起。
⑤ 使用pd.concat()
函数纵向合并data_安徽
和data_专利
。
concat_合并 = pd.concat([data_安徽, data_专利])
concat_合并
这里的结果与上文中使用df.append()
得到的结果完全一致,不过pd.concat()
函数中还有一个能够控制合并方式的参数join
,默认值是'outer'
,表示取合并后数据的并集,下面我们尝试合并数据并取交集。
concat_合并_inner = pd.concat([data_安徽, data_专利], join='inner')
concat_合并_inner
取交集后,只有参与合并的多份数据中的共有信息才会被保留。如果数据之间的连接方式是横向连接(即参数axis=1
),那么这种情况下将会保留数据中共有的数据行,而不再是数据列。
数据纵向合并的实际使用场景极其少,因为其功能实用性不强,且容易受到数据量的影响,下面我们演示横向拼接两份数据。
⑥ 使用pd.concat()
函数横向合并data_安徽
和data_北京
。
## 横向合并需要设置参数 axis=1
concat_横向合并 = pd.concat([data_安徽, data_北京], axis=1)
concat_横向合并
横向合并的作用是根据参与合并数据的行索引进行连接的,由于上述两份参与横向合并的数据的行索引都是0、1、2、3,所以合并时就像机械式的拼接在了一起。下面我们在合并过程中修改数据data_北京
的行索引值为 2、3、4、5,看一下会发生什么。
concat_横向合并 = pd.concat([data_安徽, data_北京.reindex([2,3,4,5])], axis=1)
concat_横向合并
可以看到,使用reindex()
函数修改行索引后,合并的结果中只有行索引值为 3、4 的数据才是完整的,其他数据行的值都是根据行索引进行调整的。
最后,在介绍pd.concat()
函数的参数objs
时提到objs
中参与合并的数据还可以是 Series,但是根据笔者实测,pd.concat()
函数并不支持 DataFrame 与 Series 类型的纵向拼接,即 Series 只能作为一列添加到 DataFrame 中,示例代码如下。
# 不再将结果赋值给变量,将直接返回合并结果
pd.concat([data_安徽, pd.Series(['--', '--', '--', '--'], name='其中上市公司数量')], axis=1)
上文我们已经介绍了 Pandas 中合并数据的操作方法,这一节我们介绍如何使用上述方法批量合并一个文件夹中的多个数据,当然,前提是这些数据的结构都是一样的,只是拆分保存而已。
首先我们应该清楚为什么要把一整份数据拆开保存,笔者认为有两大原因,一是为了方便查看、使用、传输数据,故而将数据按特点分开保存,比如分地区或分年份保存成多个文件;二是因为数据量太大,不得已才分批处理,所以保存时也按照特定数据量分批保存了。如果拆开保存数据的原因只是前者,那么可以使用 Pandas 直接进行合并数据,如果是后者,则需要考虑合并后的数据大小是否超过计算机的内存大小。这里的内存指的是运行内存,一般 8GB、16GB 居多,且还要考虑其他应用占用内存,以及硬盘空间与内存空间不对等的问题。文本演示的分地区数据是小数据集,所以不必考虑内存问题。
在介绍 Python 常用标准库 时,曾学习过使用glob
库快速获取多个文件的路径,下面我们先获取文件夹中所有文件的路径,存放在一个列表中。
## 使用 glob 获取文件夹内所有 excel 表的文件路径,这里得到的是相对路径
import glob
Excelfile_paths = glob.glob('./电子商务专题数据库企业规模(注册资金)分布情况(截止2020年04月)/*.xlsx')
# 输出符合要求的路径的个数
print(len(Excelfile_paths)) # 输出:31
Excelfile_paths
使用 Python 读取文件路径时,不要使用 office 软件打开要读取的文件,因为 Excel 等软件打开表格时,会在文件的同文件夹生成一个临时文件,这个临时文件在文件夹中不可见,但是却会被 Python 读取到。由于生成的临时文件中不含数据,所以会对处理造成影响。临时文件的文件名一般以符号
~$
开头,请注意识别。
循环上一步得到的路径列表,读取表格为 DataFrame,然后将所有的 DataFrame 存入一个列表中。
ALL_datas = [] # 先创建一个用于存放读取结果的空列表
for filepath in Excelfile_paths: # 循环路径列表
data = pd.read_excel(filepath) # 根据循环的路径读取文件
ALL_datas.append(data) # 读取的结果添加到列表中
这是常规的写法,比较容易理解,不过代码也比较繁琐。其实我们还可以使用列表推导式
来完成这个操作,只需要一行代码即可。
# 使用列表推导式,过程和作用完全等价于上面的代码
ALL_datas = [pd.read_excel(filepath) for filepath in Excelfile_paths]
pd.concat()
函数合并数据## 合并所有数据
data_ALL = pd.concat(ALL_datas)
data_ALL
合并完成之后,我们就可以对数据进行筛选、分析、写入等其他操作了。
df.append()
函数和pd.concat()
函数都可以实现数据的拼接合并,但是前者只能纵向追加,功能比较单一,但是用法比较简单,可惜的是 Pandas 官方最终可能还是会抛弃这个函数;而后者的功能则更加系统和完整,但是当合并的数据格式不统一时,会出现较多很难理解的现象。无论使用哪种方式,数据合并都是 Pandas 中很基础和重要的功能,需要熟练掌握。下期文章我们将学习如何使用 Pandas 做数据匹配。
向下活动查看更多
Python教学 | 学习 Python 第一步——环境安装与配置
Python教学 | Python 基本数据类型
Python教学 | Python 字符串操作(上)
Python教学 | Python 字符串操作(下)
Python教学 | Python 变量与基本运算
Python教学 | 组合数据类型-列表
Python教学 | 组合数据类型-集合(内含实例)
Python教学 | 组合数据类型 - 字典&元组
Python教学 | Python 中的分支结构(判断语句)
Python教学 | Python 中的循环结构(上)
Python教学 | Python 中的循环结构(下)
Python教学 | Python函数的定义与调用
Python教学 | Python 内置函数
Python教学 | 最常用的标准库之一 —— os
Python教学 | 盘点 Python 数据处理常用标准库
Python 教学 | “小白”友好型正则表达式教学(一)
Python 教学 | “小白”友好型正则表达式教学(二)
Python 教学 | “小白”友好型正则表达式教学(三)
Python 教学 | 数据处理必备工具之 Pandas(基础篇)
Python 教学 | 数据处理必备工具之 Pandas(数据的读取与导出)
Python 教学 | Pandas 数据索引与数据选取
Python 教学 | Pandas 妙不可言的条件数据筛选
Python 教学 | Pandas 缺失值与重复值的处理方法
Python 教学 | Pandas 表格数据行列变换
Python 教学 | Pandas 表格字段类型精讲(含类型转换)
本期