首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异构data.frames合并

异构data.frames合并
EN

Stack Overflow用户
提问于 2018-09-24 09:34:32
回答 5查看 303关注 0票数 2

我试图在R中合并两个data.frames

代码语言:javascript
复制
d1 <- data.frame(Id=1:3,Name=c("Yann","Anne","Sabri"),Age=c(21,19,31),Height=c(178,169,192),Grade=c(15,12,18))
d2 <- data.frame(Id=c(1,3,4),Name=c("Yann","Sabri","Jui"),Age=c(28,21,15),Sex=c("M","M","F"),City=c("Paris","Paris","Toulouse"))

我想通过Id合并,只保留IdNameAgeSexGrade列在最后的data.frame中。

我已经想出了一个很长的代码来完成这项工作,但是还有更好的方法吗?

代码语言:javascript
复制
dm <- data.frame(Id=unique(c(d1$Id,d2$Id)))
dm.d1.rows <- sapply(dm$Id, match, table = d1$Id)
dm.d2.rows <- sapply(dm$Id, match, table = d2$Id)
for(i in c("Name", "Age","Sex","Grade")) {
    if(i %in% colnames(d1) && is.factor(d1[[i]]) || i %in% colnames(d2) && is.factor(d2[[i]])) dm[[i]]<- factor(rep(NA,nrow(dm)),
            levels=unique(c(levels(d1[[i]]),levels(d2[[i]]))))
    else dm[[i]]<- rep(NA,nrow(dm))
    if(i %in% colnames(d1)) dm[[i]][!is.na(dm.d1.rows)] <- d1[[i]][na.exclude(dm.d1.rows)]
    if(i %in% colnames(d2)) dm[[i]][!is.na(dm.d2.rows)] <- d2[[i]][na.exclude(dm.d2.rows)]
}
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2018-09-24 09:55:46

下面是通过潮间带使用coalesce函数的一个想法。该函数基本上将NA值替换为另一个(指定的)列的值。-您可以找到更多关于函数coalesce 这里的信息和实现

给出一组向量的coalesce**:**的官方文档,()在每个位置找到第一个不丢失的值。这是由函数激发的,它为NULL做了同样的事情。

代码语言:javascript
复制
library(tidyverse)

d1 %>% 
 full_join(d2, by = c('Id', 'Name')) %>% 
 mutate(Age = coalesce(Age.x, Age.y)) %>% 
 select(Id, Name, Age, Sex, Grade)

这给了,

姓名、年龄、性别、级别1延恩21男15 2安妮19 12 3 3萨布里31 4 4瑞15女性

类似地,在data.table语法中,

代码语言:javascript
复制
library(data.table)

#Convert to data.tables
d1_t <- setDT(d1)
d2_t <- setDT(d2)

merge(d1_t, d2_t, by = c('Id', 'Name'), all = TRUE)[,
            Age := ifelse(is.na(Age.x), Age.y, Age.x)][, 
              c('Age.x', 'Age.y', 'City', 'Height') := NULL][]

这给了,

Id Name Grade Sex Age 1: 1 Yann 15 M 21 2: 2 Anne 12 <NA> 19 3: 3 Sabri 18 M 31 4: 4 Jui NA F 15

票数 5
EN

Stack Overflow用户

发布于 2018-09-24 10:08:07

就我个人而言,我非常喜欢sqldf,它允许您使用SQL查询来创建/操作数据框架。在您的例子中,下面的语句应该能做到这一点。

代码语言:javascript
复制
d1 <- data.frame(Id=1:3,Name=c("Yann","Anne","Sabri"),Age=c(21,19,31),
    Height=c(178,169,192),Grade=c(15,12,18))
d2 <- data.frame(Id=c(1,3,4),Name=c("Yann","Sabri","Jui"),Age=c(28,21,15),
    Sex=c("M","M","F"),City=c("Paris","Paris","Toulouse"))

d3 = sqldf("SELECT d1.Id, d1.Name, d1.Age, d2.Sex , d1.Grade
            FROM d1
            LEFT JOIN d2 ON d1.Id = d2.Id
            UNION
            SELECT d2.Id, d2.Name, coalesce(d1.Age, d2.Age) , d2.Sex, coalesce(d1.Grade, NULL)
            FROM d2 
            LEFT JOIN d1 ON d2.Id = d1.Id")

特别是对于更复杂的数据合并/操作,使用sqldf/SQL是很有用的。

编辑:使用工作的sqldf /R环境来修复SQL语句,导致下表:

代码语言:javascript
复制
Id  Name Age  Sex Grade
1  Yann  21    M    15
2  Anne  19 <NA>    12
3 Sabri  31    M    18
4   Jui  15    F    NA
票数 2
EN

Stack Overflow用户

发布于 2018-09-26 22:37:45

在基数R中:

代码语言:javascript
复制
d1 <- data.frame(Id=1:3,Name=c("Yann","Anne","Sabri"),Age=c(21,19,31),Height=c(178,169,192),Grade=c(15,12,18),stringsAsFactors = F)
d2 <- data.frame(Id=c(1,3,4),Name=c("Yann","Sabri","Jui"),Age=c(28,21,15),Sex=c("M","M","F"),City=c("Paris","Paris","Toulouse"),stringsAsFactors = F)
nms <- c("Id","Name", "Age", "Sex", "Grade")

. <- merge(d2,d1,all=TRUE,sort=FALSE)[nms]
aggregate(.,list(.$Id), function(x) c(na.omit(x),NA)[1])[-1]
#   Id  Name Age  Sex Grade
# 1  1  Yann  28    M    15
# 2  2  Anne  19 <NA>    12
# 3  3 Sabri  21    M    18
# 4  4   Jui  15    F    NA

注意,在应用此解决方案之前,您需要将因素转换为字符。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52476396

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档