R|数据处理|merge数据详解
Dwzb , R语言中文社区专栏作者,厦门大学统计专业学生。
知乎专栏:https://zhuanlan.zhihu.com/Data-AnalysisR
前文推送:
R数据处理|基础篇(一)
R数据处理|基础篇(二)
R数据处理|data.table篇(一)
R数据处理|data.table篇(二)
R数据处理|data.table篇(三)
R深入 | 数据类型
R | 基础绘图
R|ggplot2(一)|一个完整的绘图流程
由于merge数据在现实应用中使用非常广泛,而且真实的数据远远没有我们练习时使用的数据那么干净,所以有了这篇文章。本文会针对现实数据中可能遇到的一些问题,更深入地讲解merge数据的使用。
数据:自己有针对性地创建,故意踩一些坑并解决
函数:包括dplyr包的join族函数,data.table包的[DT, ]方法,基础及data.table包的merge函数
主要解决如下问题
要合并的两个数据集,合并所依据的列,名称不同
要合并的两个数据集,有一些相同的列名,合并后需要更改防止两列同名
合并所依据的列不是完全相同的,展示多种取舍方法
合并所依据的列中,内容不是唯一的,展示几种情况的处理方法
全文分dplyr包和data.table包来讲
数据创建
先简单说明一下创建的数据
第一组一共四个数据框
data_map 有两列可以用于merge,作为其他数据之间的桥梁,将所有数据merge在一起
data_good 用于merge的列形式很好,和data_map中的列一一对应,用于展示最简单的数据框merge合并。但是为了演示一些参数,在列名上挖了两个坑
data_diff 用于merge的列和data_map中的列有交集,都不完全包括对方,用于展示多种取舍方法在两个包中的 实现
data_bad 用于merge的列有重复,与data_map这个没有重复的数据来merge
第二组两个数据框: bad1和bad2,用于merge的列都有重复,用于展示都有重复时的merge
这里主要展示数据框创建代码,数据框长什么样子,在下面的例子中都会展示
library(dplyr) library(data.table) library(lubridate) # 设置随机种子保证随机试验可以重复 set.seed(1234) # 两列每个值都是唯一的 data_map <- data.table(name_id = letters[1:10], card_id = LETTERS[1:10]) m2 <- sample(letters[1:10], 15, replace = T) m1 <- sample(LETTERS[1:10], 10, replace = F) # object_id列值是唯一的,且正好和data_map的name_id列一一对应 data_good <- data.table(object_id = m1, # 与card_id列对应来合并,故意制造合并列名称不同的情况 name_id = paste(m1, m1, sep='')) # 故意制造同名情况 # name_id列值唯一,与data_map的name_id只有4个重合的 data_diff <- data.table(name_id = sample(letters, 10, replace = F), x1 = c(rep('m',4), rep('n',3), rep('p',3))) # name_id列值不唯一,与data_map的name_id只有7个重合的,但是data_bad中有的在data_map中都能找到 data_bad <- data.table(name_id = m2, # 与name_id对应来合并 date = ymd('20171218') + ddays(rowid(m2)), content1 = paste(m2, 1:15, sep='_content'), content2 = paste(m2, 1:15, sep='another')) bad1 <- data.table(name_id = c(1,2,3,1,4,5,1,6), text1 = letters[1:8]) bad2 <- data.table(name_id = c(1,2,3,1,2,5,3,7), text12 = LETTERS[1:8])
join族函数
dplyr包中,join族函数分为如下几个函数(对于 *_join(new, data_diff, by='name_id') 来说)
left_join 以new中name_id(记为A)为准。data_diff的name_id中,不在A中的全部舍弃,其余的对应匹配上去
right_join 和left相反,以data_diff为准
inner_join 保留两个数据name_id交叉的部分
full_join 两个数据所有内容都保留,相当于left_join结果,加上right_join结果,减去inner_join的结果
semi_join 与 anti_join 其实是对行筛选,不算是merge合并
下面代码结果分别展示
1. 这部分展示
join族函数中的两个参数 by suffix
各个join函数有什么区别
代码展示如下
new <- left_join(data_map, data_good, # 这是两个完全匹配的数据 by = c('card_id'='object_id'), # 对应匹配的列名不同,在此指定 suffix = c('', '_good')) # 两个数据有相同列名,指定融合后,两个数据集相同列名,分别加什么样的后缀 head(new) left_join(new, data_diff, by = 'name_id') right_join(new, data_diff, by = 'name_id') left_join(data_diff, new, by = 'name_id') # 除了列顺序之外,内容和上一条是一样的 inner_join(new, data_diff, by = 'name_id') full_join(new, data_diff, by = 'name_id') semi_join(new, data_diff, by = 'name_id') new[new$name_id %in% data_diff$name_id, ] # 同上 anti_join(new, data_diff, by = 'name_id') new[!new$name_id %in% data_diff$name_id, ] # 同上
结果展示如下
首先合并的是data_map和data_good得到new
data_map data_good name_id card_id || object_id name_id a A || I II b B || C CC c C || J JJ d D || B BB e E || G GG f F || F FF g G || E EE h H || A AA i I || H HH j J || D DD new card_id name_id name_id_good A a AA B b BB C c CC D d DD E e EE F f FF G g GG H h HH I i II J j JJ
下一步是new和data_diff的多种合并结果
new (name_id只有4个重合) data_diff name_id card_id name_id_good || name_id x1 a A AA || v m b B BB || n m c C CC || z m d D DD || t m e E EE || b n f F FF || j n g G GG || f n h H HH || w p i I II || u p j J JJ || d p left_join(保留new) name_id card_id name_id_good x1 a A AA <NA> b B BB n c C CC <NA> d D DD p e E EE <NA> f F FF n g G GG <NA> h H HH <NA> i I II <NA> j J JJ n right_join(保留data_diff) name_id card_id name_id_good x1 v <NA> <NA> m n <NA> <NA> m z <NA> <NA> m t <NA> <NA> m b B BB n j J JJ n f F FF n w <NA> <NA> p u <NA> <NA> p d D DD p inner_join(取交集) name_id card_id name_id_good x1 b B BB n d D DD p f F FF n j J JJ n full_join(取并集) name_id card_id name_id_good x1 a A AA <NA> b B BB n c C CC <NA> d D DD p e E EE <NA> f F FF n g G GG <NA> h H HH <NA> i I II <NA> j J JJ n v <NA> <NA> m n <NA> <NA> m z <NA> <NA> m t <NA> <NA> m w <NA> <NA> p u <NA> <NA> p semi_join(在new中筛选出data_diff有的) name_id card_id name_id_good b B BB d D DD f F FF j J JJ anti_join(在new中筛选出data_diff没有的) name_id card_id name_id_good a A AA c C CC e E EE g G GG h H HH i I II
2.接下来考虑一个数据merge列有重复的情况
# 只有一个数据的name_id有重复,就会自动扩充 left_join(new, data_bad, by = 'name_id') right_join(new, data_bad, by = 'name_id')
结果展示如下
new name_id card_id name_id_good a A AA b B BB c C CC d D DD e E EE f F FF g G GG h H HH i I II j J JJ data_bad name_id date content1 content2 b 2017-12-19 b_content1 banother1 g 2017-12-19 g_content2 ganother2 g 2017-12-20 g_content3 ganother3 g 2017-12-21 g_content4 ganother4 i 2017-12-19 i_content5 ianother5 g 2017-12-22 g_content6 ganother6 a 2017-12-19 a_content7 aanother7 c 2017-12-19 c_content8 canother8 g 2017-12-23 g_content9 ganother9 f 2017-12-19 f_content10 fanother10 g 2017-12-24 g_content11 ganother11 f 2017-12-20 f_content12 fanother12 c 2017-12-20 c_content13 canother13 j 2017-12-19 j_content14 janother14 c 2017-12-21 c_content15 canother15 left_join(new, data_bad, by = 'name_id') name_id card_id name_id_good date content1 content2 a A AA 2017-12-19 a_content7 aanother7 b B BB 2017-12-19 b_content1 banother1 c C CC 2017-12-19 c_content8 canother8 c C CC 2017-12-20 c_content13 canother13 c C CC 2017-12-21 c_content15 canother15 d D DD <NA> <NA> <NA> e E EE <NA> <NA> <NA> f F FF 2017-12-19 f_content10 fanother10 f F FF 2017-12-20 f_content12 fanother12 g G GG 2017-12-19 g_content2 ganother2 g G GG 2017-12-20 g_content3 ganother3 g G GG 2017-12-21 g_content4 ganother4 g G GG 2017-12-22 g_content6 ganother6 g G GG 2017-12-23 g_content9 ganother9 g G GG 2017-12-24 g_content11 ganother11 h H HH <NA> <NA> <NA> i I II 2017-12-19 i_content5 ianother5 j J JJ 2017-12-19 j_content14 janother14 right_join(new, data_bad, by = 'name_id') name_id card_id name_id_good date content1 content2 b B BB 2017-12-19 b_content1 banother1 g G GG 2017-12-19 g_content2 ganother2 g G GG 2017-12-20 g_content3 ganother3 g G GG 2017-12-21 g_content4 ganother4 i I II 2017-12-19 i_content5 ianother5 g G GG 2017-12-22 g_content6 ganother6 a A AA 2017-12-19 a_content7 aanother7 c C CC 2017-12-19 c_content8 canother8 g G GG 2017-12-23 g_content9 ganother9 f F FF 2017-12-19 f_content10 fanother10 g G GG 2017-12-24 g_content11 ganother11 f F FF 2017-12-20 f_content12 fanother12 c C CC 2017-12-20 c_content13 canother13 j J JJ 2017-12-19 j_content14 janother14 c C CC 2017-12-21 c_content15 canother15
当我们要把多张表merge到一起时,如果有几张都是merge列有重复的情况,就会面临要merge的两个数据都是有重复的的情况
3.两个数据集merge列都有重复
代码展示如下(直接使用left_join看默认情况即可)
> bad1 name_id text1 1: 1 a 2: 2 b 3: 3 c 4: 1 d 5: 4 e 6: 5 f 7: 1 g 8: 6 h > bad2 name_id text12 1: 1 A 2: 2 B 3: 3 C 4: 1 D 5: 2 E 6: 5 F 7: 3 G 8: 7 H > left_join(bad1, bad2, by = 'name_id') name_id text1 text12 1 1 a A 2 1 a D 3 2 b B 4 2 b E 5 3 c C 6 3 c G 7 1 d A 8 1 d D 9 4 e <NA> 10 5 f F 11 1 g A 12 1 g D 13 6 h <NA>
从上面结果可见,比如1重复,则bad1中的每个1都和bad2的每个1构成一行,所以产生了3*2=6个name_id是1的行。
这样merge有一个缺点就是产生了大量重复数据,还有另一种处理方法,长表变宽表,这样可以让name_id不会重复,但是列就会增加很多。
这里只展示data_bad如何将name_id唯一化的,即把date变到列上去,即看每个name_id在各个date上的content1和content2分别是什么
> data_bad name_id date content1 content2 1: b 2017-12-19 b_content1 banother1 2: g 2017-12-19 g_content2 ganother2 3: g 2017-12-20 g_content3 ganother3 4: g 2017-12-21 g_content4 ganother4 5: i 2017-12-19 i_content5 ianother5 6: g 2017-12-22 g_content6 ganother6 7: a 2017-12-19 a_content7 aanother7 8: c 2017-12-19 c_content8 canother8 9: g 2017-12-23 g_content9 ganother9 10: f 2017-12-19 f_content10 fanother10 11: g 2017-12-24 g_content11 ganother11 12: f 2017-12-20 f_content12 fanother12 13: c 2017-12-20 c_content13 canother13 14: j 2017-12-19 j_content14 janother14 15: c 2017-12-21 c_content15 canother15 > data_bad %>% melt(id = c('name_id', 'date')) %>% + dcast(name_id~date+variable) name_id 2017-12-19_content1 2017-12-19_content2 2017-12-20_content1 2017-12-20_content2 1: a a_content7 aanother7 NA NA 2: b b_content1 banother1 NA NA 3: c c_content8 canother8 c_content13 canother13 4: f f_content10 fanother10 f_content12 fanother12 5: g g_content2 ganother2 g_content3 ganother3 6: i i_content5 ianother5 NA NA 7: j j_content14 janother14 NA NA 2017-12-21_content1 2017-12-21_content2 2017-12-22_content1 2017-12-22_content2 1: NA NA NA NA 2: NA NA NA NA 3: c_content15 canother15 NA NA 4: NA NA NA NA 5: g_content4 ganother4 g_content6 ganother6 6: NA NA NA NA 7: NA NA NA NA 2017-12-23_content1 2017-12-23_content2 2017-12-24_content1 2017-12-24_content2 1: NA NA NA NA 2: NA NA NA NA 3: NA NA NA NA 4: NA NA NA NA 5: g_content9 ganother9 g_content11 ganother11 6: NA NA NA NA 7: NA NA NA NA
这样name_id唯一再merge到data_map表中,不会增加太多重复的行,但是这个方法也有一个很大的弊端,就是增加了太多列,产生了非常多的缺失值。
其实这种name_id不唯一的表,称为动态表;而唯一的是静态表
静态表表示这个id的静态数据,特征等,一个id就对应该指标的一个值
动态表则反映这个id的动态情况,比如哪一天这个id发生了什么,换一天又发生了什么,这样一个表就会出现多次同一个id,即name_id列有重复的内容
真正遇到这种问题时,其实没有必要非要把静态表和动态表合并在一起了,合并后数据格式都不好了,肯定也没办法分析
data.table
使用data.table运行结果和join族函数一样,所以这里只列代码
使用[]来合并,[]的在merge上的功能比较弱,而且别扭,只能做下面这些事
new <- data_map[data_good, on="card_id==object_id"] new # data_map[data_good, name_id_good:= i.name_id,on="card_id==object_id"][] # 要改名就在原数据上修改,改名没有join族函数方便 # 以data_diff为准 new[data_diff, on='name_id'] # 以new为准 data_diff[new, on='name_id']
但是[]中使用merge可以结合[]中其他位置的参数一起使用,在只需要简单merge时,可以达到多步合并为一行的简洁效果。
下面我们来看一下merge函数,data.table中的merge会比基础包中merge更快,同时更改了一些默认选项,基本使用以及参数都没有改变,这里的数据因为创建时使用的是data.table函数,所以使用merge时自动用的是data.table包中的函数
new <- merge(data_map, data_good, by.x='card_id', by.y='object_id', suffixes=c('','.good')) new # 全部保留 merge(new, data_diff, by='name_id', all=T) # 保留new的 merge(new, data_diff, by='name_id', all.x=T) # 保留data_diff的 merge(new, data_diff, by='name_id', all.y=T) # 保留交集 merge(new, data_diff, by='name_id', all=F) merge(new, data_bad, by='name_id', all.x=T) merge(new, data_bad, by='name_id', all.y=T) merge(bad1,bad2, by='name_id', all.x=T)
大家都在看
2017年R语言发展报告(国内)
精心整理 | R语言中文社区历史文章合集(作者篇)
公众号后台回复关键字即可学习
回复 爬虫 爬虫三大案例实战
回复 Python 1小时破冰入门回复 数据挖掘 R语言入门及数据挖掘
回复 人工智能 三个月入门人工智能
回复 数据分析师 数据分析师成长之路
回复 机器学习 机器学习的商业应用
回复 数据科学 数据科学实战
回复 常用算法 常用数据挖掘算法
R|数据处理|merge数据详解相关推荐
- R语言基础知识详解及概括
R语言基础知识详解及概括 目录 R语言基础知识详解及概括 R数据可视化示例 R语言进行数据创建
- IoT:大端与小端字节数据详解
大端与小端字节数据详解 转自:https://blog.csdn.net/dosthing/article/details/80641173 前言 计算机的数据以01构成的字节存储,这就涉及数据大小端 ...
- python爬取app中的音频_Python爬取喜马拉雅音频数据详解
码农公社 210.net.cn 210是何含义?10月24日是程序员节,1024 =210.210既 210 之意. Python爬取喜马拉雅音频数据详解 一.项目目标 爬取喜马拉雅音频数据 受害 ...
- python能处理nc文件吗_利用python如何处理nc数据详解
前言 这两天帮一个朋友处理了些 nc 数据,本以为很简单的事情,没想到里面涉及到了很多的细节和坑,无论是"知难行易"还是"知易行难"都不能充分的说明问题,还是& ...
- R统计绘图-PCA详解1(princomp/principal/prcomp/rda等)
此文为<精通机器学习:基于R>的学习笔记,书中第九章详细介绍了无监督学习-主成分分析(PCA)的分析过程和结果解读. PCA可以对相关变量进行归类,从而降低数据维度,提高对数据的理解.分析 ...
- python处理nc数据_利用python如何处理nc数据详解
利用python如何处理nc数据详解 来源:中文源码网 浏览: 次 日期:2018年9月2日 [下载文档: 利用python如何处理nc数据详解.txt ] (友情提示:右键点上行txt ...
- python爬取喜马拉雅_Python爬虫实战案例之爬取喜马拉雅音频数据详解
这篇文章我们来讲一下在网站建设中,Python爬虫实战案例之爬取喜马拉雅音频数据详解.本文对大家进行网站开发设计工作或者学习都有一定帮助,下面让我们进入正文. 前言 喜马拉雅是专业的音频分享平台,汇集 ...
- r语言如何读取matlab数据类型,R语言数据类型深入详解
R语言用来存储数据的对象包括: 向量, 因子, 数组, 矩阵, 数据框, 时间序列(ts)以及列表 意义介绍 1. 向量(一维数据): 只能存放同一类型的数据 语法: c(data1, data2, ...
- R语言which函数详解以及Rcpp改写
R语言which函数详解以及Rcpp的改写 引言 which 函数的介绍 which函数的一些小例子 1 2 which函数的改进以及时间对比 引言 首先来介绍一下R语言which函数的作用:whic ...
- dicom多帧转换_Python解析多帧dicom数据详解
概述 pydicom是一个常用python DICOM parser.但是,没有提供解析多帧图的示例.本文结合相关函数和DICOM知识做一个简单说明. DICOM多帧数据存储 DICOM标准中关于多帧 ...
最新文章
- 公司数据部培训讲义:ArcMap数字化培训教程
- bs4爬取的时候有两个标签相同_4.4 爬虫中的bs4数据爬取步骤
- TOMCAT startup.bat
- kettle 调用存储过程_Mysql存储过程
- 【干货】华为管理干部内部资料:华为管理者应知应会之咨询方法论.pdf(附下载链接)...
- EditPlus配置Python环境
- matlab中的turbo码,基于Matlab的Turbo码仿真研究
- 力扣-797. 所有可能的路径
- java+整合handwrite_E-signature-master
- 前端生成PDF,让后端刮目相看
- 1.12 Cubemx_STM32F4 步进电机(四)----S曲线理论
- Eslint的坑和常见报错
- 中学计算机兴趣小组 计划,陵口中学科技兴趣小组工作计划
- 幻方解法之Strachey法生成双偶幻方
- 【倾心整理】高级工程师手写总结,入门到顶级程序员的学习方法
- 数据库批量插入和存在的问题
- 如何做好数据分析报告(一)
- 问题诊断:为什么点击淘宝评价详情无法显示内容?
- USB转串口驱动应用于macbook
- 数据库的多表连接查询 emp表,dept表,salgrade表