pandas之数据合并(索引上的合并、轴向连接、合并重叠数据等)

合并数据集

pandas对象中得数据可以通过一些内置的方式进行合并:
——pandas.merge可根据一个或多个键将不同DataFrame中的连接起来。SQL或其他关系型数据库的用户对此应该会比较熟悉,因为它实现的就是数据库的连接操作。

——pandas.concat可以沿着一条将多个对象堆叠到一起。

——combine_first可以将重复数据编接在一起,用一个对象中的值填充另一个对象中的缺失值。

1、数据库风格的DataFrame合并

(1)数据集的合并(merge)或连接(join)运算是通过一个或多个键将行链接起来的。

df1 = DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)})
df2 = DataFrame({'key':['a','b','d'],'data2':range(3)})
df1
Out[3]: 
  key  data1
0   b      0
1   b      1
2   a      2
3   c      3
4   a      4
5   a      5
6   b      6

df2
Out[4]: 
  key  data2
0   a      0
1   b      1
2   d      2

(2)这是一种多对一的合并。

df1中的数据有多个被标记为a和b的行,而df2中key列的每个值则仅对应一行。对这些对象调用merge即可得到:

pd.merge(df1,df2)    #没有指明用哪个列连接时,merge就会被重叠列的列名当做键。
Out[6]: 
  key  data1  data2
0   b      0      1
1   b      1      1
2   b      6      1
3   a      2      0
4   a      4      0
5   a      5      0

pd.merge(df1,df2,on='key')   #最好显式指定一下
Out[7]: 
  key  data1  data2
0   b      0      1
1   b      1      1
2   b      6      1
3   a      2      0
4   a      4      0
5   a      5      0

(3)如果两个对象的列名不同,也可以分别进行指定:

df3 = DataFrame({'1key':['b','b','a','c','a','a','b'],'data1':range(7)})
df4 = DataFrame({'rkey':['a','b','d'],'data2':range(3)})
pd.merge(df3,df4,left_on='1key',right_on='rkey')
Out[11]: 
  1key  data1 rkey  data2
0    b      0    b      1
1    b      1    b      1
2    b      6    b      1
3    a      2    a      0
4    a      4    a      0
5    a      5    a      0

(4)默认情况下,merge做的是inner连接,结果中的键是交集。其他方式还有“left”、“right”、“outer”,外连接是并集,组合了左连接和右连接的效果。多对多的合并操作非常简单,无需额外的工作。

df1 = DataFrame({'key':['b','b','a','c','a','b'],'data1':range(6)})
df2 = DataFrame({'key':['a','b','a','b','d'],'data2':range(5)})
df1
Out[13]: 
  key  data1
0   b      0
1   b      1
2   a      2
3   c      3
4   a      4
5   b      5

df2
Out[14]: 
  key  data2
0   a      0
1   b      1
2   a      2
3   b      3
4   d      4

pd.merge(df1,df2,on='key',how='left')
Out[15]: 
   key  data1  data2
0    b      0    1.0
1    b      0    3.0
2    b      1    1.0
3    b      1    3.0
4    a      2    0.0
5    a      2    2.0
6    c      3    NaN
7    a      4    0.0
8    a      4    2.0
9    b      5    1.0
10   b      5    3.0

(5)多对多连接产生的是行的笛卡尔积。由于左边的DataFrame有3个“b”行,右边的有2个,所以最终结果中有6个“b”行。

left = DataFrame({'key1':['foo','foo','bar'],'key2':['one','two','one'],'lval':[1,2,3]})
right = DataFrame({'key1':['foo','foo','bar','bar'],'key2':['one','one','one','two'],'rval':[4,5,6,7]})
left
Out[18]: 
  key1 key2  lval
0  foo  one     1
1  foo  two     2
2  bar  one     3

right
Out[19]: 
  key1 key2  rval
0  foo  one     4
1  foo  one     5
2  bar  one     6
3  bar  two     7

pd.merge(left,right,on=['key1','key2'],how='outer')   #可以这样理解,多个键形成一系列元组,并将其当做单个连接键
Out[20]: 
  key1 key2  lval  rval
0  foo  one   1.0   4.0
1  foo  one   1.0   5.0
2  foo  two   2.0   NaN
3  bar  one   3.0   6.0
4  bar  two   NaN   7.0

(6)对重复列名的处理

merge的suffixes选项,用于指定附加到左右两个DataFrame对象的重叠列名上的字符串:

pd.merge(left,right,on='key1')
Out[21]: 
  key1 key2_x  lval key2_y  rval
0  foo    one     1    one     4
1  foo    one     1    one     5
2  foo    two     2    one     4
3  foo    two     2    one     5
4  bar    one     3    one     6
5  bar    one     3    two     7

pd.merge(left,right,on='key1',suffixes=('_left','_right'))
Out[22]: 
  key1 key2_left  lval key2_right  rval
0  foo       one     1        one     4
1  foo       one     1        one     5
2  foo       two     2        one     4
3  foo       two     2        one     5
4  bar       one     3        one     6
5  bar       one     3        two     7
merge函数的参数
left 参与合并的左侧DataFrame
right 参与合并的右侧DataFrame
how inner、outer、left、right其中一个。默认为inner
on 用于连接的列名。必须存在于左右两个DataFrame对象中。如果未指定,且其他连接键也未指定,则以left和right列名的交集作为连接键
left_on 左侧DataFrame中用作连接键的列
right_on 右侧DataFrame中用作连接键的列
left_index 将左侧的行索引用作其连接键
right_index 类似于left_index
sort 根据连接键对合并后的数据进行排序,默认为True。有时在处理大数据集时,禁用该选项可获得更好的性能。
suffixes 字符串值元组,用于追加到重叠列名的末尾,默认为('_x','_y')。例如,如果左右两个DataFrame对象都有“data”,则结果中就会出现“data_x”和“data_y”
copy 设置为False,可以在某些特殊情况下避免将数据复制到结果数据结构中。默认总是复制。

2、索引上的合并

(1)有时,DataFrame中的连接键位于其索引中,这时我们可以传入left_index=Trueright_index=True以说明索引应该被用作连接键

left1 = DataFrame({'key':['a','b','a','a','b','c'],'value':range(6)})
right1 = DataFrame({'group_val':[3.5,7]},index=['a','b'])
left1
Out[24]: 
  key  value
0   a      0
1   b      1
2   a      2
3   a      3
4   b      4
5   c      5

right1
Out[25]: 
   group_val
a        3.5
b        7.0

pd.merge(left1,right1,left_on='key',right_index=True)
Out[26]: 
  key  value  group_val
0   a      0        3.5
2   a      2        3.5
3   a      3        3.5
1   b      1        7.0
4   b      4        7.0

(2)由于默认的merge方法是求取连接键的交集,可通过外连接的方式得到它们的并集。对于层次化索引的数据,事情就有点复杂了

lefth = DataFrame({'key1':['O','O','O','N','N'],'key2':[2000,2001,2002,2001,2002],'data':np.arange(5.)})
righth = DataFrame(np.arange(12).reshape((6,2)),index=[['N','N','O','O','O','O'],[2001,2000,2000,2000,2001,2002]],columns=['e1','e2'])
lefth
Out[28]: 
  key1  key2  data
0    O  2000   0.0
1    O  2001   1.0
2    O  2002   2.0
3    N  2001   3.0
4    N  2002   4.0

righth
Out[29]: 
        e1  e2
N 2001   0   1
  2000   2   3
O 2000   4   5
  2000   6   7
  2001   8   9
  2002  10  11

这种情况下,必须以列表形式指明用作合并键的多个列。

pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True)
Out[3]: 
  key1  key2  data  e1  e2
0    O  2000   0.0   4   5
0    O  2000   0.0   6   7
1    O  2001   1.0   8   9
2    O  2002   2.0  10  11
3    N  2001   3.0   0   1
pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True,how='outer')
Out[4]: 
  key1  key2  data    e1    e2
0    O  2000   0.0   4.0   5.0
0    O  2000   0.0   6.0   7.0
1    O  2001   1.0   8.0   9.0
2    O  2002   2.0  10.0  11.0
3    N  2001   3.0   0.0   1.0
4    N  2002   4.0   NaN   NaN
4    N  2000   NaN   2.0   3.0

同时使用合并双方的索引也没问题。

left2 = DataFrame([[1.,2.],[3.,4.],[5.,6.]],index=['a','c','e'],columns=['O','N'])
right2 = DataFrame([[7.,8.],[9.,10.],[11.,12.],[13,14]],index=['b','c','d','e'],columns=['M','A'])
left2
Out[6]: 
     O    N
a  1.0  2.0
c  3.0  4.0
e  5.0  6.0
right2
Out[7]: 
      M     A
b   7.0   8.0
c   9.0  10.0
d  11.0  12.0
e  13.0  14.0
pd.merge(left2,right2,how='outer',left_index=True,right_index=True)
Out[8]: 
     O    N     M     A
a  1.0  2.0   NaN   NaN
b  NaN  NaN   7.0   8.0
c  3.0  4.0   9.0  10.0
d  NaN  NaN  11.0  12.0
e  5.0  6.0  13.0  14.0

(3)join

①实现按索引合并。②用于合并多个带有相同或相似索引的DataFrame对象,而不管他们之间有没有重叠的列。

left2.join(right2,how='outer')   
Out[9]: 
     O    N     M     A
a  1.0  2.0   NaN   NaN
b  NaN  NaN   7.0   8.0
c  3.0  4.0   9.0  10.0
d  NaN  NaN  11.0  12.0
e  5.0  6.0  13.0  14.0

DataFrame的join方法是在连接键上做左连接。

③它还支持参数DataFrame的索引跟调用者DataFrame的某个列之间的连接:

left1.join(right1,on='key')
Out[14]: 
  key  value  group_val
0   a      0        3.5
1   b      1        7.0
2   a      2        3.5
3   a      3        3.5
4   b      4        7.0
5   c      5        NaN

④对于简单的索引合并,还可以向join传入一组DataFrame。

another = DataFrame([[7.,8.],[9.,10.],[11.,12.],[16.,17.]],index=['a','c','e','f'],columns=['N','O'])
left2.join([right2,another],how='outer')

3、轴向连接

(1)另一种数据合并运算也被称为连接(concatenation)、绑定(binding)、堆叠(stacking)。NumPy有一个用于合并原始NumPy数组的Concatenation函数:

arr = np.arange(12).reshape((3,4))
arr
Out[19]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

np.concatenate([arr,arr],axis=1)
Out[20]: 
array([[ 0,  1,  2,  3,  0,  1,  2,  3],
       [ 4,  5,  6,  7,  4,  5,  6,  7],
       [ 8,  9, 10, 11,  8,  9, 10, 11]])

(2)pandas的concat

s1 = Series([0,1],index=['a','b'])
s2 = Series([2,3,4],index=['c','d','e'])
s3 = Series([5,6],index=['f','g'])

①默认情况下,concat是在axis=0上工作的,最终产生一个新的Series。如果传入axis=1,会变成一个DataFrame(axis=1):

pd.concat([s1,s2,s3])
Out[23]: 
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64

pd.concat([s1,s2,s3],axis=1)
Out[24]: 
     0    1    2
a  0.0  NaN  NaN
b  1.0  NaN  NaN
c  NaN  2.0  NaN
d  NaN  3.0  NaN
e  NaN  4.0  NaN
f  NaN  NaN  5.0
g  NaN  NaN  6.0

②传入join='inner'得到它们的交集

s4 = pd.concat([s1*5,s3])
s4
Out[27]: 
a    0
b    5
f    5
g    6
dtype: int64

pd.concat([s1,s4],axis=1)
Out[26]: 
     0  1
a  0.0  0
b  1.0  5
f  NaN  5
g  NaN  6
pd.concat([s1,s4],axis=1,join='inner')
Out[28]: 
   0  1
a  0  0
b  1  5

③join_axes指定要在其他轴上使用的索引

pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']])
Out[29]: 
     0    1
a  0.0  0.0
c  NaN  NaN
b  1.0  5.0
e  NaN  NaN

④在连接轴创建一个层次化索引

参与连接的片段在结果中区分不开,可使用keys参数进行连接轴上的层次化索引

result = pd.concat([s1,s2,s3],keys=['one','two','three'])
result
Out[31]: 
one    a    0
       b    1
two    c    2
       d    3
       e    4
three  f    5
       g    6
dtype: int64

result.unstack()
Out[32]: 
         a    b    c    d    e    f    g
one    0.0  1.0  NaN  NaN  NaN  NaN  NaN
two    NaN  NaN  2.0  3.0  4.0  NaN  NaN
three  NaN  NaN  NaN  NaN  NaN  5.0  6.0

pd.concat([s1,s2,s3],axis=1,keys=['one','two','three'])  #沿着axis=1对Series进行合并,则keys就会成为DataFrame的列头
Out[37]: 
   one  two  three
a  0.0  NaN    NaN
b  1.0  NaN    NaN
c  NaN  2.0    NaN
d  NaN  3.0    NaN
e  NaN  4.0    NaN
f  NaN  NaN    5.0
g  NaN  NaN    6.0

同样的逻辑对DataFrame对象也是一样。

⑤如果传入的不是列表而是一个字典,则字典的就会被当做keys选项的值:

pd.concat({'level1':df1,'level2':df2},axis=1)
Out[41]: 
  level1     level2     
     one two  three four
a      0   1    5.0  6.0
b      2   3    NaN  NaN
c      4   5    7.0  8.0

⑥用于管理层次化索引创建方式的参数names

pd.concat([df1,df2],axis=1,keys=['level1','level2'],names=['upper','lower'])
Out[43]: 
upper level1     level2     
lower    one two  three four
a          0   1    5.0  6.0
b          2   3    NaN  NaN
c          4   5    7.0  8.0

⑦去除无意义的行索引,重新索引

df1 = DataFrame(np.random.randn(3,4),columns=['a','b','c','d'])
df2 = DataFrame(np.random.randn(2,3),columns=['b','d','a'])
df1
Out[46]: 
          a         b         c         d
0  0.178245  1.452040  2.204483 -0.468347
1 -0.644702 -0.003995  0.102923 -1.867448
2 -0.715122 -1.139546  0.493268 -0.148000

df2
Out[47]: 
          b         d         a
0 -0.293157 -0.195911 -0.478124
1  1.614451  0.498994  0.246414

pd.concat([df1,df2])
Out[48]: 
          a         b         c         d
0  0.178245  1.452040  2.204483 -0.468347
1 -0.644702 -0.003995  0.102923 -1.867448
2 -0.715122 -1.139546  0.493268 -0.148000
0 -0.478124 -0.293157       NaN -0.195911
1  0.246414  1.614451       NaN  0.498994

pd.concat([df1,df2],ignore_index=True)
Out[49]: 
          a         b         c         d
0  0.178245  1.452040  2.204483 -0.468347
1 -0.644702 -0.003995  0.102923 -1.867448
2 -0.715122 -1.139546  0.493268 -0.148000
3 -0.478124 -0.293157       NaN -0.195911
4  0.246414  1.614451       NaN  0.498994
concat函数的参数
objs 参与连接的pandas对象的列表或字典。唯一必需的参数
axis 指明连接的轴向,默认为0
join “inner”、“outer”其中之一,默认为“outer”。指明其他轴向上的索引是按交集(inner)还是并集(outer)进行合并
join_axes 指明用于其他n-1条轴的索引,不执行并集
keys 与连接对象有关的值,用于形成连接轴向上的层次化索引。可以是任意值的列表或数组、元组数组、数组列表(如果将levels设置成多级数组的话)
levels 指定用作层次化索引各级别上的索引,如果设置了keys的话(就是外层级别的索引)
names 用于创建分层级别的名称,如果设置了keys和(或)levels的话
verify_integrity 检查结果对象新轴上的重复情况,如果发现则引发异常。默认(False)允许重复
ignore_index 不保留连接轴上的索引,产生一组新索引range(total_length)

4、合并重叠数据

有时可能有索引全部或部分重叠的两个数据集,我们使用NumPy的where函数,用于表达一种矢量化的if-else:
 

a = Series([np.nan,2.5,np.nan,3.5,4.5,np.nan],index=['f','e','d','c','b','a'])
b = Series(np.arange(len(a),dtype=np.float64),index=['f','e','d','c','b','a'])
b[-1] = np.nan
a
Out[51]: 
f    NaN
e    2.5
d    NaN
c    3.5
b    4.5
a    NaN
dtype: float64

b
Out[52]: 
f    0.0
e    1.0
d    2.0
c    3.0
b    4.0
a    NaN
dtype: float64

np.where(pd.isnull(a),b,a)
Out[53]: array([0. , 2.5, 2. , 3.5, 4.5, nan])

Series有一个combine_first方法,实现的是一样的功能,而且会进行数据对齐:

b[:-2].combine_first(a[2:])
Out[54]: 
a    NaN
b    4.5
c    3.0
d    2.0
e    1.0
f    0.0
dtype: float64

对于DataFrame,combine_first会在列上做同样的事情,即用参数对象中的数据为调用者对象的缺失数据“打补丁”。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(pandas之数据合并(索引上的合并、轴向连接、合并重叠数据等))