我试图弄清楚如何通过匹配其中一个列的值将一个数据框中的行替换为另一个。两个数据框具有相同的列名。
例如:
df1 <- data.frame(x = c(1,2,3,4), y = c("a", "b", "c", "d"))
df2 <- data.frame(x = c(1,2), y = c("f", "g"))
是否可以用共享相同x变量的df2中的同一行替换df1中的行?看起来像这样。
data.frame(x = c(1,2,3,4), y = c("f","g","c","d")
我已经研究了一段时间了,这是我最近得到的-
df1[which(df1$x %in% df2$x),]$y <- df2[which(df1$x %in% df2$x),]$y
但是它只是将值替换为NA。
有人知道怎么做吗?
答案 0 :(得分:3)
我们可以使用match
。 :
inds <- match(df1$x, df2$x)
df1$y[!is.na(inds)] <- df2$y[na.omit(inds)]
df1
# x y
#1 1 f
#2 2 g
#3 3 c
#4 4 d
答案 1 :(得分:3)
首先,在制作可直接复制粘贴的可复制示例方面做得很好。这总是有帮助的,特别是带有预期输出的示例。好人!
您有几种选择,但是让我们看看为什么您的解决方案不能正常工作:
首先,我尝试将您的最后一行复制粘贴到新会话中,并得到了可怕的因数错误:
Warning message:
In `[<-.factor`(`*tmp*`, iseq, value = 1:2) :
invalid factor level, NA generated
如果我们使用df1
函数查看您的数据框df2
和str
,您会发现它们不包含文本,而是 factors 。这些不是文本-简而言之,它们代表分类数据(男性对女性,分数A,B,C,D和F等),并且实际上是带有文本作为标签的整数。所以这可能是您的问题。
运行代码会发出警告,因为您试图将不存在的新因素(标签)导入df1
中。而且R不知道如何处理它们,因此仅插入NA
值。
正如r2evens回答的那样,他使用stringsAsFactors
禁用使用字符串作为因子-您甚至可以使用options(stringsAsFactors=FALSE)
在整个会话范围内禁用它(我听说过)将在即将发布的R4.0中默认禁用-是的。)
禁用stringsAsFactors
后,您的代码可以正常工作-还是可以?试试看这个尺寸:
df2 <- df2[c(2,1),]
df1[which(df1$x %in% df2$x),]$y <- df2[which(df1$x %in% df2$x),]$y
df1
中现在有什么?不太正确了。
在第一行中,我交换了df2
中的两行,然后瞧瞧,交换了df1
中的替换值。为什么呢?
让我们解构您的声明df2[which(df1$x %in% df2$x),]$y
调用df1$x %in% df2$x
返回一个逻辑向量(布尔值),其中在df1$x
中找到df2
中的元素-即前两个,后两个 not 。但这与第一个向量中的哪个位置与第二个向量中的哪个位置无关。
调用which(df1$x %in% df2$x)
然后减少索引为TRUE
的逻辑向量。再次,我们现在不与哪个元素相对应。
对于解决方案,我建议使用r2evans,因为它不依赖于额外的软件包(尽管data.table
或dplyr
是两个功能强大的软件包)。
在他的解决方案中,他使用merge
执行“完全连接”,该连接根据值而不是-嗯,根据您的操作来匹配行。借助transform
,他在从第一个参数调用的merge
函数返回的data.frame上下文的 上下文中分配了新变量。
答案 2 :(得分:2)
我认为您需要的是“合并”或“加入”操作。
(我将stringsAsFactors=FALSE
添加到框架中,以便合并和以后的工作没有任何问题,因为factor
有时会造成破坏。)
基本R:
df1 <- data.frame(x = c(1,2,3,4), y = c("a", "b", "c", "d"), stringsAsFactors = FALSE)
# df2 <- data.frame(x = c(1,2), y = c("f", "g"), stringsAsFactors = FALSE)
merge(df1, df2, by = "x", all = TRUE)
# x y.x y.y
# 1 1 a f
# 2 2 b g
# 3 3 c <NA>
# 4 4 d <NA>
transform(merge(df1, df2, by = "x", all = TRUE), y = ifelse(is.na(y.y), y.x, y.y))
# x y.x y.y y
# 1 1 a f f
# 2 2 b g g
# 3 3 c <NA> c
# 4 4 d <NA> d
transform(merge(df1, df2, by = "x", all = TRUE), y = ifelse(is.na(y.y), y.x, y.y), y.x = NULL, y.y = NULL)
# x y
# 1 1 f
# 2 2 g
# 3 3 c
# 4 4 d
Dplyr:
library(dplyr)
full_join(df1, df2, by = "x") %>%
mutate(y = coalesce(y.y, y.x)) %>%
select(-y.x, -y.y)
# x y
# 1 1 f
# 2 2 g
# 3 3 c
# 4 4 d
答案 3 :(得分:2)
带有data.table
的联接选项,其中我们将on
联接到'x'列,并用{{将第二个数据集(i.y
)中的y值分配给第一个1}}
:=
注意:最好使用library(data.table)
setDT(df1)[df2, y := i.y, on = .(x)]
(在stringsAsFactors = FALSE
中-尽管默认情况下是这样),否则我们需要在两个数据集中都使用所有R 4.0.0
公用