在R中合并两个数据框时,用现有数据替换缺失值

3
我想合并两个数据框。这两个数据框有一些共同的变量和一些不同的变量,并且每个数据框中的行数也不同。这两个数据框共享一些行,但并非全部。而且两个数据框都有可能缺失另一个数据框中拥有的数据。
DF1:
姓名 年龄 体重 身高
Tim 7 54 112
Dave 5 50 NA
Larry NA 42 73
Rob 1 30 43
DF2:
姓名 年龄 体重 身高 年级
Tim 7 NA 112 2
Dave NA 50 103 1
Larry 3 NA 73 NA
Rob 1 30 NA NA
John 6 60 NA 1
Tom 8 61 112 2
我想通过共享的列(姓名、年龄、体重和身高)将这两个数据框合并在一起。但是,我希望覆盖缺失值,即如果两个数据框中有一个拥有值而另一个拥有缺失值,则将该值传递到第三个数据框中。理想情况下,当DF1和DF2在同一位置都有NA时,最后的数据框应该只有NA。
理想的数据框:
姓名 年龄 体重 身高 年级
蒂姆 7岁 54公斤 112厘米 2年级
戴夫 5岁 50公斤 103厘米 1年级
拉里 3岁 42公斤 73厘米 N/A
罗布 1岁 30公斤 43厘米 N/A
约翰 6岁 60公斤 N/A 1年级
汤姆 8岁 61公斤 112厘米 2年级

我一直在使用full_join和left_join,但我不知道如何合并它们,以便将NAs替换为实际数据(如果它存在于其中一个数据框中)。 有没有一种方法可以做到这一点?


1
这个回答解决了你的问题吗?按ID合并两个不均匀的数据框并填充缺失值 - benson23
1
你可以进行“合并连接” https://alistaire.rbind.io/blog/coalescing-joins/ - Skaqqs
如果df1和df2都包含非NA值,但不同,应该发生什么?另外,我假设“name”列包含唯一值? - Ottie
3个回答

3
这是一个dplyr中的rows_patch()可以处理的典型情况。
library(dplyr)

rows_patch(df2, df1, by = "name")

   name age weight height grade
1   Tim   7     54    112     2
2  Dave   5     50    103     1
3 Larry   3     42     73    NA
4   Rob   1     30     43    NA
5  John   6     60     NA     1
6   Tom   8     61    112     2
数据
df1 <- structure(list(name = c("Tim", "Dave", "Larry", "Rob"), age = c(7L, 
5L, NA, 1L), weight = c(54L, 50L, 42L, 30L), height = c(112L, 
NA, 73L, 43L)), class = "data.frame", row.names = c(NA, -4L))

df2 <- structure(list(name = c("Tim", "Dave", "Larry", "Rob", "John", 
"Tom"), age = c(7L, NA, 3L, 1L, 6L, 8L), weight = c(NA, 50L, 
NA, 30L, 60L, 61L), height = c(112L, 103L, 73L, NA, NA, 112L), 
grade = c(2L, 1L, NA, NA, 1L, 2L)), class = "data.frame", row.names = c(NA, -6L))

1

另一个可能的解决方案:

library(tidyverse)

df2 %>% 
  bind_rows(df1) %>% 
  group_by(name) %>% 
  fill(age:grade, .direction = "updown") %>% 
  ungroup %>% 
  distinct

#> # A tibble: 6 x 5
#>   name    age weight height grade
#>   <chr> <int>  <int>  <int> <int>
#> 1 Tim       7     54    112     2
#> 2 Dave      5     50    103     1
#> 3 Larry     3     42     73    NA
#> 4 Rob       1     30     43    NA
#> 5 John      6     60     NA     1
#> 6 Tom       8     61    112     2

0

我喜欢第一条评论中建议的powerjoin包,这是我以前从未听说过的。

然而,如果你想避免使用额外的包,你可以在基本的R语言中实现。这种方法也避免了需要显式命名每个列 - 评论中建议的dplyr方法并没有做到这一点,尽管可能可以修改。

# Load data

df1  <- read.table(text = "name age weight  height
Tim 7   54  112
Dave    5   50  NA
Larry   NA  42  73
Rob 1   30  43", header=TRUE)
df2  <- read.table(text = "name age weight  height  grade
Tim 7   NA  112 2
Dave    NA  50  103 1
Larry   3   NA  73  NA
Rob 1   30  NA  NA
John    6   60  NA  1
Tom 8   61  112 2", header=TRUE)


df3  <- merge(df1, df2, by = "name", all = TRUE, sort=FALSE)

# Coalesce the common columns
common_cols  <- names(df1)[names(df1)!="name"]
df3[common_cols]  <- lapply(common_cols, function(col) {
    coalesce(df3[[paste0(col, ".x")]], df3[[paste0(col, ".y")]])
}) 

# Select desired columns
df3[names(df2)]

#    name age weight height grade
# 1   Tim   7     54    112     2
# 2  Dave   5     50    103     1
# 3 Larry   3     42     73    NA
# 4   Rob   1     30     43    NA
# 5  John   6     60     NA     1
# 6   Tom   8     61    112     2

使用基本的R语言有其优点,但是powerjoin看起来也是一个很有趣的包。


请注意,coalesce 函数来自于 dplyr 包。 - benson23
好观点!这就是你一直加载dplyr的结果! - SamR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接