目录
1 pandas.merge
1.1 merge函数的语法
1.2 单一键上合并
1.2.1 key名相同
1.2.2 两者key名不同
1.3 多个键上合并
1.4 连接键key之外,合并数据中两者存在重复列名
1.5 索引上的合并
1.5.1 使用单方DataFrame索引
1.5.2 使用双方DataFrame索引
1.6 层次化索引
2 Pandas.concat
2.1 concat()函数语法
2.2 不同轴向上合并
2.2.1 axis=0轴上合并
2.2.2 axis=1轴上合并
2.3 设置其他轴上索引
2.4 当传入对象obj为字典
2.5 管理分层索引
3 pandas.DataFrame.join
3.1 join()函数语法
3.2 两个DataFrame连接
3.3 多个DataFrame连接
4 combine_first
4.1 pandas.Series.combine_first
4.1.1 Series.combine_first 函数语法
4.1.2 Series.combine_first 实例
4.2 pandas.DataFrame.combine_first
4.2.1 DataFrame.combine_first函数语法
4.2.2 DataFrame.combine_first 实例
5 小结
在数据分析和建模的工作中,需要对数据进行规整:加载、清理、转换以及重塑等。
本文总结梳理Python标准库和Pandas用于数据集合并的两种方法:pandas.merge,pandas.concat,pandas.DataFrame.join,combine_first。
参考书籍《利用Python进行数据分析》
数据集的merge合并是通过一个或多个键key将行链接起来。
pandas.
merge
(left, 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)
主要参数:
参数 | 说明 |
left | 参与合并的左侧DataFrame |
right | 参与合并的右侧DataFrame |
how | “inner”,“outer”,“left”,“right”其中之一。默认为“inner” |
on | 用于连接的列名。必须存在于左右两个DataFrame对象中。 如果未指定,且其他连接键也未指定,则以left和right列名的交集作为连接键 |
left_on | 左侧DataFrame中用作连接键的列 |
right_on | 右侧DataFrame中用作连接键的列 |
left_index | 将左侧的行索引用作其连接键 |
right_index | 将右侧的行索引用作其连接键 |
sort | 根据连接键对合并后的数据进行排序,默认为False,按照合并的方式how进行排序。 如果为True,按照连接键名的字母顺序排序 |
suffixes | 字符串值元祖,用于追加到重叠列名的末尾,默认为('_x','_y')。 例如,如果左右两个DataFrame对象都有'data',则结果中就会出现'data_x' 和 'data_y' |
copy | 设置会False,可以在某些特殊情况下避免将数据复制到结果数据中。默认总是复制。 |
import pandas as pd
import numpy as np
df1 = pd.DataFrame({"key":["b","b","a","c","a","a","b"],"data1":range(7)})
df2 = pd.DataFrame({"key":["a","b","d"],"data2":range(3)})
pd.merge(df1,df2, on="key") # merge默认的方式是inner
df1: df2: pd.merge(df1,df2, on="key")
上述是一种多对一的合并。函数中如果没有指定on="key"也是可以的,默认选择两个dataframe中相同的key来连接。
但,建议还是要显式表达出来。
这种情况,可以用left_on 和 right_on 分别指定。
df3 = pd.DataFrame({"lkey":["b","b","a","c","a","a","b"],"data1":range(7)})
df4 = pd.DataFrame({"rkey":["a","b","d"],"data2":range(3)})
pd.merge(df3,df4,left_on="lkey",right_on="rkey")
df3: df4: merge函数作用后
默认merge连接方式为inner,即求df3和df4的交集,所以c,d对应的数据在上述结果中消失了。并集,可以设置参数how='outer'。
多个键上合并,需要设置参数on,传入一个列名组成的列表做为参数即可。
left = pd.DataFrame({"key1":['foo','foo','bar'],"key2":['one','two','one'],'lval':[1,2,3]})
right = pd.DataFrame({"key1":['foo','foo','bar','bar'],"key2":['one','one','one','two'],'rval':[4,5,6,7]})
pd.merge(left,right,on=["key1","key2"],how="outer")
left: right: merge函数作用后
如果将上述创建的left表和right表,仅按照key1进行合并,两者都存在key2这一相同的列名,如何在合并后的dataframe中加以区分呢?
merge有一个很实用的suffixes参数,默认是在重复的列名后面加上(‘_x’, ‘_y’)。
left = pd.DataFrame({"key1":['foo','foo','bar'],"key2":['one','two','one'],'lval':[1,2,3]})
right = pd.DataFrame({"key1":['foo','foo','bar','bar'],"key2":['one','one','one','two'],'rval':[4,5,6,7]})
pd.merge(left,right,on=["key1"])
left: right: merge函数作用后
如果要自己设计后缀名,可以单独设置suffixes的参数,suffixes=("_left","_right")。
left = pd.DataFrame({"key1":['foo','foo','bar'],"key2":['one','two','one'],'lval':[1,2,3]})
right = pd.DataFrame({"key1":['foo','foo','bar','bar'],"key2":['one','one','one','two'],'rval':[4,5,6,7]})
pd.merge(left,right,on='key1',suffixes=("_left","_right")) #设置自己命名的后缀
left: right: merge函数作用后
当DataFrame合并的连接键,为某一DataFrame或两者DataFrame索引index的时候,可以设置merge函数的left_index=True或者right_index=True,或两者都设置为True。设置为True的DataFrame将其索引作为连接键。
# 用left1的列名、right1的索引左右连接件键
left1 = pd.DataFrame({"key":["a","b","a","a","b","c"],"value":range(6)})
right1 = pd.DataFrame({"group_val":[3.5,7]},index=["a","b"])
pd.merge(left1,right1,left_on="key",right_index=True)
left1: right1: merge函数作用后
合并时,同时使用双方的索引也是没有问题的。
left2 = pd.DataFrame([[1,2],[3,4],[5,6]],index=['a','c','e'],columns=['Ohio','Nevada'])
right2 = pd.DataFrame([[7,8],[9,10],[11,12],[13,14]],index=['b','c','d','e'],columns=['Missouri','Alabama'])
pd.merge(left2,right2,how='outer',left_index=True,right_index=True)
left2: right2: merge函数作用后
lefth = pd.DataFrame({"key1":['Ohio','Ohio','Ohio','Nevada','Nevada'],
'key2':[2000,2001,2002,2001,2002],
'data':np.arange(5)})
righth = pd.DataFrame(np.arange(12).reshape((6,2)),
index=[['Nevada','Nevada','Ohio','Ohio','Ohio','Ohio'],
[2001,2000,2000,2000,2001,2002]],
columns=['event1','event2'])
pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True)
遇到层次化索引,看起来有点复杂,请道理是一样的。对于多个key进行合并,以列表形式指明用于合并键的多个列即可。
lefth: righth: merge函数作用后
concat()函数可以用于多个对象之间的连接。
pandas.
concat
(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=None, copy=True)
主要参数:
参数 | 说明 |
obj | 参与连接的pandas对象的列表或字典。唯一必需的参数 |
axis | 指明连接的轴向,默认为0 |
join | “inner”,“outer”其中之一,默认为“outer”。指明其他轴向上的索引是按照交集(inner)还是并集(outer)进行合并 |
join_axes | 指明用于其他n-1条轴的索引,不执行并集/交集运算 |
keys | 与连接对象有关的值,用于形成连接轴向上的层次化索引。可以是任意值的列表或数组、元祖数组、数组列表(如果将levels设置成多级数组的话) |
names | 用于创建分层级别的名称,如果设置了keys和(或)levels的话 |
verify_integrity | 检查结果对象新轴上的重复情况,如果发现则引发异常。默认(False)允许重复 |
ignore_index | 不保留连接轴上的索引,产生一组新索引range(total_length) |
s1=pd.Series([0,1],index=['a','b'])
s2=pd.Series([2,3,4],index=['c','d','e'])
s3=pd.Series([5,6],index=['f','g'])
pd.concat([s1,s2,s3]) # 默认 axis = 0
s1 s2 s3 concat函数作用后
以上调用concat函数将值和索引粘连在一起,默认在axis=0上工作,最终产生一个新的Series。
上述的s1,s2,s3如果在axis=1上合并,结果如何呢?
s1=pd.Series([0,1],index=['a','b'])
s2=pd.Series([2,3,4],index=['c','d','e'])
s3=pd.Series([5,6],index=['f','g'])
pd.concat([s1,s2,s3],axis=1)
s1 s2 s3 concat函数作用后
从上述结果可以看出,concat函数默认的是外连接方式outer。在axis=1上工作,最终产生一个新的DataFrame。
合并时,没有对应值得位置,为NaN空值。
在axis=1的条件下,通过设置join='inner'参数,可以得到交集。
我们可以通过:
设置join_axes参数,来设置合并时在其他轴上的索引。如,下方按照行索引['a','c','b','e']进行合并,当索引为'c'和'e'时,没有对应的数值,为NaN空。
设置keys参数,来设置合并轴上的索引。如,下方代码将合并后列索引设置为"set1","set2"。
s1=pd.Series([0,1],index=['a','b'])
s4=pd.concat([s1*5,s3])
pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']],keys=["set1","set2"])
s1 s4 concat函数作用后
当concat函数传入的对象obj不是列表,而是字典形式时,字典的键将会被当做keys选项的值。
如下方代码,对象为字典{'level1':df1,'level2':df2}。'level1'和'level2'被当做合并后DataFrame的列的值。
df1 = pd.DataFrame(np.arange(6).reshape(3,2),index=['a','b','c'],columns=['one','two'])
df2 = pd.DataFrame(5+np.arange(4).reshape(2,2),index=['a','c'],columns=['three','four'])
pd.concat({'level1':df1,'level2':df2},axis=1)
df1 df2 concat函数作用后
同2.5节中代码一致,我们另外加上names参数设置,可以加入层次化的索引。效果参下图,增加了层次化索引'level','ord_num'。
df1 = pd.DataFrame(np.arange(6).reshape(3,2),index=['a','b','c'],columns=['one','two'])
df2 = pd.DataFrame(5+np.arange(4).reshape(2,2),index=['a','c'],columns=['three','four'])
pd.concat({'level1':df1,'level2':df2},axis=1,names=['level','ord_num'])
df1 df2 concat函数作用后
join()函数可以方便地实现按索引合并,用于合并多个带有相同或相似索引的DataFrame对象,而不管它们之间是否有重叠的列。
DataFrame.
join
(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)
用法:将当前DataFrame同参数对象other的列连接。
我们称 .join 前面的数据框为calling frame 或者为caller。
主要参数:
参数 | 说明 |
other | 参与连接的对象,可以是DataFrame,Series,或者为DataFrame的列表。 该对象的index应该同调用函数的calling frame的index相似。 如果传入的对象是Series,那么Series的name属性必须制定,用来作为合并后数据框中对应的列名。 如果传入DataFrame的列表,即为多个DataFrame的连接 |
on | 调用join函数的对象calling frame的列或者index索引名 |
how | {‘left’, ‘right’, ‘outer’, ‘inner’},其中之一,默认为“left”。 left: 使用calling frame的索引(或者on参数上特别制定的列) right:使用参数对象other的索引 outer:使用caling frame和参数对象other的全部索引,并按照字母顺序排序 inner:使用caling frame和参数对象other的共有索引,并按照calling frame中索引顺序排列 |
lsuffix | 用于追加到重叠列名的末尾,添加在左侧calling frame的重复列名后 |
rsuffix | 用于追加到重叠列名的末尾,添加在右侧other frame的重复列名后 |
sort | 将合并后的数据框内容按照连接键的字母顺序排序。 如果sort 为False,连接键的顺序由连接方式how的类型来决定 |
left2 = pd.DataFrame([[1,2],[3,4],[5,6]],
index=['a','c','e'],
columns=['Ohio','Nevada'])
right2 = pd.DataFrame([[7,8],[9,10],[11,12],[13,14]],
index=['b','c','d','e'],
columns=['Missouri','Alabama'])
left2.join(right2) # 默认为左连接
left2 right2 join函数左右后
对于简单的索引合并,我们还可想join传入一组DataFrame。
如3.2中的连接函数中,我们在传入一个DataFrame为another,join函数的参数为一组DataFrame组成的列表。
left2 = pd.DataFrame([[1,2],[3,4],[5,6]],
index=['a','c','e'],
columns=['Ohio','Nevada'])
right2 = pd.DataFrame([[7,8],[9,10],[11,12],[13,14]],
index=['b','c','d','e'],
columns=['Missouri','Alabama'])
another = pd.DataFrame([[7,8],[9,10],[11,12],[16,17]],index=['a','c','e','f'],
columns=['New York','Oregon'])
left2.join([right2,another],how='inner')
left2 right2
another join函数作用后
这个例子多个对象直接的连接,连接方式为inner。我们同样可以用concat函数实现这个连接,结果是一样的。
left2 = pd.DataFrame([[1,2],[3,4],[5,6]],
index=['a','c','e'],
columns=['Ohio','Nevada'])
right2 = pd.DataFrame([[7,8],[9,10],[11,12],[13,14]],
index=['b','c','d','e'],
columns=['Missouri','Alabama'])
another = pd.DataFrame([[7,8],[9,10],[11,12],[16,17]],
index=['a','c','e','f'],
columns=['New York','Oregon'])
pd.concat([left2,right2,another],axis=1,join='inner')
但因为concat函数只有“inner”,“outer”两种,所以当连接方式为“left”,“right”时,concat函数就无法作用了。
对于有索引全部相同或者部分相同的两个数据集,可以使用combine_first实现数据的连接,同时可以进行数据对齐。
Series.
combine_first
(other)
我们将 .combine_first
前面的Series称为 calling Series。
参数:other为用于结合的其他Series
作用:将两个Series中的值合并,优先选择calling Series中的值;如果calling Series中出现空值,用other中对应的值填充。
最终合并后的对象索引为两者索引的汇总。
import pandas as pd
import numpy as np
a = pd.Series([np.nan,2.5,np.nan,3.5,4.5,np.nan],index=['f','e','d','c','b','a'])
b = pd.Series(np.arange(len(a)),dtype=np.float64,index=['f','e','d','c','b','a'])
b[-1]=np.nan
b[:-2].combine_first(a[2:])
我们逐项列出上述代码相关对象:
a a[2:]
b b[:-2]
b[:-2].combine_first(a[2:]) 结果为:
combine_first作用后的索引为b[:-2]和a[2:]两者索引的汇总。
b[:-2]中已有数值都非空,将保留;同时吸收其在a[2:]中没有的数据,即索引a,b对应的数据。
DataFrame.
combine_first
(other)
我们将 .combine_first
前面的Series称为 calling DataFrame 。
参数:other为用于结合的其他DataFrame
作用:将两个DataFrame 中的值合并,优先选择calling DataFrame 中的值;如果calling DataFrame 中出现空值,用other中对应的值填充。
最终合并后的对象索引为两者索引的汇总。
df1 = pd.DataFrame({'a':[1.,np.nan,5.,np.nan],
'b':[np.nan,2.,np.nan,6.],
'c':range(2,18,4)})
df2 = pd.DataFrame({'a':[5.,4.,np.nan,3.,7.],
'b':[np.nan,3.,4.,6.,8.]})
df1.combine_first(df2)
df1 df2 df1.combine_first(df2)
要特别说明的是,两个DataFrame之间的作用是按照Series-wise展开的,分别按照对应的列key值,两两进行series.combine_first操作。。
如上述df1和df2在用combine_first操作时,分别按照‘a’对应的两个series来进行结合,填充空值;
在按照‘b’对应的两个series来进行结合,填充空值;最后是‘c’对应的series。
举例:‘a’对应的两个series的结合
df1['a'] df2['a']
df1['a'] 和 df2['a'] 作用,产生合并后新的DataFrame的第一列。
pd.merge() 只能作用于两个对象之间,连接方式“inner”,“outer”,“left”,“right”其中之一。默认为“inner”。无轴向axis参数。
pd.concat()可以用于多个对象连接,连接方式为“inner”,“outer”其中之一,默认为“outer”。有轴向axis参数。
.join()可以用于多个对象连接, 连接方式为‘left’, ‘right’, ‘outer’, ‘inner’其中之一,默认为“left”。无轴向axis参数。
.combine_first() 对于有索引全部相同或者部分相同的两个数据集,实现两者数据的结合。
(不当之处,欢迎留言,互通有无~)