数据合并

pandas包中,进行数据合并有join()merge()concat(), append()四种方法。它们的区别是:

  1. df.join() 相同行索引的数据被合并在一起,因此拼接后的行数不会增加(可能会减少)、列数增加;
  2. df.merge()通过指定的列索引进行合并,行列都有可能增加;merge也可以指定行索引进行合并;
  3. pd.concat()通过axis参数指定在水平还是垂直方向拼接;
  4. df.append()在DataFrame的末尾添加一行或多行;大致等价于pd.concat([df1,df2],axis=0,join='outer')
import numpy as np
import pandas as pd
df1 = pd.DataFrame(np.arange(1,9).reshape(2, 4),index=["A","B"],columns=list("abcd"))
df1
abcd
A1234
B5678
df2 = pd.DataFrame(np.zeros((3,3)),index=list("ABC"),columns=list("xyz"))
df2
xyz
A0.00.00.0
B0.00.00.0
C0.00.00.0

1 df.join()按相同index拼接列

  • 相同行索引的不同列被合并在一起;
  • 左拼接(how=‘left’)时,other中与DataFrame中不同的行索引会被忽略(如C行只在df2中,合并后的df1_new中没有C行);
  • 没同时在两个对象中的位置,会用NaN填充。如:左拼接(how=‘left’)时,DataFrame中有,但other中没有的行索引会保留,并用NaN填充;
  • 要合并的两个DataFrame对象默认不能有相同的列索引。若有相同列索引,需要通过lsuffix或rsuffix参数为相同列指定后缀,否则会报错。

源码:

DataFrame.join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)

参数说明
other右表, DataFrame, Series, or list of DataFrame
on关联字段, 是关联index的
how拼接方式,默认left,{‘left’, ‘right’, ‘outer’, ‘inner’}
lsuffix左表相同列索引的后缀
rsuffix右表相同列索引的后缀
sort根据连接键对合并后的数据进行排列,默认为False

1.1 how参数取值含义示意图:

how=‘inner’ 内连接:A.join(B, how=‘inner’),取同时出现在AB中的index:

how=‘outer’ 外连接:A.join(B, how=‘outer’),取AB中的index的并集:

how=‘right’ 右连接:A.join(B, how=‘right’),B中的所有index,独自出现在A中的index被忽略:

how=‘left’ 右连接:A.join(B, how=‘left’),A中所有的index,独自出现在B中的index被忽略:

1.2 有相同行索引且没有重复列索引时:


how参数默认left,代表左连接,以左边的DataFrame的index为拼接依据;

# 以左表df1的index为依据,进行左连接,右表df2的indexC被忽略;
print("df1.index:\n", df1.index)
print()
df1_new = df1.join(df2)
df1_new
df1.index:
 Index(['A', 'B'], dtype='object')
abcdxyz
A12340.00.00.0
B56780.00.00.0
# 左表df2的index为依据,进行左连接,由于右表中没有C的index,因此对应位置以NaN填充
df2.join(df1)
xyzabcd
A0.00.00.01.02.03.04.0
B0.00.00.05.06.07.08.0
C0.00.00.0NaNNaNNaNNaN

1.3 有相同行索引和列索引

df = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'],
                   'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})
df
keyA
0K0A0
1K1A1
2K2A2
3K3A3
4K4A4
5K5A5
other = pd.DataFrame({'key': ['K0', 'K1', 'K2'],
                      'B': ['B0', 'B1', 'B2']})
other
keyB
0K0B0
1K1B1
2K2B2

列索引’key’在左右表中都存在,必须指定左右表的后缀,可以2个参数一起使用,或只指定左表或右表的后缀

# 存在相同列索引时,lsuffix指定左表后缀,rsuffix指定右表后缀
df.join(other, lsuffix='_left', rsuffix='_ritht')
key_leftAkey_rithtB
0K0A0K0B0
1K1A1K1B1
2K2A2K2B2
3K3A3NaNNaN
4K4A4NaNNaN
5K5A5NaNNaN
df.join(other, lsuffix='_left')
key_leftAkeyB
0K0A0K0B0
1K1A1K1B1
2K2A2K2B2
3K3A3NaNNaN
4K4A4NaNNaN
5K5A5NaNNaN
df.join(other, rsuffix='_ritht')
keyAkey_rithtB
0K0A0K0B0
1K1A1K1B1
2K2A2K2B2
3K3A3NaNNaN
4K4A4NaNNaN
5K5A5NaNNaN

1.4 on参数指定关联字段


默认情况下,左连接(how=‘left’)时,当想拼接的两个表中,虽然行索引不同,但右表的行索引与左表中某一列的值有相同值时,可以 左表.join(右表, on='右表列索引') 来进行拼接。

other.set_index(keys=['key'])
B
key
K0B0
K1B1
K2B2
df
keyA
0K0A0
1K1A1
2K2A2
3K3A3
4K4A4
5K5A5
df.join(other.set_index(keys=['key']), on='key')
keyAB
0K0A0B0
1K1A1B1
2K2A2B2
3K3A3NaN
4K4A4NaN
5K5A5NaN

2 df.merge()按列索引拼接列

2.1 两表中有共同列索引时:

nan代替没同时出现的元素

源码:

DataFrame.merge(right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes='_x', '_y', copy=True, indicator=False, validate=None)

参数说明
right右表, DataFrame, Series, or list of DataFrame
how拼接方式,默认inner,{‘left’, ‘right’, ‘outer’, ‘inner’}
on默认None,自动根据相同列拼接。关联字段, 是关联columns的,必须同时存在于2个表中
left_on默认None,左表中用作连接键的列索引
right_on默认None,右表中用作连接键的列索引
left_index默认Flase,是否将左表中的行索引用作连接键
right_index默认Flase,是否将右表中的行索引用作连接键
sort根据连接键对合并后的数据进行排列,默认为Flase
df1
abcd
A1234
B5678
df3 = pd.DataFrame(np.zeros((3,3)),columns=list("fax"))
df3
fax
00.00.00.0
10.00.00.0
20.00.00.0
2.1.1 默认内连接 how=‘inner’
df1
abcd
A1234
B5678
# on 参数表示根据什么进行合并;
# how参数,默认值inner,表示取的是交集;
# 指定的列中必须有相同的元素,否则返回空集
df1.merge(df3, on="a")
abcdfx
df3 = pd.DataFrame(np.arange(12).reshape((3,4)),columns=list("faxy"))
df3
faxy
00123
14567
2891011
# 以a列的相同元素进行合并
df1.merge(df3, on="a")
abcdfxy
01234023
15678467
2.1.2 外连接 how=‘outer’
# outer 代表外连接,并集,所有行和列都会合并在一起,未在2个对象中同时出现的元素以NaN代替。
df1.merge(df3, on="a", how="outer")
abcdfxy
012.03.04.0023
156.07.08.0467
29NaNNaNNaN81011
2.1.3 左连接 how=‘left’
# 以df1为准进行合并,未同时出现的元素nan代替
df1.merge(df3, on="a", how="left")
abcdfxy
01234023
15678467
2.1.4 右连接 how=‘right’
# 以df3为准进行合并,未同时出现的元素nan代替
df1.merge(df3, on="a", how="right")
abcdfxy
012.03.04.0023
156.07.08.0467
29NaNNaNNaN81011

2.2 当2表中没有共同列索引:

  • t1.merge(t2, left_on="O", right_on="X")
    • 通过left_on指定t1中的按照O列进行合并
    • 通过right_on指定t2中的按照X列进行合并
    • O列和X列中必须有相同的元素,比如下例中的元素"c"
    • NAN代替没同时出现的元素
t1 = pd.DataFrame(np.ones((3, 4)), index=list("ABC"), columns=list("MNOP"))
# for循环把O列的1替换为字母
for i in t1.index:
    t1.loc[i, "O"] = i.lower()
t1
MNOP
A1.01.0a1.0
B1.01.0b1.0
C1.01.0c1.0
t2 = pd.DataFrame(np.zeros((2, 5)), index=list("AB"), columns=list("VWXYZ"))
t2.loc["A", "X"] = "c"
t2.loc["B", "X"] = "d"
t2
VWXYZ
A0.00.0c0.00.0
B0.00.0d0.00.0
2.2.1 how='inner’交集
# how默认值inner,即默认 交集
# 左表以'O'列为关联字段,右表以'X'列为关联字段,两列中值相同的只有c,因此返回结果中有一行
t1.merge(t2, left_on="O", right_on="X")   
MNOPVWXYZ
01.01.0c1.00.00.0c0.00.0
2.2.2 how='outer’并集
# 未在2表中同时出现的位置,以NaN填充
t1.merge(t2, left_on="O", right_on="X", how="outer")
MNOPVWXYZ
01.01.0a1.0NaNNaNNaNNaNNaN
11.01.0b1.0NaNNaNNaNNaNNaN
21.01.0c1.00.00.0c0.00.0
3NaNNaNNaNNaN0.00.0d0.00.0
2.2.3 how='left’左连接
t1.shape, t2.shape
((3, 4), (2, 5))
# 以左表t1为准进行拼接,NaN填充没在左表中出现的位置
# 左表有3行数据,所以拼接后的DataFrame有3行
t1.merge(t2, left_on="O", right_on="X", how="left")
MNOPVWXYZ
01.01.0a1.0NaNNaNNaNNaNNaN
11.01.0b1.0NaNNaNNaNNaNNaN
21.01.0c1.00.00.0c0.00.0
2.2.4 how='right’右连接
# 以右表t2为准进行拼接,NaN填充没在右表中出现列的位置
# 右表有2行数据,所以拼接后的DataFrame有2行
t1.merge(t2, left_on="O", right_on="X", how="right")
MNOPVWXYZ
01.01.0c1.00.00.0c0.00.0
1NaNNaNNaNNaN0.00.0d0.00.0

2.3 存在相同列,但指定以其他不同列拼接时,suffixes参数为相同列增加后缀

df1 = pd.DataFrame({'lkey': ['foo', 'bar', 'baz', 'foo'],
                    'value': [1, 2, 3, 5]})
df1
lkeyvalue
0foo1
1bar2
2baz3
3foo5
df2 = pd.DataFrame({'rkey': ['foo', 'bar', 'baz', 'foo'],
                    'value': [5, 6, 7, 8]})
df2
rkeyvalue
0foo5
1bar6
2baz7
3foo8
# 默认:on=None,how='inner'交集,此时2表将按照相同列value中的相同元素的行进行拼接
df1.merge(df2)
lkeyvaluerkey
0foo5foo
# 左表以lkey列,右表以rkey列为关联字段,这2列中相同的元素对应的行进行拼接
# suffixes参数为相同列索引名增加后缀_x,_y
df1.merge(df2, left_on='lkey', right_on='rkey')
lkeyvalue_xrkeyvalue_y
0foo1foo5
1foo1foo8
2foo5foo5
3foo5foo8
4bar2bar6
5baz3baz7

2.4 指定以相同行索引进行拼接,等价于join()方法:

df1
lkeyvalue
0foo1
1bar2
2baz3
3foo5
df2
rkeyvalue
0foo5
1bar6
2baz7
3foo8
# 指定以2个表的相同行索引进行拼接
df1.merge(df2, left_index=True, right_index=True)
lkeyvalue_xrkeyvalue_y
0foo1foo5
1bar2bar6
2baz3baz7
3foo5foo8

3 按方向拼接 pd.concat()

pandas.concat(objs: Union[Iterable[FrameOrSeries], Mapping[Label, FrameOrSeries]], axis='0', join: str = "'outer'", ignore_index: bool = 'False', keys='None', levels='None', names='None', verify_integrity: bool = 'False', sort: bool = 'False', copy: bool = 'True') → FrameOrSeriesUnion

  • 按方向拼接(pd.concat()按行或列进行合并,axis参数决定拼接方向)

  • pd.concat([data1, data2], axis=0) 默认axis=0,垂直方向拼接,默认join='outer’并集拼接;当join='inner’进行交集拼接时,对列索引取交集;

  • pd.concat([data1, data2], axis=1) 水平方向拼接,默认并集拼接;当join='inner’进行交集拼接时,对行索引取交集;

  • 并集拼接时,若列标签均不相同,则行列标签数量均会增加,未同时存在在2个表中的字段的values为NaN;

常用参数说明
objs要合并的DataFrame或Series,以列表传入。如[df1, df2]
axis拼接方向,{0/’index’, 1/’columns’},默认0,代表垂直方向拼接;1代表水平方向拼接
join拼接方式,默认outer并集,{‘outer’, ‘inner’} ,inner交集
ignore_index默认False,是否需要重置索引。
df1
lkeyvalue
0foo1
1bar2
2baz3
3foo5
df2
rkeyvalue
0foo5
1bar6
2baz7
3foo8

3.1 axis=0 垂直方向

3.1.1 join='outer’并集拼接

相同的字段的列被合并,不同的列也被保留,未同时出现在2表中的字段以空值NaN代替

# 参数默认值axis=0, join='outer', ignore_index=False
# 未在2个表中同时出现的位置也是以NaN填充
pd.concat([df1, df2])
lkeyvaluerkey
0foo1NaN
1bar2NaN
2baz3NaN
3foo5NaN
0NaN5foo
1NaN6bar
2NaN7baz
3NaN8foo
3.1.2 join='inner’交集拼接,未重置索引

垂直交集拼接时,相同列索引的字段垂直拼接,不同列索引的字段被忽略。

# axis=0, 为垂直拼接,当join='inner',对2表的列索引取交集
# ignore_index=False
pd.concat([df1, df2], join='inner')
value
01
12
23
35
05
16
27
38
3.1.3 join='inner’交集+重置索引ignore_index=True
pd.concat([df1, df2], join='inner', ignore_index=True)
value
01
12
23
35
45
56
67
78

3.2 axis=1水平方向

3.2.1 join='outer’并集拼接

水平方向并集拼接时,相同列索引被当做2个不同列保留

df1.index = [1, 2, 3, 4]
df1
lkeyvalue
1foo1
2bar2
3baz3
4foo5
df2
rkeyvalue
0foo5
1bar6
2baz7
3foo8
# 参数默认值 join='outer', ignore_index=False
# 当2个表中存在相同列索引时,均会被保留到新的DataFrame中
pd.concat([df1, df2], axis=1)
lkeyvaluerkeyvalue
0NaNNaNfoo5.0
1foo1.0bar6.0
2bar2.0baz7.0
3baz3.0foo8.0
4foo5.0NaNNaN
3.2.2 join='inner’交集拼接
# axis=1为水平方向拼接,当join='inner',对2表的行索引取交集
# 重复的列索引作为2列被保留
pd.concat([df1, df2], axis=1, join='inner')
lkeyvaluerkeyvalue
1foo1bar6
2bar2baz7
3baz3foo8

4 df.append()在DataFrame末尾添加行

  • 和pd.concat方法的区别:
    1. append只能做行的拼接
    2. append方法是外连接
  • 相同点:
    1. append可以支持多个DataFrame的拼接
    2. append大致等同于 pd.concat([df1,df2],axis=0,join='outer')

源码:
DataFrame.append(other, ignore_index=False, verify_integrity=False, sort=False)

常用参数说明
other要被拼接进去的对象
ignore_index是否需要重置索引,默认False不重置,会保留other的原索引;
verify_integrity默认False,是否在创建具有重复项的索引时引发ValueError
sort默认False,否,是否在df和other的列不对齐时,对列进行排序
df = pd.DataFrame([[1, 2], [3, 4]], index=[1, 2], columns=list('AB'))
df
AB
112
234
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
df2
AB
056
178
# 当未指定重置索引时,会保留df2的原有索引
df.append(df2)
AB
112
234
056
178
# 重置索引将会重置为从0开始的索引
df.append(df2, ignore_index=True)
AB
012
134
256
378

上一行代码,与下面pd.concat()等价

pd.concat([df, df2], axis=0, join='outer', ignore_index=True)
AB
012
134
256
378
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐