代码之家  ›  专栏  ›  技术社区  ›  Hard_Course

用另一列中的值替换行的最后一个非NA条目

  •  4
  • Hard_Course  · 技术社区  · 3 月前

    我有一个这样的数据集:

      tdf <- data.frame(
        A = c(1, 2, 5, 4),
        B = c(NA, 3, 4, 5),
        C = c(NA, NA, NA, NA),
        D = c(NA, NA, NA, NA),
        E = c(10, 20, 30, 40))
    

    我需要将最后一个从左到右的非NA值替换为另一列的值,比如E,以给出以下结果:

      enddf <- data.frame(
        A = c(10, 2, 5, 4),
        B = c(NA, 20, 30, 40),
        C = c(NA, NA, NA, NA),
        D = c(NA, NA, NA, NA),
        E = c(10, 20, 30, 40))
    
    

    我正在读取多个不同列数的dfs,所以我在考虑一个跨所有行读取但最后一行可以工作的函数?

    我试过这样的方法,但我觉得我走错了方向:

    df <- tdf %>%
        rowwise() %>%
        mutate(
          A = ifelse(is.na(A), A, ifelse(!is.na(B), C, A)),
          B = ifelse(!is.na(A) & is.na(B), C, B)
        )
    
    4 回复  |  直到 3 月前
        1
  •  6
  •   Andre Wildberg    3 月前

    A. 基数R 寻找的方法 NA 行明智与 apply .

    wcol <- ncol(tdf)
    
    data.frame(t(apply(tdf, 1, \(x) {
      x[which(is.na(x))[1] - 1] <- x[wcol]
      x
    })))
    

    输出

       A  B  C  D  E
    1 10 NA NA NA 10
    2  2 20 NA NA 20
    3  5 30 NA NA 30
    4  4 40 NA NA 40
    

    由于这些值都是数字,因此中间矩阵结果不会发生转换。

        2
  •  4
  •   Rui Barradas    3 月前

    行程编码 rle 可以给你最后一个非- NA 在每一行。加1并用作索引矩阵中的列号。

    tdf <- data.frame(
      A = c(1, 2, 5, 4),
      B = c(NA, 3, 4, 5),
      C = c(NA, NA, NA, NA),
      D = c(NA, NA, NA, NA),
      E = c(10, 20, 30, 40))
    
    inx <- apply(tdf, 1L, \(x) {
      i <- rle(is.na(x))$lengths[1L]
      ifelse(i < nrow(tdf), i, NA_integer_)
    })
    inx <- cbind(seq_len(nrow(tdf)), inx)
    tdf[inx] <- tdf$E
    tdf
    #>    A  B  C  D  E
    #> 1 10 NA NA NA 10
    #> 2  2 20 NA NA 20
    #> 3  5 30 NA NA 30
    #> 4  4 40 NA NA 40
    

    创建于2025-02-21 reprex v2.1.1

        3
  •  2
  •   ThomasIsCoding    3 月前

    您可以使用 max.col + is.na 如下图所示

    > tdf[cbind(1:nrow(tdf), max.col(is.na(tdf), "first") - 1)] <- tdf$E
    
    > tdf
       A  B  C  D  E
    1 10 NA NA NA 10
    2  2 20 NA NA 20
    3  5 30 NA NA 30
    4  4 40 NA NA 40
    
        4
  •  2
  •   tmfmnk    3 月前

    1 tidyverse 选项可以是:

    tdf %>%
     mutate(pmap_dfr(across(c(A:D, E)), 
                     ~ `[<-`(c(...), max(which(!is.na(head(c(...), -1)))), tail(c(...), 1))))
                     
       A  B  C  D  E
    1 10 NA NA NA 10
    2  2 20 NA NA 20
    3  5 30 NA NA 30
    4  4 40 NA NA 40