【问题标题】:replace certain values in df according to several conditions根据几个条件替换 df 中的某些值
【发布时间】:2020-03-12 20:24:24
【问题描述】:

基本问题,但我正在寻找一个很好的解决方案(不是循环),如果满足几个条件,则通过 DF2 的值在 DF1 中进行条件替换:

DF1
Name  Year   Val1
A    2010     x1
A    2012     x2
B    2012     x3
C    2015     x4
C    2012     x5
DF2
Name  Year   Val1
A    2012     y1
B    2012     y2
C    2012     y3

如果 Year 是某个值,例如在这种情况下为 2012,并且 DF1 和 DF2 的名称相同,则将 Val1 从 DF2 分配给 DF1。

我尝试了几件事: DF1$Val1[DF1$Year=="2012"&DF1$Name==DF2$Name,] <-DF2$Val1 DF1$Val1<-replace(DF1$Val1, DF1$Year=="2012" & DF1$Name==DF2$Name, DF2$Val1)

但不幸的是,我收到了一个错误,因为 DF1 和 DF2 的长度不同。

预期:

DF1
Name  Year   Val1
A    2010     x1
A    2012     y1
B    2012     y2
C    2015     x4
C    2012     y3

感谢您的帮助!

【问题讨论】:

  • 抱歉完全忘记了!我编辑了我的问题。

标签: r database merge


【解决方案1】:

我们可以使用 on 与 data.table 的列连接并更新“Val”

librar(data.table)
setDT(DF1)[DF2, Val1 := i.Val1, on = .(Name, Year)]
DF1
#   Name Year Val1
#1:    A 2010   x1
#2:    A 2012   y1
#3:    B 2012   y2
#4:    C 2015   x4
#5:    C 2012   y3

数据

DF1 <- structure(list(Name = c("A", "A", "B", "C", "C"), Year = c(2010L, 
2012L, 2012L, 2015L, 2012L), Val1 = c("x1", "x2", "x3", "x4", 
"x5")), class = "data.frame", row.names = c(NA, -5L))

DF2 <- structure(list(Name = c("A", "B", "C"), Year = c(2012L, 2012L, 
2012L), Val1 = c("y1", "y2", "y3")), class = "data.frame", row.names = c(NA, 
-3L))

【讨论】:

  • 这会忽略所有 DF1 的值,如果它们在 DF2 中,即使 NA 也是如此。如果 DF2 中的 Val1 是 NA,我不想将其加入我的新 DF
【解决方案2】:

我认为最简单的方法是过滤 DF2,然后将其附加到 DF1。

所以

    DF2 <- dplyr::filter(DF2, Year==2012,
                     Name %in% unique(DF1$Name)
    DF1 <- dplyr::bind_rows(DF1, DF2)

【讨论】:

    【解决方案3】:

    这里有两个基本的 R 解决方案。

    - 使用match:

    inds <- match(data.frame(t(DF2[-3]),stringsAsFactors = FALSE),
                  data.frame(t(DF1[-3]),stringsAsFactors = FALSE))
    DF1$Val1[inds] <- DF2$Val1
    

    这样

    > DF1
      Name Year Val1
    1    A 2010   x1
    2    A 2012   y1
    3    B 2012   y2
    4    C 2015   x4
    5    C 2012   y3
    

    - 使用merge + subset:

    DF1 <- subset(within(merge(DF1,DF2,by=c("Name","Year"),all.x = TRUE), 
                         Val1 <- ifelse(is.na(Val1.y),Val1.x,Val1.y)),
                  select = names(DF1))
    

    这样

    > DF1
      Name Year Val1
    1    A 2010   x1
    2    A 2012   y1
    3    B 2012   y2
    4    C 2012   y3
    5    C 2015   x4
    

    【讨论】:

      【解决方案4】:

      我们可以在 Name 和 Year 上使用 left_join df1 和 df2 并使用 coalesce 从两个 Val1 列中选择非 NA 值。

      library(dplyr)
      
      DF1 %>%
        left_join(DF2, by = c('Name', 'Year')) %>%
        mutate(Val1 = coalesce(Val1.y, Val1.x)) %>%
        select(names(df1))
      
      #  Name Year Val1
      #1    A 2010   x1
      #2    A 2012   y1
      #3    B 2012   y2
      #4    C 2015   x4
      #5    C 2012   y3
      

      【讨论】:

      • 这是否意味着,如果DF1中的Val1为NA,它将被DF2中的Val1替换,否则不会被替换?
      • @antonina 不,现在在当前代码中优先使用DF2,如果Val1 存在于DF2 中,它将采用它的值或从DF1 中采用Val1。如果需要,也可以通过将coalesce 中的参数更改为coalesce(Val1.x, Val1.y) 以优先考虑DF1 来更改此设置。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      • 2022-01-19
      • 1970-01-01
      • 2018-10-29
      • 1970-01-01
      相关资源
      最近更新 更多