我有一个数据框,我想用另一个数据框(查找数据框)中的信息进行更新。
特别是,我想根据列df2$value
和id
用id2
的单元格更新df1 $ value的单元格。
df1$value
的单元格是NA
,我知道如何使用软件包data.table
但是
df1$value
的单元格不为空,则data.table仍将使用df2$value
的单元格对其进行更新。 我不要那个。我想要这样:
如果df1$value
的单元格不为空(在这种情况下,df1$id
是c
的行),请不要更新该单元格,而是创建df1的重复行,其中df1 $ value的单元格从df2$value
的单元格中获取值
我已经在网上寻找解决方案,但找不到任何解决方案。有没有办法使用tidyverse或data.table或sql-like
包轻松做到这一点?
谢谢您的帮助!
edit:我刚刚意识到,我忘了把两个数据帧中的行都设为NA的特殊情况。到目前为止,我已经收到(07/08/19 14:42
)的答复,从上一个数据帧中删除了行e
。但是我真的需要保留它!
概述:
> df1
id id2 value
1 a 1 100
2 b 2 101
3 c 3 50
4 d 4 NA
5 e 5 NA
> df2
id id2 value
1 c 3 200
2 d 4 201
3 e 5 NA
# I'd like:
> df5
id id2 value
1 a 1 100
2 b 2 101
3 c 3 50
4 c 3 200
5 d 4 201
6 e 5 NA
这是我设法解决问题的方法,但这很麻烦。
# I create the dataframes
df1 <- data.frame(id=c('a', 'b', 'c', 'd'), id2=c(1,2,3,4),value=c(100, 101, 50, NA))
df2 <- data.frame(id=c('c', 'd', 'e'),id2=c(3,4, 5), value=c(200, 201, 300))
# I first do a left_join so I'll have two value columnes: value.x and value.y
df3 <- dplyr::left_join(df1, df2, by = c("id","id2"))
# > df3
# id id2 value.x value.y
# 1 a 1 100 NA
# 2 b 2 101 NA
# 3 c 3 50 200
# 4 d 4 NA 201
# I keep only the rows in which value.x is NA, so the 4th row
df4 <- df3 %>%
filter(is.na(value.x)) %>%
dplyr::select(id, id2, value.y)
# > df4
# id id2 value.y
# 1 d 4 201
# I rename the column "value.y" to "value". (I don't do it with dplyr because the function dplyr::replace doesn't work in my R version)
colnames(df4)[colnames(df4) == "value.y"] <- "value"
# > df4
# id id2 value
# 1 d 4 201
# I update the df1 with the df4$value. This step is necessary to update only the rows of df1 in which df1$value is NA
setDT(df1)[setDT(df4), on = c("id","id2"), `:=`(value = i.value)]
# > df1
# id id2 value
# 1: a 1 100
# 2: b 2 101
# 3: c 3 50
# 4: d 4 201
# I filter only the rows in which both value.x and value.y are NAs
df3 <- as_tibble(df3) %>%
filter(!is.na(value.x), !is.na(value.y)) %>%
dplyr::select(id, id2, value.y)
# > df3
# # A tibble: 1 x 3
# id id2 value.y
# <chr> <dbl> <dbl>
# 1 c 3 200
# I rename column df3$value.y to value
colnames(df3)[colnames(df3) == "value.y"] <- "value"
# I bind by rows df1 and df3 and I order by the column id
df5 <- rbind(df1, df3) %>%
arrange(id)
# > df5
# id id2 value
# 1 a 1 100
# 2 b 2 101
# 3 c 3 50
# 4 c 3 200
# 5 d 4 201
答案 0 :(得分:3)
与data.table的左连接:
library(data.table)
setDT(df1); setDT(df2)
df2[df1, on=.(id, id2), .(value =
if (.N == 0) i.value
else na.omit(c(i.value, x.value))
), by=.EACHI]
id id2 value
1: a 1 100
2: b 2 101
3: c 3 50
4: c 3 200
5: d 4 201
工作原理:语法为x[i, on=, j, by=.EACHI]
:对i = df1
的每一行都执行j
。
在这种情况下,j = .(value = expr)
其中.()
是list()
的快捷方式,因为通常j
应该返回一个列列表。
关于表达式,.N
是为x = df2
的每一行找到的i = df1
的行数,因此,如果找不到匹配项,我们将保留{{1} };否则我们将保留两个表中的值,删除缺失的值。
dplyr方式:
i
评论。 dplyr方式有点尴尬,因为需要bind_rows(df1, semi_join(df2, df1, by=c("id", "id2"))) %>%
group_by(id, id2) %>%
do(if (nrow(.) == 1) . else na.omit(.))
# A tibble: 5 x 3
# Groups: id, id2 [4]
id id2 value
<chr> <dbl> <dbl>
1 a 1 100
2 b 2 101
3 c 3 50
4 c 3 200
5 d 4 201
来获得动态确定的行数,但是通常不鼓励do()
,并且不支持do()
和其他辅助函数。由于没有简单的半联接功能,因此data.table的方式有点尴尬。
数据:
n()
答案 1 :(得分:2)
通过基数R的另一个想法是从df2
中删除在df1
中不匹配的行,将两个数据帧按行绑定(rbind
),并省略NA,即< / p>
na.omit(rbind(df1, df2[do.call(paste, df2[1:2]) %in% do.call(paste, df1[1:2]),]))
# id id2 value
#1 a 1 100
#2 b 2 101
#3 c 3 50
#5 c 3 200
#6 d 4 201
要满足您的新要求,我们可以保留相同的rbind
方法并根据您的条件进行过滤,即
dd <- rbind(df1, df2[do.call(paste, df2[1:2]) %in% do.call(paste, df1[1:2]),])
dd[!!with(dd, ave(value, id, id2, FUN = function(i)(all(is.na(i)) & !duplicated(i)) | !is.na(i))),]
# id id2 value
#1 a 1 100
#2 b 2 101
#3 c 3 50
#5 e 5 NA
#6 c 3 200
#7 d 4 201
答案 2 :(得分:2)
使用update join然后完全外部合并的data.table的可能方法:
merge(df1[is.na(value), value := df2[.SD, on=.(id, id2), x.value]], df2, all=TRUE)
输出:
id id2 value
1: a 1 100
2: b 2 101
3: c 3 50
4: c 3 200
5: d 4 201
6: e 5 NA
数据:
library(data.table)
df1 <- data.table(id=c('a', 'b', 'c', 'd', 'e'), id2=c(1,2,3,4,5),value=c(100, 101, 50, NA, NA))
df2 <- data.table(id=c('c', 'd', 'e'), id2=c(3,4, 5), value=c(200, 201, NA))
答案 3 :(得分:1)
这是使用full_join
和gather
的一种方式
library(dplyr)
left_join(df1, df2, by = c("id","id2")) %>%
tidyr::gather(key, value, starts_with("value"), na.rm = TRUE) %>%
select(-key)
# id id2 value
#1 a 1 100
#2 b 2 101
#3 c 3 50
#7 c 3 200
#8 d 4 201
对于更新的案例,我们可以做到
left_join(df1, df2, by = c("id","id2")) %>%
tidyr::gather(key, value, starts_with("value")) %>%
group_by(id, id2) %>%
filter((all(is.na(value)) & !duplicated(value)) | !is.na(value)) %>%
select(-key)
# id id2 value
# <chr> <int> <int>
#1 a 1 100
#2 b 2 101
#3 c 3 50
#4 e 5 NA
#5 c 3 200
#6 d 4 201