Python Pandas 第5章 合并

>>> import numpy as np
>>> import pandas as pd
>>> df = pd.read_csv('data/table.csv')
>>> df.head()
  School Class    ID Gender   Address  Height  Weight  Math Physics
0    S_1   C_1  1101      M  street_1     173      63  34.0      A+
1    S_1   C_1  1102      F  street_2     192      73  32.5      B+
2    S_1   C_1  1103      M  street_2     186      82  87.2      B+
3    S_1   C_1  1104      F  street_2     167      81  80.4      B-
4    S_1   C_1  1105      F  street_4     159      64  84.8      B+

一、append与assign

1. append方法

(a)利用序列添加行(必须指定name)

>>> df_append = df.loc[:3,['Gender','Height']].copy()
>>> df_append
  Gender  Height
0      M     173
1      F     192
2      M     186
3      F     167

>>> s = pd.Series({'Gender':'F','Height':188},name='new_row')
>>> df_append.append(s)
        Gender  Height
0            M     173
1            F     192
2            M     186
3            F     167
new_row      F     188

(b)用DataFrame添加表

>>> df_temp = pd.DataFrame({'Gender':['F','M'],'Height':[188,176]},index=['new_1','new_2'])
>>> df_append.append(df_temp)
      Gender  Height
0          M     173
1          F     192
2          M     186
3          F     167
new_1      F     188
new_2      M     176

2. assign方法

该方法主要用于添加列,列名直接由参数指定:

>>> s = pd.Series(list('abcd'),index=range(4))
>>> df_append.assign(Letter=s)
  Gender  Height Letter
0      M     173      a
1      F     192      b
2      M     186      c
3      F     167      d

可以一次添加多个列:

>>> df_append.assign(col1=lambda x:x['Gender']*2, col2=s)
  Gender  Height col1 col2
0      M     173   MM    a
1      F     192   FF    b
2      M     186   MM    c
3      F     167   FF    d

二、combine与update

1. comine方法

comineupdate都是用于表的填充函数,可以根据某种规则填充

(a)填充对象

可以看出combine方法是按照表的顺序轮流进行逐列循环的,而且自动索引对齐,缺失值为NaN,理解这一点很重要

>>> df_combine_1 = df.loc[:1,['Gender','Height']].copy()
>>> df_combine_2 = df.loc[10:11,['Gender','Height']].copy()
>>> df_combine_1.combine(df_combine_2,lambda x,y:print(x,y))
0       M
1       F
10    NaN
11    NaN
Name: Gender, dtype: object 0     NaN
1     NaN
10      M
11      F
Name: Gender, dtype: object
0     173.0
1     192.0
10      NaN
11      NaN
Name: Height, dtype: float64 0       NaN
1       NaN
10    161.0
11    175.0
Name: Height, dtype: float64
   Gender Height
0     NaN    NaN
1     NaN    NaN
10    NaN    NaN
11    NaN    NaN

(b)一些例子

例①:根据列均值的大小填充

# 例子1
>>> df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
>>> df2 = pd.DataFrame({'A': [8, 7], 'B': [6, 5]})
>>> df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y)
   A  B
0  8  6
1  7  5

例②:索引对齐特性(默认状态下,后面的表没有的行列都会设置为NaN)

>>> df2 = pd.DataFrame({'B': [8, 7], 'C': [6, 5]},index=[1,2])
>>> df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y)
    A    B    C
0 NaN  NaN  NaN
1 NaN  8.0  6.0
2 NaN  7.0  5.0

例③:使得df1原来符合条件的值不会被覆盖

>>> df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y,overwrite=False) 
     A    B    C
0  1.0  NaN  NaN
1  2.0  8.0  6.0
2  NaN  7.0  5.0

例④:在新增匹配df2的元素位置填充-1

>>> df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y,fill_value=-1)
     A    B    C
0  1.0 -1.0 -1.0
1  2.0  8.0  6.0
2 -1.0  7.0  5.0

(c)combine_first方法

这个方法作用是用df2填补df1的缺失值,功能比较简单,但很多时候会比combine更常用,下面举两个例子:

>>> df1 = pd.DataFrame({'A': [None, 0], 'B': [None, 4]})
>>> df2 = pd.DataFrame({'A': [1, 1], 'B': [3, 3]})
>>> df1.combine_first(df2)
     A    B
0  1.0  3.0
1  0.0  4.0

>>> df1 = pd.DataFrame({'A': [None, 0], 'B': [4, None]})
>>> df2 = pd.DataFrame({'B': [3, 3], 'C': [1, 1]}, index=[1, 2])
>>> df1.combine_first(df2)
     A    B    C
0  NaN  4.0  NaN
1  0.0  3.0  1.0
2  NaN  3.0  1.0

2. update方法

(a)三个特点

①返回的框索引只会与被调用框的一致(默认使用左连接,下一节会介绍)
②第二个框中的nan元素不会起作用
③没有返回值,直接在df上操作

(b)例子

例①:索引完全对齐情况下的操作

>>> df1 = pd.DataFrame({'A': [1, 2, 3],
                    'B': [400, 500, 600]})
>>> df2 = pd.DataFrame({'B': [4, 5, 6],
                    'C': [7, 8, 9]})
>>> df1.update(df2)
>>> df1
   A  B
0  1  4
1  2  5
2  3  6

例②:部分填充

>>> df1 = pd.DataFrame({'A': ['a', 'b', 'c'],
                    'B': ['x', 'y', 'z']})
>>> df2 = pd.DataFrame({'B': ['d', 'e']}, index=[1,2])
>>> df1.update(df2)
>>> df1
   A  B
0  a  x
1  b  d
2  c  e

例③:缺失值不会填充

>>> df1 = pd.DataFrame({'A': [1, 2, 3],
                    'B': [400, 500, 600]})
>>> df2 = pd.DataFrame({'B': [4, np.nan, 6]})
>>> df1.update(df2)
>>> df1
   A      B
0  1    4.0
1  2  500.0
2  3    6.0

三、concat方法

concat方法可以在两个维度上拼接,默认纵向凭借(axis=0),拼接方式默认外连接
所谓外连接,就是取拼接方向的并集,而'inner'时取拼接方向(若使用默认的纵向拼接,则为列的交集)的交集

下面举一些例子说明其参数:

>>> df1 = pd.DataFrame({'A': ['A0', 'A1'],
                    'B': ['B0', 'B1']},
                    index = [0,1])
>>> df2 = pd.DataFrame({'A': ['A2', 'A3'],
                    'B': ['B2', 'B3']},
                    index = [2,3])
>>> df3 = pd.DataFrame({'A': ['A1', 'A3'],
                    'D': ['D1', 'D3'],
                    'E': ['E1', 'E3']},
                    index = [1,3])

默认状态拼接:

>>> pd.concat([df1,df2])
    A   B
0  A0  B0
1  A1  B1
2  A2  B2
3  A3  B3

axis=1时沿列方向拼接:

>>> pd.concat([df1,df2],axis=1)
     A    B    A    B
0   A0   B0  NaN  NaN
1   A1   B1  NaN  NaN
2  NaN  NaN   A2   B2
3  NaN  NaN   A3   B3

join设置为内连接(由于axis=0,因此列取交集):

>>> pd.concat([df3,df1],join='inner')
    A
1  A1
3  A3
0  A0
1  A1

join设置为外链接:

>>> pd.concat([df3,df1],join='outer',sort=True) #sort设置列排序,默认为False
    A    B    D    E
1  A1  NaN   D1   E1
3  A3  NaN   D3   E3
0  A0   B0  NaN  NaN
1  A1   B1  NaN  NaN

verify_integrity检查列是否唯一:

>>> #pd.concat([df3,df1],verify_integrity=True,sort=True) 报错

同样,可以添加Series

>>> s = pd.Series(['X0', 'X1'], name='X')
>>> pd.concat([df1,s],axis=1)
    A   B   X
0  A0  B0  X0
1  A1  B1  X1

key参数用于对不同的数据框增加一个标号,便于索引:

>>> pd.concat([df1,df2], keys=['x', 'y'])
      A   B
x 0  A0  B0
  1  A1  B1
y 2  A2  B2
  3  A3  B3
>>> pd.concat([df1,df2], keys=['x', 'y']).index
MultiIndex([('x', 0),
            ('x', 1),
            ('y', 2),
            ('y', 3)],
           )

四、merge与join

1. merge函数

merge函数的作用是将两个pandas对象横向合并,遇到重复的索引项时会使用笛卡尔积,默认inner连接,可选leftouterright连接

所谓左连接,就是指以第一个表索引为基准,右边的表中如果不再左边的则不加入,如果在左边的就以笛卡尔积的方式加入

merge/joinconcat的不同之处在于on参数,可以指定某一个对象为key来进行连接

同样的,下面举一些例子:

>>> left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                     'key2': ['K0', 'K1', 'K0', 'K1'],
                      'A': ['A0', 'A1', 'A2', 'A3'],
                      'B': ['B0', 'B1', 'B2', 'B3']}) 
>>> right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                      'key2': ['K0', 'K0', 'K0', 'K0'],
                      'C': ['C0', 'C1', 'C2', 'C3'],
                      'D': ['D0', 'D1', 'D2', 'D3']})
>>> right2 = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                      'key2': ['K0', 'K0', 'K0', 'K0'],
                      'C': ['C0', 'C1', 'C2', 'C3']})

key1为准则连接,如果具有相同的列,则默认suffixes=('_x','_y')

>>> pd.merge(left, right, on='key1')
  key1 key2_x   A   B key2_y   C   D
0   K0     K0  A0  B0     K0  C0  D0
1   K0     K1  A1  B1     K0  C0  D0
2   K1     K0  A2  B2     K0  C1  D1
3   K1     K0  A2  B2     K0  C2  D2
4   K2     K1  A3  B3     K0  C3  D3

以多组键连接:

>>> pd.merge(left, right, on=['key1','key2'])
  key1 key2   A   B   C   D
0   K0   K0  A0  B0  C0  D0
1   K1   K0  A2  B2  C1  D1
2   K1   K0  A2  B2  C2  D2

默认使用inner连接,因为merge只能横向拼接,所以取行向上keys的交集,下面看如果使用how=outer参数

注意:这里的how就是concatjoin

>>> pd.merge(left, right, how='outer', on=['key1','key2'])
  key1 key2    A    B    C    D
0   K0   K0   A0   B0   C0   D0
1   K0   K1   A1   B1  NaN  NaN
2   K1   K0   A2   B2   C1   D1
3   K1   K0   A2   B2   C2   D2
4   K2   K1   A3   B3  NaN  NaN
5   K2   K0  NaN  NaN   C3   D3

左连接:

>>> pd.merge(left, right, how='left', on=['key1', 'key2'])
  key1 key2   A   B    C    D
0   K0   K0  A0  B0   C0   D0
1   K0   K1  A1  B1  NaN  NaN
2   K1   K0  A2  B2   C1   D1
3   K1   K0  A2  B2   C2   D2
4   K2   K1  A3  B3  NaN  NaN

右连接:

>>> pd.merge(left, right, how='right', on=['key1', 'key2'])
  key1 key2    A    B   C   D
0   K0   K0   A0   B0  C0  D0
1   K1   K0   A2   B2  C1  D1
2   K1   K0   A2   B2  C2  D2
3   K2   K0  NaN  NaN  C3  D3

如果还是对笛卡尔积不太了解,请务必理解下面这个例子,由于B的所有元素为2,因此需要6行:

>>> left = pd.DataFrame({'A': [1, 2], 'B': [2, 2]})
>>> right = pd.DataFrame({'A': [4, 5, 6], 'B': [2, 2, 2]})
>>> pd.merge(left, right, on='B', how='outer')
   A_x  B  A_y
0    1  2    4
1    1  2    5
2    1  2    6
3    2  2    4
4    2  2    5
5    2  2    6

validate检验的是到底哪一边出现了重复索引,如果是“one_to_one”则两侧索引都是唯一,如果"one_to_many"则左侧唯一

>>> left = pd.DataFrame({'A': [1, 2], 'B': [2, 2]})
>>> right = pd.DataFrame({'A': [4, 5, 6], 'B': [2, 3, 4]})
>>> #pd.merge(left, right, on='B', how='outer',validate='one_to_one') #报错
>>> left = pd.DataFrame({'A': [1, 2], 'B': [2, 1]})
>>> pd.merge(left, right, on='B', how='outer',validate='one_to_one')
   A_x  B  A_y
0  1.0  2  4.0
1  2.0  1  NaN
2  NaN  3  5.0
3  NaN  4  6.0

indicator参数指示了,合并后该行索引的来源

>>> df1 = pd.DataFrame({'col1': [0, 1], 'col_left': ['a', 'b']})
>>> df2 = pd.DataFrame({'col1': [1, 2, 2], 'col_right': [2, 2, 2]})
>>> pd.merge(df1, df2, on='col1', how='outer', indicator=True) #indicator='indicator_column'也是可以的
   col1 col_left  col_right      _merge
0     0        a        NaN   left_only
1     1        b        2.0        both
2     2      NaN        2.0  right_only
3     2      NaN        2.0  right_only

2. join函数

join函数作用是将多个pandas对象横向拼接,遇到重复的索引项时会使用笛卡尔积,默认左连接,可选innerouterright连接

>>> left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
                     'B': ['B0', 'B1', 'B2']},
                    index=['K0', 'K1', 'K2'])
>>> right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
                      'D': ['D0', 'D2', 'D3']},
                    index=['K0', 'K2', 'K3'])
>>> left.join(right)
     A   B    C    D
K0  A0  B0   C0   D0
K1  A1  B1  NaN  NaN
K2  A2  B2   C2   D2

对于many_to_one模式下的合并,往往join更为方便
同样可以指定key

>>> left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
                     'B': ['B0', 'B1', 'B2', 'B3'],
                     'key': ['K0', 'K1', 'K0', 'K1']})
>>> right = pd.DataFrame({'C': ['C0', 'C1'],
                      'D': ['D0', 'D1']},
                     index=['K0', 'K1'])
>>> left.join(right, on='key')
    A   B key   C   D
0  A0  B0  K0  C0  D0
1  A1  B1  K1  C1  D1
2  A2  B2  K0  C0  D0
3  A3  B3  K1  C1  D1

多层key

>>> left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
                     'B': ['B0', 'B1', 'B2', 'B3'],
                     'key1': ['K0', 'K0', 'K1', 'K2'],
                     'key2': ['K0', 'K1', 'K0', 'K1']})
>>> index = pd.MultiIndex.from_tuples([('K0', 'K0'), ('K1', 'K0'),
                                   ('K2', 'K0'), ('K2', 'K1')],names=['key1','key2'])
>>> right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
                      'D': ['D0', 'D1', 'D2', 'D3']},
                     index=index)
>>> left.join(right, on=['key1','key2'])
    A   B key1 key2    C    D
0  A0  B0   K0   K0   C0   D0
1  A1  B1   K0   K1  NaN  NaN
2  A2  B2   K1   K0   C1   D1
3  A3  B3   K2   K1   C3   D3

相关文章
Python Pandas 第1章 基础
Python Pandas 第2章 索引
Python Pandas 第3章 分组
Python Pandas 第4章 变形
Python Pandas 第5章 合并
Python Pandas 第6章 缺少数据
Python Pandas 第7章 文本数据
Python Pandas 第8章 分类数据
Python Pandas 第9章 时序数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值