3.7 合并数据集:Concat与Append操作

3.7 合并数据集:Concat与Append操作

经常需要将不同的数据源进行合并,pd中有函数提供方便。

 

import numpy as np
import pandas as pd

简单起见,先定义一个能创建DF数据的函数:

 

def make_df(cols, ind):
    """快速创建 DataFrame"""
    data = {c: [str(c) + str(i) for i in ind]
            for c in cols}
    return pd.DataFrame(data, ind)
# 例子 DataFrame
make_df('ABC', range(3))
  A B C
0 A0 B0 C0
1 A1 B1 C1
2 A2 B2 C2

定义一个display类,用于方便地并列显示数据:

 

class display(object):
    """Display HTML representation of multiple objects"""
    template = """
    

{0}

{1}
    
"""
    def __init__(self, *args):
        self.args = args
 
    def _repr_html_(self):
        return '\n'.join(self.template.format(a, eval(a)._repr_html_())
                         for a in self.args)
 
    def __repr__(self):
        return '\n\n'.join(a + '\n' + repr(eval(a))
                           for a in self.args)

3.7.1 回顾np数组的合并

np数组可用函数 np.concatenate 进行合并:

 

x = [1, 2, 3]
y = [4, 5, 6]
z = [7, 8, 9]
np.concatenate([x, y, z])
array([1, 2, 3, 4, 5, 6, 7, 8, 9])

第一个参数是需要合并的数组列表或元组,还有一个axis参数可以设置合并的坐标轴方向:

 

x = [[1, 2],
     [3, 4]]
np.concatenate([x, x])
array([[1, 2],
       [3, 4],
       [1, 2],
       [3, 4]])

 

np.concatenate([x, x], axis=1)
array([[1, 2, 1, 2],
       [3, 4, 3, 4]])

3.7.2 通过pd.concat实现简易合并

pd有函数 pd.concat() 与前述np的函数 np.concatenate 语法类似,但是配置参数更多,功能也更强大:

# Signature in Pandas v0.18
pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
          keys=None, levels=None, names=None, verify_integrity=False,
          copy=True)

concat可以简单地合并一维Series或DF对象,与np的concatenate合并数组一样:

 

ser1 = pd.Series(['A', 'B', 'C'], index=[1, 2, 3])
ser2 = pd.Series(['D', 'E', 'F'], index=[4, 5, 6])
pd.concat([ser1, ser2])
1    A
2    B
3    C
4    D
5    E
6    F
dtype: object

也可用来合并高维数据,如下面的DF:

 

df1 = make_df('AB', [1, 2])
df2 = make_df('AB', [3, 4])
display('df1', 'df2', 'pd.concat([df1, df2])')

df1

  A B
1 A1 B1
2 A2 B2

df2

  A B
3 A3 B3
4 A4 B4

pd.concat([df1, df2])

  A B
1 A1 B1
2 A2 B2
3 A3 B3
4 A4 B4

默认情况下DF的合并都是逐行进行的,即默认设置 axis=0 。concat也可以设置合并坐标轴,如:

 

df3 = make_df('AB', [0, 1])
df4 = make_df('CD', [0, 1])
display('df3', 'df4', "pd.concat([df3, df4], axis=1)")

df3

  A B
0 A0 B0
1 A1 B1

df4

  C D
0 C0 D0
1 C1 D1

pd.concat([df3, df4], axis=1)

  A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1

索引重复

pd与np在合并函数上的主要差异就是,pd在合并时会保留索引,即使索引是重复的,依然保留,如:

 

x = make_df('AB', [0, 1])
y = make_df('AB', [2, 3])
y.index = x.index  # 复制索引
display('x', 'y', 'pd.concat([x, y])')

x

  A B
0 A0 B0
1 A1 B1

y

  A B
0 A2 B2
1 A3 B3

pd.concat([x, y])

  A B
0 A0 B0
1 A1 B1
0 A2 B2
1 A3 B3

如果不想要重复的索引,有如下办法:

  • 1 捕捉索引重复的错误。可设置参数verify_integrity为True,合并时如果有重复索引则引发异常:

 

try:
    pd.concat([x, y], verify_integrity=True)
except ValueError as e:
    print("ValueError:", e)
ValueError: Indexes have overlapping values: Int64Index([0, 1], dtype='int64')
  • 2 忽略索引。有时索引无关紧要,那么合并时就可忽略之,设置参数ignore_index为True即可,此时合并时会创建一个新的整数索引,而将旧索引丢弃:

 

display('x', 'y', 'pd.concat([x, y], ignore_index=True)')

x

  A B
0 A0 B0
1 A1 B1

y

  A B
0 A2 B2
1 A3 B3

pd.concat([x, y], ignore_index=True)

  A B
0 A0 B0
1 A1 B1
2 A2 B2
3 A3 B3
  • 3 增加多级索引。另一种处理索引重复的方法是通过keys参数为数据源设置多级索引标签,这样结果数据就会带上多级索引:

 

display('x', 'y', "pd.concat([x, y], keys=['x', 'y'])")

x

  A B
0 A0 B0
1 A1 B1

y

  A B
0 A2 B2
1 A3 B3

pd.concat([x, y], keys=['x', 'y'])

    A B
x 0 A0 B0
1 A1 B1
y 0 A2 B2
1 A3 B3

示例合并后的结果是多级索引的DF对象,可用3.6节介绍的方法进行进一步转化,变为需要的形式。

类似 join 的合并

实际情况中往往合并的数据有不同的列名,concat有参数用于此种情况:

 

df5 = make_df('ABC', [1, 2])
df6 = make_df('BCD', [3, 4])
display('df5', 'df6', 'pd.concat([df5, df6])')
c:\program files\python36-32\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=False'.

To retain the current behavior and silence the warning, pass 'sort=True'.

  """Entry point for launching an IPython kernel.

df5

  A B C
1 A1 B1 C1
2 A2 B2 C2

df6

  B C D
3 B3 C3 D3
4 B4 C4 D4

pd.concat([df5, df6])

  A B C D
1 A1 B1 C1 NaN
2 A2 B2 C2 NaN
3 NaN B3 C3 D3
4 NaN B4 C4 D4

 

df5 = make_df('ABC', [1, 2])
df6 = make_df('BCD', [3, 4])
display('df5', 'df6', 'pd.concat([df5, df6], sort=False)')

df5

  A B C
1 A1 B1 C1
2 A2 B2 C2

df6

  B C D
3 B3 C3 D3
4 B4 C4 D4

pd.concat([df5, df6], sort=False)

  A B C D
1 A1 B1 C1 NaN
2 A2 B2 C2 NaN
3 NaN B3 C3 D3
4 NaN B4 C4 D4

默认情况下,某位置的缺失数据会设为NaN,如不想这样,用参数join:

  • join='outer' 对输入列进行并集合并
  • join='inner' 对输入列进行交集合并

 

display('df5', 'df6',
        "pd.concat([df5, df6], join='outer')")
c:\program files\python36-32\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=False'.

To retain the current behavior and silence the warning, pass 'sort=True'.

  """Entry point for launching an IPython kernel.

df5

  A B C
1 A1 B1 C1
2 A2 B2 C2

df6

  B C D
3 B3 C3 D3
4 B4 C4 D4

pd.concat([df5, df6], join='outer')

  A B C D
1 A1 B1 C1 NaN
2 A2 B2 C2 NaN
3 NaN B3 C3 D3
4 NaN B4 C4 D4

 

display('df5', 'df6',
        "pd.concat([df5, df6], join='inner')")

df5

  A B C
1 A1 B1 C1
2 A2 B2 C2

df6

  B C D
3 B3 C3 D3
4 B4 C4 D4

pd.concat([df5, df6], join='inner')

  B C
1 B1 C1
2 B2 C2
3 B3 C3
4 B4 C4

另一种方法是直接确定结果使用的列名,设置参数join_axes,值为索引对象构成的列表(列表的列表),如下,将结果的列表设为第一个输入的列名:

 

display('df5', 'df6',
        "pd.concat([df5, df6], join_axes=[df5.columns])")

df5

  A B C
1 A1 B1 C1
2 A2 B2 C2

df6

  B C D
3 B3 C3 D3
4 B4 C4 D4

pd.concat([df5, df6], join_axes=[df5.columns])

  A B C
1 A1 B1 C1
2 A2 B2 C2
3 NaN B3 C3
4 NaN B4 C4

append方法

该方法可以较小的代码实现合并功能,与concat效果相同,如:

 

display('df1', 'df2', 'df1.append(df2)')
# pd.concat([df1, df2]) 等同 df1.append(df2)

df1

  A B
1 A1 B1
2 A2 B2

df2

  A B
3 A3 B3
4 A4 B4

df1.append(df2)

  A B
1 A1 B1
2 A2 B2
3 A3 B3
4 A4 B4

注意:与python列表中的append方法不同,pd的append实际上不直接更新原有数据对象的值,而是为合并后的数据创建一个新的对象。如需要合并多个DF,还是用concat一次合并更节省资源。

你可能感兴趣的:(python,数据科学)