R 使用另一个表中的数据连接并覆盖一个表中的数据

R 使用另一个表中的数据连接并覆盖一个表中的数据,r,data.table,overwrite,R,Data.table,Overwrite,如何连接和覆盖数据似乎是一个常见的要求,但我还没有找到一个适用于整个数据集的优雅解决方案 (注意:为了简化数据,对于值和一小部分列,我只使用1s和NAs,但实际上我有数百个具有不同值的列) 我有一个数据表(d1),在某些列和行中有NA值 library(data.table) d1 = fread( "r id v1 v2 v3 1 A 1 1 1 2 B 1 1 1 3 C 1 NA NA 4 D 1 1 NA 5 E 1 NA 1")[, r := NULL]

如何连接和覆盖数据似乎是一个常见的要求,但我还没有找到一个适用于整个数据集的优雅解决方案

(注意:为了简化数据,对于值和一小部分列,我只使用1s和NAs,但实际上我有数百个具有不同值的列)

我有一个数据表(d1),在某些列和行中有NA值

library(data.table)
d1 = fread(
"r id v1 v2 v3
1  A  1  1  1
2  B  1  1  1
3  C  1 NA NA
4  D  1  1 NA
5  E  1 NA  1")[, r := NULL]
我还有另一个数据表(d2),它由附加列以及d1中现有列缺少的数据点组成

d2 = fread(
"r id v2 v3 v4 v5
1  C  1  1  1  1
2  D  1  1  1  1
3  E  1  1  1  1")[, r := NULL ]
我希望基本上用d2中的所有数据连接并覆盖d1,当然要确保按id匹配行,按名称匹配列,如下所示

> d12
  id v1 v2 v3 v4 v5
1  A  1  1  1 NA NA
2  B  1  1  1 NA NA
3  C  1  1  1  1  1
4  D  1  1  1  1  1
5  E  1  1  1  1  1
其他场景:如果您只想更新d1中的NA值,也就是说,确保不覆盖现有的非NA值,那么我还想知道如何做到这一点。(为了使其更易于可视化,我添加了同时包含1和0的新表)

例如,如果我们有d3

d3 = fread(
"r id v1 v2 v3
1  A  1  1  1
2  B  1  1  1
3  C  1  0 NA
4  D  1  1  0
5  E  1 NA  1")[, r := NULL ]
我们希望加入d2并仅覆盖NAs以获得:

> d32
  id v1 v2 v3 v4 v5
1  A  1  1  1 NA NA
2  B  1  1  1 NA NA
3  C  1  0  1  1  1
4  D  1  1  0  1  1
5  E  1  1  1  1  1
仅供参考,下面是一些其他帖子,解决了这个问题,但只针对一个或两个专栏。我正在寻找的解决方案应该允许一个表中的数据被另一个表中的许多列(如果不是所有列的话)覆盖

首选基于数据表的解决方案,但也欢迎其他解决方案

库(“dplyr”)
library("dplyr")

d12 <- anti_join(d1, d2, by = "id") %>%
         bind_rows(d2)
d12% 绑定行(d2)
此解决方案从
d1
中获取不在
d2
中的行,然后将
d2
行添加到这些行中


这对“附加场景”不起作用,它看起来更混乱,可能应该是一个单独的问题。

以下是评论中@Frank的解决方案。(注:d1和d2需要先定义为数据表)

正如他所指出的,我在下面提供的原始解决方案一般来说是个坏主意。如果ID出现多次或以不同的顺序出现,它将做错误的事情


d1[d1$id%in%d2$id,names(d2):=d2]

我认为最容易使用长格式:

md1 = melt(d2, id="id")
md2 = melt(d2, id="id")
然后可以将它们堆叠起来,并获取最新的值:

res1 = unique(rbind(md1, md2), by=c("id", "variable"), fromLast=TRUE)
我还想知道,如果您只想更新[
d3
]中的NA值,也就是说,确保现有的非NA值不会被覆盖,那么如何才能做到这一点

如果行出现在
md3
中,则可以从更新表
md2
中排除行:

md3 = melt(d3, id="id")

res3 = unique(rbind(md3, md2[!md3, on=.(id, variable)]), 
  by=c("id", "variable"), fromLast=TRUE)   

dcast
可用于在必要时返回到宽格式,例如,
dcast(res3,id~…)

是否为
by=“id”
?这不起作用,因为行绑定会导致数据不完整。一般来说,这是个坏主意。如果ID出现多次或以不同的顺序出现,它将做错误的事情。相反,我认为连接应该可以工作:
cols=setdiff(intersect(names(d1),names(d2)),“id”);d1[d2,on=(id),(cols):=mget(paste0(“i.”,cols))]
。我将此作为评论发布,因为它与您的答案基本相同,如果您愿意,您可以在中进行编辑。弗兰克,我欢迎您(或任何其他人)也尝试一下其他场景,您希望覆盖数据,但NAs可能会取代非NA值的情况除外。在我链接的帖子中有一些data.table解决方案,我希望可以应用于多个列(即所有正在更新的列)。我不确定我是否理解您描述的场景。我想,一种不覆盖NAs的粗略方法是使用
replace
ifelse
。你可以发布一个新问题。对不起,我不够清楚。在现已编辑的OP中,我描述了第二个场景,您不希望覆盖现有的非NA数据。我觉得这篇文章是解决这两种情况的好地方,一种是所有数据都应该被覆盖,另一种是只有NA数据应该被覆盖。这种方法很有趣,而且效果很好。但是,融化将所有数据强制为一种类型,因此如果同时具有字符和整数数据,则会产生问题(我承认我的示例过于简化)。我会在每一步的末尾添加decast,因为这是最终数据的外观(即,宽格式是原始格式)。
md3 = melt(d3, id="id")

res3 = unique(rbind(md3, md2[!md3, on=.(id, variable)]), 
  by=c("id", "variable"), fromLast=TRUE)