写点什么

Pandas 高级教程之:Dataframe 的合并

发布于: 2021 年 06 月 14 日

简介

Pandas 提供了很多合并 Series 和 Dataframe 的强大的功能,通过这些功能可以方便的进行数据分析。本文将会详细讲解如何使用 Pandas 来合并 Series 和 Dataframe。

使用 concat

concat 是最常用的合并 DF 的方法,先看下 concat 的定义:

pd.concat(objs, axis=0, join='outer', ignore_index=False, keys=None,          levels=None, names=None, verify_integrity=False, copy=True)
复制代码

看一下我们经常会用到的几个参数:

objs 是 Series 或者 Series 的序列或者映射。

axis 指定连接的轴。

join : {‘inner’, ‘outer’}, 连接方式,怎么处理其他轴的 index,outer 表示合并,inner 表示交集。

ignore_index: 忽略原本的 index 值,使用 0,1,… n-1 来代替。

copy:是否进行拷贝。

keys:指定最外层的多层次结构的 index。

我们先定义几个 DF,然后看一下怎么使用 concat 把这几个 DF 连接起来:

In [1]: df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],   ...:                     'B': ['B0', 'B1', 'B2', 'B3'],   ...:                     'C': ['C0', 'C1', 'C2', 'C3'],   ...:                     'D': ['D0', 'D1', 'D2', 'D3']},   ...:                    index=[0, 1, 2, 3])   ...: 
In [2]: df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], ...: 'B': ['B4', 'B5', 'B6', 'B7'], ...: 'C': ['C4', 'C5', 'C6', 'C7'], ...: 'D': ['D4', 'D5', 'D6', 'D7']}, ...: index=[4, 5, 6, 7]) ...:
In [3]: df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'], ...: 'B': ['B8', 'B9', 'B10', 'B11'], ...: 'C': ['C8', 'C9', 'C10', 'C11'], ...: 'D': ['D8', 'D9', 'D10', 'D11']}, ...: index=[8, 9, 10, 11]) ...:
In [4]: frames = [df1, df2, df3]
In [5]: result = pd.concat(frames)
复制代码

df1,df2,df3 定义了同样的列名和不同的 index,然后将他们放在 frames 中构成了一个 DF 的 list,将其作为参数传入 concat 就可以进行 DF 的合并。



举个多层级的例子:

In [6]: result = pd.concat(frames, keys=['x', 'y', 'z'])
复制代码



使用 keys 可以指定 frames 中不同 frames 的 key。

使用的时候,我们可以通过选择外部的 key 来返回特定的 frame:

In [7]: result.loc['y']Out[7]:     A   B   C   D4  A4  B4  C4  D45  A5  B5  C5  D56  A6  B6  C6  D67  A7  B7  C7  D7
复制代码

上面的例子连接的轴默认是 0,也就是按行来进行连接,下面我们来看一个例子按列来进行连接,如果要按列来连接,可以指定 axis=1:

In [8]: df4 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],   ...:                     'D': ['D2', 'D3', 'D6', 'D7'],   ...:                     'F': ['F2', 'F3', 'F6', 'F7']},   ...:                    index=[2, 3, 6, 7])   ...: 
In [9]: result = pd.concat([df1, df4], axis=1, sort=False)
复制代码



默认的 join='outer',合并之后 index 不存在的地方会补全为 NaN。

下面看一个 join=’inner’的情况:

In [10]: result = pd.concat([df1, df4], axis=1, join='inner')
复制代码



join=’inner’ 只会选择 index 相同的进行展示。

如果合并之后,我们只想保存原来 frame 的 index 相关的数据,那么可以使用 reindex:

In [11]: result = pd.concat([df1, df4], axis=1).reindex(df1.index)
复制代码

或者这样:

In [12]: pd.concat([df1, df4.reindex(df1.index)], axis=1)Out[12]:     A   B   C   D    B    D    F0  A0  B0  C0  D0  NaN  NaN  NaN1  A1  B1  C1  D1  NaN  NaN  NaN2  A2  B2  C2  D2   B2   D2   F23  A3  B3  C3  D3   B3   D3   F3
复制代码

看下结果:



可以合并 DF 和 Series:

In [18]: s1 = pd.Series(['X0', 'X1', 'X2', 'X3'], name='X')
In [19]: result = pd.concat([df1, s1], axis=1)
复制代码



如果是多个 Series,使用 concat 可以指定列名:

In [23]: s3 = pd.Series([0, 1, 2, 3], name='foo')
In [24]: s4 = pd.Series([0, 1, 2, 3])
In [25]: s5 = pd.Series([0, 1, 4, 5])
复制代码


In [27]: pd.concat([s3, s4, s5], axis=1, keys=['red', 'blue', 'yellow'])Out[27]:    red  blue  yellow0    0     0       01    1     1       12    2     2       43    3     3       5
复制代码

使用 append

append 可以看做是 concat 的简化版本,它沿着axis=0 进行 concat:

In [13]: result = df1.append(df2)
复制代码



如果 append 的两个 DF 的列是不一样的会自动补全 NaN:

In [14]: result = df1.append(df4, sort=False)
复制代码



如果设置 ignore_index=True,可以忽略原来的 index,并重写分配 index:

In [17]: result = df1.append(df4, ignore_index=True, sort=False)
复制代码



向 DF append 一个 Series:

In [35]: s2 = pd.Series(['X0', 'X1', 'X2', 'X3'], index=['A', 'B', 'C', 'D'])
In [36]: result = df1.append(s2, ignore_index=True)
复制代码



使用 merge

和 DF 最类似的就是数据库的表格,可以使用 merge 来进行类似数据库操作的 DF 合并操作。

先看下 merge 的定义:

pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,         left_index=False, right_index=False, sort=True,         suffixes=('_x', '_y'), copy=True, indicator=False,         validate=None)
复制代码

Left, right 是要合并的两个 DF 或者 Series。

on 代表的是 join 的列或者 index 名。

left_on:左连接

right_on:右连接

left_index: 连接之后,选择使用左边的 index 或者 column。

right_index:连接之后,选择使用右边的 index 或者 column。

how:连接的方式,'left''right''outer''inner'. 默认 inner.

sort: 是否排序。

suffixes: 处理重复的列。

copy: 是否拷贝数据

先看一个简单 merge 的例子:

In [39]: left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],   ....:                      'A': ['A0', 'A1', 'A2', 'A3'],   ....:                      'B': ['B0', 'B1', 'B2', 'B3']})   ....: 
In [40]: right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'], ....: 'C': ['C0', 'C1', 'C2', 'C3'], ....: 'D': ['D0', 'D1', 'D2', 'D3']}) ....:
In [41]: result = pd.merge(left, right, on='key')
复制代码



上面两个 DF 通过 key 来进行连接。

再看一个多个 key 连接的例子:

In [42]: left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],   ....:                      'key2': ['K0', 'K1', 'K0', 'K1'],   ....:                      'A': ['A0', 'A1', 'A2', 'A3'],   ....:                      'B': ['B0', 'B1', 'B2', 'B3']})   ....: 
In [43]: right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'], ....: 'key2': ['K0', 'K0', 'K0', 'K0'], ....: 'C': ['C0', 'C1', 'C2', 'C3'], ....: 'D': ['D0', 'D1', 'D2', 'D3']}) ....:
In [44]: result = pd.merge(left, right, on=['key1', 'key2'])
复制代码



How 可以指定 merge 方式,和数据库一样,可以指定是内连接,外连接等:


In [45]: result = pd.merge(left, right, how='left', on=['key1', 'key2'])
复制代码



指定 indicator=True ,可以表示具体行的连接方式:

In [60]: df1 = pd.DataFrame({'col1': [0, 1], 'col_left': ['a', 'b']})
In [61]: df2 = pd.DataFrame({'col1': [1, 2, 2], 'col_right': [2, 2, 2]})
In [62]: pd.merge(df1, df2, on='col1', how='outer', indicator=True)Out[62]: col1 col_left col_right _merge0 0 a NaN left_only1 1 b 2.0 both2 2 NaN 2.0 right_only3 2 NaN 2.0 right_only
复制代码

如果传入字符串给 indicator,会重命名 indicator 这一列的名字:

In [63]: pd.merge(df1, df2, on='col1', how='outer', indicator='indicator_column')Out[63]:    col1 col_left  col_right indicator_column0     0        a        NaN        left_only1     1        b        2.0             both2     2      NaN        2.0       right_only3     2      NaN        2.0       right_only
复制代码

多个 index 进行合并:

In [112]: leftindex = pd.MultiIndex.from_tuples([('K0', 'X0'), ('K0', 'X1'),   .....:                                        ('K1', 'X2')],   .....:                                       names=['key', 'X'])   .....: 
In [113]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'], .....: 'B': ['B0', 'B1', 'B2']}, .....: index=leftindex) .....:
In [114]: rightindex = pd.MultiIndex.from_tuples([('K0', 'Y0'), ('K1', 'Y1'), .....: ('K2', 'Y2'), ('K2', 'Y3')], .....: names=['key', 'Y']) .....:
In [115]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'], .....: 'D': ['D0', 'D1', 'D2', 'D3']}, .....: index=rightindex) .....:
In [116]: result = pd.merge(left.reset_index(), right.reset_index(), .....: on=['key'], how='inner').set_index(['key', 'X', 'Y'])
复制代码



支持多个列的合并:

In [117]: left_index = pd.Index(['K0', 'K0', 'K1', 'K2'], name='key1')
In [118]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], .....: 'B': ['B0', 'B1', 'B2', 'B3'], .....: 'key2': ['K0', 'K1', 'K0', 'K1']}, .....: index=left_index) .....:
In [119]: right_index = pd.Index(['K0', 'K1', 'K2', 'K2'], name='key1')
In [120]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'], .....: 'D': ['D0', 'D1', 'D2', 'D3'], .....: 'key2': ['K0', 'K0', 'K0', 'K1']}, .....: index=right_index) .....:
In [121]: result = left.merge(right, on=['key1', 'key2'])
复制代码



使用 join

join 将两个不同 index 的 DF 合并成一个。可以看做是 merge 的简写。

In [84]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],   ....:                      'B': ['B0', 'B1', 'B2']},   ....:                     index=['K0', 'K1', 'K2'])   ....: 
In [85]: right = pd.DataFrame({'C': ['C0', 'C2', 'C3'], ....: 'D': ['D0', 'D2', 'D3']}, ....: index=['K0', 'K2', 'K3']) ....:
In [86]: result = left.join(right)
复制代码



可以指定 how 来指定连接方式:

In [87]: result = left.join(right, how='outer')
复制代码



默认 join 是按 index 来进行连接。

还可以按照列来进行连接:

In [91]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],   ....:                      'B': ['B0', 'B1', 'B2', 'B3'],   ....:                      'key': ['K0', 'K1', 'K0', 'K1']})   ....: 
In [92]: right = pd.DataFrame({'C': ['C0', 'C1'], ....: 'D': ['D0', 'D1']}, ....: index=['K0', 'K1']) ....:
In [93]: result = left.join(right, on='key')
复制代码



单个 index 和多个 index 进行 join:

In [100]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],   .....:                      'B': ['B0', 'B1', 'B2']},   .....:                      index=pd.Index(['K0', 'K1', 'K2'], name='key'))   .....: 
In [101]: index = pd.MultiIndex.from_tuples([('K0', 'Y0'), ('K1', 'Y1'), .....: ('K2', 'Y2'), ('K2', 'Y3')], .....: names=['key', 'Y']) .....:
In [102]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'], .....: 'D': ['D0', 'D1', 'D2', 'D3']}, .....: index=index) .....:
In [103]: result = left.join(right, how='inner')
复制代码



列名重复的情况:

In [122]: left = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'v': [1, 2, 3]})
In [123]: right = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'v': [4, 5, 6]})
In [124]: result = pd.merge(left, right, on='k')
复制代码



可以自定义重复列名的命名规则:

In [125]: result = pd.merge(left, right, on='k', suffixes=('_l', '_r'))
复制代码



覆盖数据

有时候我们需要使用 DF2 的数据来填充 DF1 的数据,这时候可以使用 combine_first:

In [131]: df1 = pd.DataFrame([[np.nan, 3., 5.], [-4.6, np.nan, np.nan],   .....:                    [np.nan, 7., np.nan]])   .....: 
In [132]: df2 = pd.DataFrame([[-42.6, np.nan, -8.2], [-5., 1.6, 4]], .....: index=[1, 2]) .....:
复制代码


In [133]: result = df1.combine_first(df2)
复制代码



或者使用 update:

In [134]: df1.update(df2)
复制代码

本文已收录于 http://www.flydean.com/04-python-pandas-merge/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 2021 年 06 月 14 日阅读数: 210
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
Pandas高级教程之:Dataframe的合并