Pandas数据规整 - 合并

Pandas数据规整 - 合并


数据合并

Pandas提供了大量方法,能轻松的对Series,DataFrame执行合并操作

  • 按行合并
    • 追加:append()
    • 连接:concat()
  • 按列合并
    • 复杂合并:merge()
      • 按行索引合并:join()
  • 合并重叠数据(一个表为主,先填充再合并):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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容