基于dataframe2的列更新dataframe1的列,如果column1不为空,则创建新行

基于dataframe2的列更新dataframe1的列,如果column1不为空,则创建新行,r,dataframe,dplyr,data.table,R,Dataframe,Dplyr,Data.table,我有一个数据帧,我想用另一个数据帧(查找数据帧)的信息更新它 特别是,我想根据列id和id2将df1$value的单元格更新为df2$value的单元格 如果df1$value的单元格是NA,我知道如何使用package data.table来完成它 但是 如果df1$value的单元格不为空,data.table仍将使用df2$value的单元格对其进行更新。 我不想那样。我想要这个: 如果df1$value的单元格在这种情况下不是空的,则df1$id为c的行不更新该单元格,而是创建一个重复的

我有一个数据帧,我想用另一个数据帧(查找数据帧)的信息更新它

特别是,我想根据列id和id2将df1$value的单元格更新为df2$value的单元格

如果df1$value的单元格是NA,我知道如何使用package data.table来完成它 但是

如果df1$value的单元格不为空,data.table仍将使用df2$value的单元格对其进行更新。 我不想那样。我想要这个:

如果df1$value的单元格在这种情况下不是空的,则df1$id为c的行不更新该单元格,而是创建一个重复的df1行,其中df1$value的单元格从df2$value的单元格中获取值

我已经在网上寻找了解决方案,但没有找到。有没有一种方法可以轻松地使用tidyverse、data.table或类似sql的包来实现这一点

谢谢你的帮助

编辑:我刚刚意识到我忘了把两个数据帧中的行都是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
这里有一种使用完全联接和聚集的方法

对于更新的案例,我们可以这样做

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

通过base R的另一个想法是从df2中删除在df1中不匹配的行,将两个数据帧按行rbind绑定,并省略NAs,即

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

具有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 do j的每一行

在这种情况下,j=.value=expr,其中。是列表的快捷方式,因为通常j应该返回列列表

关于表达式,.N是为i=df1的每一行找到的x=df2的行数,因此如果没有找到匹配项,则保留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

使用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
数据:


谢谢你,我没想过要那样做!但我必须指出,我不希望df2的行与df1不匹配。因此,在这种情况下,我需要使用left_-join来代替full_-join:亲爱的Ronak。我刚刚意识到我忘了在代码中放一个角盒,现在我又被卡住了。请你看看我编辑的问题好吗?亲爱的索托斯,谢谢你的回答。我刚刚意识到我忘了在代码中放一个角盒,现在我又被卡住了。请您看看我编辑的问题好吗根据您的新条件进行编辑
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))