Pandas数据规整 - 合并
数据合并
Pandas提供了大量方法,能轻松的对Series,DataFrame执行合并操作
- 按行合并
- 按列合并
- 合并重叠数据(一个表为主,先填充再合并):combine_first()
import numpy as np
import pandas as pd
追加 append()
df = pd.DataFrame(np.random.randn(8, 4), columns = ['A','B','C','D'])
df
|
A |
B |
C |
D |
0 |
-0.689822 |
-0.648901 |
-1.254336 |
-1.462992 |
1 |
1.015466 |
-0.080582 |
-0.151619 |
1.031207 |
2 |
0.306727 |
0.632053 |
-2.154726 |
-1.709076 |
3 |
-0.690849 |
-1.192955 |
0.854840 |
0.981361 |
4 |
0.123055 |
-1.175942 |
-0.857090 |
-1.328282 |
5 |
0.062193 |
-1.254776 |
-1.754978 |
-1.902248 |
6 |
1.156093 |
0.884695 |
0.491332 |
1.186955 |
7 |
0.067683 |
-1.017259 |
1.504190 |
-0.111545 |
s = df.loc[[3, 5]]
s
|
A |
B |
C |
D |
3 |
-0.690849 |
-1.192955 |
0.854840 |
0.981361 |
5 |
0.062193 |
-1.254776 |
-1.754978 |
-1.902248 |
# 追加合并
df.append(s)
df.append(s, ignore_index=True) # 不使用追加表的索引,使用主表的默认索引
|
A |
B |
C |
D |
0 |
-0.689822 |
-0.648901 |
-1.254336 |
-1.462992 |
1 |
1.015466 |
-0.080582 |
-0.151619 |
1.031207 |
2 |
0.306727 |
0.632053 |
-2.154726 |
-1.709076 |
3 |
-0.690849 |
-1.192955 |
0.854840 |
0.981361 |
4 |
0.123055 |
-1.175942 |
-0.857090 |
-1.328282 |
5 |
0.062193 |
-1.254776 |
-1.754978 |
-1.902248 |
6 |
1.156093 |
0.884695 |
0.491332 |
1.186955 |
7 |
0.067683 |
-1.017259 |
1.504190 |
-0.111545 |
8 |
-0.690849 |
-1.192955 |
0.854840 |
0.981361 |
9 |
0.062193 |
-1.254776 |
-1.754978 |
-1.902248 |
DataFrame和Series追加合并
s2 = pd.Series([1,2,3,4], index = ['A','B','C','D'])
s2
A 1
B 2
C 3
D 4
dtype: int64
df.append(s2, ignore_index=True)
|
A |
B |
C |
D |
0 |
-0.689822 |
-0.648901 |
-1.254336 |
-1.462992 |
1 |
1.015466 |
-0.080582 |
-0.151619 |
1.031207 |
2 |
0.306727 |
0.632053 |
-2.154726 |
-1.709076 |
3 |
-0.690849 |
-1.192955 |
0.854840 |
0.981361 |
4 |
0.123055 |
-1.175942 |
-0.857090 |
-1.328282 |
5 |
0.062193 |
-1.254776 |
-1.754978 |
-1.902248 |
6 |
1.156093 |
0.884695 |
0.491332 |
1.186955 |
7 |
0.067683 |
-1.017259 |
1.504190 |
-0.111545 |
8 |
1.000000 |
2.000000 |
3.000000 |
4.000000 |
连接 .concat()
df = pd.DataFrame(np.random.randn(10, 4))
df
|
0 |
1 |
2 |
3 |
0 |
-0.373907 |
-0.769224 |
0.461345 |
1.337485 |
1 |
-0.740551 |
0.099881 |
1.117474 |
-0.039611 |
2 |
0.487944 |
0.544769 |
-0.306465 |
-2.191426 |
3 |
0.358255 |
0.451373 |
-2.207165 |
0.741016 |
4 |
0.737892 |
1.124667 |
-0.764180 |
0.127036 |
5 |
0.666555 |
0.351640 |
-0.001513 |
0.491519 |
6 |
-1.705258 |
0.890396 |
0.049744 |
-0.041995 |
7 |
0.551278 |
-2.426324 |
0.954741 |
-1.388955 |
8 |
1.058934 |
0.922589 |
0.516951 |
-0.070646 |
9 |
1.379310 |
-0.898367 |
0.572260 |
-0.648712 |
x = df.loc[:2]
x
y = df.loc[4:6]
y
z = df[-2:]
z
|
0 |
1 |
2 |
3 |
8 |
1.058934 |
0.922589 |
0.516951 |
-0.070646 |
9 |
1.379310 |
-0.898367 |
0.572260 |
-0.648712 |
pd.concat([x, y, z]) # 将合并表格放入列表
|
0 |
1 |
2 |
3 |
0 |
-0.373907 |
-0.769224 |
0.461345 |
1.337485 |
1 |
-0.740551 |
0.099881 |
1.117474 |
-0.039611 |
2 |
0.487944 |
0.544769 |
-0.306465 |
-2.191426 |
4 |
0.737892 |
1.124667 |
-0.764180 |
0.127036 |
5 |
0.666555 |
0.351640 |
-0.001513 |
0.491519 |
6 |
-1.705258 |
0.890396 |
0.049744 |
-0.041995 |
8 |
1.058934 |
0.922589 |
0.516951 |
-0.070646 |
9 |
1.379310 |
-0.898367 |
0.572260 |
-0.648712 |
复杂合并 .merge()和.join()
merge()函数用于复杂综合数据合并,操作复杂,功能强大
join()是merge()的一个特殊用法,用于按索引合并,操作简单,功能单一
# df1,姓名和分组
df1 = pd.DataFrame({
'name': ['张三', '李四', '王五', '赵六'],
'group': ['DBA', 'PM','PM', 'HR']
})
df1
|
name |
group |
0 |
张三 |
DBA |
1 |
李四 |
PM |
2 |
王五 |
PM |
3 |
赵六 |
HR |
# df2,姓名和入职时间
df2 = pd.DataFrame({
'name': ['李四', '赵六', '张三', '王五'],
'date': [2004, 2008, 2012, 2014]
})
df2
|
name |
date |
0 |
李四 |
2004 |
1 |
赵六 |
2008 |
2 |
张三 |
2012 |
3 |
王五 |
2014 |
使用查询和添加列进行表合并
比较麻烦
# 查询添加默认以行索引为基准对齐,所以需要把俩表相关列设为行索引
df11 = df1.set_index('name').copy()
df21 = df2.set_index('name').copy()
df21['group'] = df11['group']
df21.reset_index()
|
name |
date |
group |
0 |
李四 |
2004 |
PM |
1 |
赵六 |
2008 |
HR |
2 |
张三 |
2012 |
DBA |
3 |
王五 |
2014 |
PM |
两个表必须有相关性,才有合并的需要
以两个表相关的列(或行索引)为基准,合并
合并两个对象,默认匹配相同过的列名,自动对齐合并
df3 = pd.merge(df1, df2)
df3
|
name |
group |
date |
0 |
张三 |
DBA |
2012 |
1 |
李四 |
PM |
2004 |
2 |
王五 |
PM |
2014 |
3 |
赵六 |
HR |
2008 |
要合并的样本量(行数)不同时,合并后的数据会自动扩展,不损失信息
df3
|
name |
group |
date |
0 |
张三 |
DBA |
2012 |
1 |
李四 |
PM |
2004 |
2 |
王五 |
PM |
2014 |
3 |
赵六 |
HR |
2008 |
# df4,每个分组的领导,行数少
df4 = pd.DataFrame({
'group': ['DBA', 'PM', 'HR'],
'leader': ['钱大', '孙二', '周三']
})
df4
|
group |
leader |
0 |
DBA |
钱大 |
1 |
PM |
孙二 |
2 |
HR |
周三 |
# 样本量(行数)不同时,合并后的数据会自动扩展,不损失信息
pd.merge(df3, df4)
|
name |
group |
date |
leader |
0 |
张三 |
DBA |
2012 |
钱大 |
1 |
李四 |
PM |
2004 |
孙二 |
2 |
王五 |
PM |
2014 |
孙二 |
3 |
赵六 |
HR |
2008 |
周三 |
分组和技能,行数多
df1
|
name |
group |
0 |
张三 |
DBA |
1 |
李四 |
PM |
2 |
王五 |
PM |
3 |
赵六 |
HR |
df5 = pd.DataFrame({
'group': ['DBA', 'DBA','PM', 'PM', 'HR', 'HR'],
'skills': ['Linux', '数据库', 'Axuer RP', '社交','招聘', '组织']
})
df5
|
group |
skills |
0 |
DBA |
Linux |
1 |
DBA |
数据库 |
2 |
PM |
Axuer RP |
3 |
PM |
社交 |
4 |
HR |
招聘 |
5 |
HR |
组织 |
pd.merge(df1, df5)
|
name |
group |
skills |
0 |
张三 |
DBA |
Linux |
1 |
张三 |
DBA |
数据库 |
2 |
李四 |
PM |
Axuer RP |
3 |
李四 |
PM |
社交 |
4 |
王五 |
PM |
Axuer RP |
5 |
王五 |
PM |
社交 |
6 |
赵六 |
HR |
招聘 |
7 |
赵六 |
HR |
组织 |
两个表没有同名列时,如何合并
两个对象没有同名列时,用left_on和right_on强制指定列名对应合并
# df1,姓名 name 和分组
df1
|
name |
group |
0 |
张三 |
DBA |
1 |
李四 |
PM |
2 |
王五 |
PM |
3 |
赵六 |
HR |
# df6,姓名2 username 和薪资
df6 = pd.DataFrame({
'username': ['王五', '张三', '赵六', '李四'],
'salary': [10000, 160000, 7000, 120000]
})
df6
|
username |
salary |
0 |
王五 |
10000 |
1 |
张三 |
160000 |
2 |
赵六 |
7000 |
3 |
李四 |
120000 |
pd.merge(df1, df6, left_on='name', right_on='username')
pd.merge(df1, df6, left_on='name', right_on='username').drop('username', axis=1) # 删除多余列
|
name |
group |
salary |
0 |
张三 |
DBA |
160000 |
1 |
李四 |
PM |
120000 |
2 |
王五 |
PM |
10000 |
3 |
赵六 |
HR |
7000 |
按照行索引合并
当要合并数据的行索引相关时,指定 merge() 函数的参数 left_index 与 right_index 的值为 True,就可以实现自动依照索引序号合并
join()函数也能实现,写法更简单
merge()的优势在于更灵活,尤其是当数据集索引值差别很大,数据合并又必须以其中一组数据的索引值为依据时
# df1a,将df1的name列设为行索引
df1a = df1.set_index('name')
df1a
|
group |
name |
|
--- |
--- |
张三 |
DBA |
李四 |
PM |
王五 |
PM |
赵六 |
HR |
# df2a,将df2的name列设为行索引
df2a = df2.set_index('name')
df2a
|
date |
name |
|
--- |
--- |
李四 |
2004 |
赵六 |
2008 |
张三 |
2012 |
王五 |
2014 |
按索引合并,最简单的方式 :join()
df1a.join(df2a)
|
group |
date |
name |
|
|
--- |
--- |
--- |
张三 |
DBA |
2012 |
李四 |
PM |
2004 |
王五 |
PM |
2014 |
赵六 |
HR |
2008 |
# merge实现,同上
pd.merge(df1a, df2a, left_index=True, right_index=True)
|
group |
date |
name |
|
|
--- |
--- |
--- |
张三 |
DBA |
2012 |
李四 |
PM |
2004 |
王五 |
PM |
2014 |
赵六 |
HR |
2008 |
两数据索引差异巨大,又必须以一个索引为主合并
# df1a,姓名和分组,姓名为行索引
df1a
|
group |
name |
|
--- |
--- |
张三 |
DBA |
李四 |
PM |
王五 |
PM |
赵六 |
HR |
# df6,姓名2和薪资
df6
|
username |
salary |
0 |
王五 |
10000 |
1 |
张三 |
160000 |
2 |
赵六 |
7000 |
3 |
李四 |
120000 |
# 指定一个表的行索引和另一个表的列为基准合并
pd.merge(df1a, df6, left_index=True, right_on='username')
|
group |
username |
salary |
1 |
DBA |
张三 |
160000 |
3 |
PM |
李四 |
120000 |
0 |
PM |
王五 |
10000 |
2 |
HR |
赵六 |
7000 |
两个对应列不完全重复的数据集的合并
参数 how
-
how='inner'
,交集,两个表共有的行
-
how='outer'
,并集,两个表所有的行
-
how='left'
,表1的行
-
how='right'
,表2的行
# df1,姓名和分组
df1
|
name |
group |
0 |
张三 |
DBA |
1 |
李四 |
PM |
2 |
王五 |
PM |
3 |
赵六 |
HR |
# df7,姓名和时间,姓名列不完全一致
df7 = pd.DataFrame({'name':['张一', '李二', '赵六'], 'data':[2000,2001,2002]})
df7
|
name |
data |
0 |
张一 |
2000 |
1 |
李二 |
2001 |
2 |
赵六 |
2002 |
pd.merge(df1, df7) # 简写
pd.merge(df1, df7, how='inner') # 交集
|
name |
group |
data |
0 |
赵六 |
HR |
2002 |
pd.merge(df1, df7, how='outer') # 并集
|
name |
group |
data |
0 |
张三 |
DBA |
NaN |
1 |
李四 |
PM |
NaN |
2 |
王五 |
PM |
NaN |
3 |
赵六 |
HR |
2002.0 |
4 |
张一 |
NaN |
2000.0 |
5 |
李二 |
NaN |
2001.0 |
pd.merge(df1, df7, how='left') # 以左表为基准
|
name |
group |
data |
0 |
张三 |
DBA |
NaN |
1 |
李四 |
PM |
NaN |
2 |
王五 |
PM |
NaN |
3 |
赵六 |
HR |
2002.0 |
pd.merge(df1, df7, how='right') # 以右表为基准
|
name |
group |
data |
0 |
赵六 |
HR |
2002 |
1 |
张一 |
NaN |
2000 |
2 |
李二 |
NaN |
2001 |
合并数据集中包含两个或以上相同列名时
参数 on 指定用于合并的主键
合并后的数据集中,之前相同的列名会被默认加上 _x 等后缀用于区分
参数 suffixes 可以自定义后缀
# df1,姓名和分组
df1
|
name |
group |
0 |
张三 |
DBA |
1 |
李四 |
PM |
2 |
王五 |
PM |
3 |
赵六 |
HR |
# df8,相同的姓名和分组
df8 = pd.DataFrame({
'name': ['张三', '王五', '赵六', '李四'],
'group': ['code', 'VP','VP', 'code']
})
df8
|
name |
group |
0 |
张三 |
code |
1 |
王五 |
VP |
2 |
赵六 |
VP |
3 |
李四 |
code |
pd.merge(df1, df8, on='name') # 两表超过1个列名相同,手动指定合并基准列
|
name |
group_x |
group_y |
0 |
张三 |
DBA |
code |
1 |
李四 |
PM |
code |
2 |
王五 |
PM |
VP |
3 |
赵六 |
HR |
VP |
# 通过设置参数 suffixes 自定义后缀
pd.merge(df1, df8, on='name', suffixes=['_L', '_R'])
|
name |
group_L |
group_R |
0 |
张三 |
DBA |
code |
1 |
李四 |
PM |
code |
2 |
王五 |
PM |
VP |
3 |
赵六 |
HR |
VP |
合并重叠数据
有一类数据组合问题不能用简单的合并(merge)或连接(concatenation(concat))运算来处理。 如合并全部或部分重叠的两个数据集
举例,我们使用NumPy的where函数,它表示一种等价于面向数组的if-else
以a为基准合并,a的缺失值使用b填充
先给a打补丁(用b填充a的缺失值,再合并)
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
a
f NaN
e 2.5
d NaN
c 3.5
b 4.5
a NaN
dtype: float64
b
f 0.0
e 1.0
d 2.0
c 3.0
b 4.0
a NaN
dtype: float64
方法1
ax = a.copy()
ax.isnull()
ax[ax.isnull()] # 查询a的缺失值
ax[ax.isnull()] = b # a的缺失值用b填充(操作默认是索引对齐)
ax
f 0.0
e 2.5
d 2.0
c 3.5
b 4.5
a NaN
dtype: float64
Series有一个combine_first方法,实现的也是类似功能,
除了用b填充a的缺失值,还带有pandas数据对齐的合并功能
例子:以a2为基准合并,a2缺失数据使用b2填充
a2 = a[2:]
a2
d NaN
c 3.5
b 4.5
a NaN
dtype: float64
b2 = b[:-2]
b2
f 0.0
e 1.0
d 2.0
c 3.0
dtype: float64
方法1:使用原生方式打补丁(a2的缺失值使用b2填充)
# 使用b2填充a2
a2[a2.isnull()] = b2
a2
# # 打补丁后合并
a22 = a2.append(b2)
a22
# # 去重,排序
a22.index.duplicated()
a22[~(a22.index.duplicated())].sort_index()
a NaN
b 4.5
c 3.5
d 2.0
e 1.0
f 0.0
dtype: float64
方法2:使用combine_first方法,先打补丁,再合并,再排序
a3 = a[2:]
a3
a3.combine_first(b2)
a NaN
b 4.5
c 3.5
d 2.0
e 1.0
f 0.0
dtype: float64
对于DataFrame,combine_first会在列上应用同样操作,可以将其看做:
用传递对象中的数据为调用对象的缺失数据“打补丁”
df11 = pd.DataFrame({'a': [1., np.nan, 5., np.nan], 'b': [np.nan, 2., np.nan, 6.], 'c': range(2, 18, 4)})
df21 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.], 'b': [np.nan, 3., 4., 6., 8.]})
df11
|
a |
b |
c |
0 |
1.0 |
NaN |
2 |
1 |
NaN |
2.0 |
6 |
2 |
5.0 |
NaN |
10 |
3 |
NaN |
6.0 |
14 |
df21
|
a |
b |
0 |
5.0 |
NaN |
1 |
4.0 |
3.0 |
2 |
NaN |
4.0 |
3 |
3.0 |
6.0 |
4 |
7.0 |
8.0 |
df11.combine_first(df21) # 以df11为基准,先填充缺失值(用df21的值填充df11),再合并(df21的多余行列合并到df11上)
|
a |
b |
c |
0 |
1.0 |
NaN |
2.0 |
1 |
4.0 |
2.0 |
6.0 |
2 |
5.0 |
4.0 |
10.0 |
3 |
3.0 |
6.0 |
14.0 |
4 |
7.0 |
8.0 |
NaN |
df21.combine_first(df11) # 以df21为基准,先填充(用df11的值填充df21),再合并
|
a |
b |
c |
0 |
5.0 |
NaN |
2.0 |
1 |
4.0 |
3.0 |
6.0 |
2 |
5.0 |
4.0 |
10.0 |
3 |
3.0 |
6.0 |
14.0 |
4 |
7.0 |
8.0 |
NaN |