【问题标题】:Replacing leading NAs by group with 0s, but Keep other NAs用 0 按组替换前导 NA,但保留其他 NA
【发布时间】:2021-11-29 14:00:27
【问题描述】:

我有一个按州分组的 COVID 数据框,有 60 列。由于 COVID 在各州的不同时间开始,因此在不同州的值之前存在 NA。不同的指标(第 9 列)也有不同的数据开始。下面是我为演示制作的示例 df。

state <- c(rep("A", 6), rep("B", 6))
time <- c(1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6)
x1 <- c(NA, NA, NA, 4, 5, 6, NA, NA, 3, 4, 5, NA)
x2 <- c(NA, 2, 3, NA, 5, 6, NA, NA, NA, 4, 5, 6)
x3 <- c(NA, NA, 3, 4, 5, NA, NA, 2, NA, 4, 5, 6)
df <- data.frame(state, time, x1, x2, x3)
df

   state time x1 x2 x3
1      A    1 NA NA NA
2      A    2 NA  2 NA
3      A    3 NA  3  3
4      A    4  4 NA  4
5      A    5  5  5  5
6      A    6  6  6 NA
7      B    1 NA NA NA
8      B    2 NA NA  2
9      B    3  3 NA NA
10     B    4  4  4  4
11     B    5  5  5  5
12     B    6 NA  6  6

我正在尝试将每个州的所有前导 NA 替换为 0,但保留其他 NA。结果应如下所示:

   state time x1 x2 x3
1      A    1  0  0  0
2      A    2  0  2  0
3      A    3  0  3  3
4      A    4  4 NA  4
5      A    5  5  5  5
6      A    6  6  6 NA
7      B    1  0  0  0
8      B    2  0  0  2
9      B    3  3  0 NA
10     B    4  4  4  4
11     B    5  5  5  5
12     B    6 NA  6  6

我想出的一个解决方案是用累积和的条件替换 NAs,如下所示:

df1 <- df %>% 
  group_by(state) %>% 
  mutate(
    check.sum1 = cumsum(replace_na(x1, 0)),
    x1 = if_else(check.sum1 != 0, x1, 0),
    check.sum2 = cumsum(replace_na(x2, 0)),
    x2 = if_else(check.sum2 != 0, x2, 0),
    check.sum3 = cumsum(replace_na(x3, 0)),
    x3 = if_else(check.sum3 != 0, x3, 0)
  )
df1

这个方法效果很好。但由于有 60 列,我想用一个函数和/或使用 apply() 来包装它。但它会发出错误消息:

df2 <- df %>% 
  group_by(state) %>% 
  apply(
    df[3:5], MARGIN = 2, FUN = function(x) mutate(
      check.sum = cumsum(replace_na(x, 0)),
      x = if_else(check.sum != 0, x, 0)
    ) 
  )

Error in FUN(newX[, i], ...) : unused argument (df[3:5])

#or
func <- function(x) {
  mutate(
    check.sum = cumsum(replace_na(x, 0)),
    x = if_else(check.sum != 0, x, 0)
  )
}

df3 <- df %>% 
  group_by(state) %>% 
  apply(
    df[3:5], MARGIN = 2, func
  )

Error in match.fun(FUN) : 
  'df[3:5]' is not a function, character or symbol

所以有三个具体问题:

  1. 如何使用列作为参数来创建用户定义的函数。
  2. 如何使用 apply() 函数。和
  3. 还有其他方法可以使用现有函数(例如 na.locf() 或 na.trim())来完成这项工作吗?

谢谢!

【问题讨论】:

    标签: r apply user-defined-functions lapply na


    【解决方案1】:

    使用by 并查看is.na 列的位置 NA 没有重复,即布尔值differences 小于或等于零。

    do.call(rbind, by(df, df$state, \(x) {
      x[] <- lapply(x, \(z) {z[is.na(z) & c(0, diff(is.na(z))) <= 0] <- 0; z})
      return(x)
    }))
    #      state time x1 x2 x3
    # A.1      A    1  0  0  0
    # A.2      A    2  0  2  0
    # A.3      A    3  0  3  3
    # A.4      A    4  4 NA  4
    # A.5      A    5  5  5  5
    # A.6      A    6  6  6 NA
    # B.7      B    1  0  0  0
    # B.8      B    2  0  0  2
    # B.9      B    3  3  0 NA
    # B.10     B    4  4  4  4
    # B.11     B    5  5  5  5
    # B.12     B    6 NA  6  6
    

    注意:请使用更新R>=4.1\(x) 函数简写符号或写function(x)

    【讨论】:

      【解决方案2】:

      使用dplyr,我们可以做到

      library(dplyr)
      df %>%
          group_by(state) %>% 
          mutate(across(starts_with('x'), ~ replace(., !cumsum(!is.na(.)), 0))) %>% 
          ungroup
      # A tibble: 12 × 5
         state  time    x1    x2    x3
         <chr> <dbl> <dbl> <dbl> <dbl>
       1 A         1     0     0     0
       2 A         2     0     2     0
       3 A         3     0     3     3
       4 A         4     4    NA     4
       5 A         5     5     5     5
       6 A         6     6     6    NA
       7 B         1     0     0     0
       8 B         2     0     0     2
       9 B         3     3     0    NA
      10 B         4     4     4     4
      11 B         5     5     5     5
      12 B         6    NA     6     6
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-22
        • 2014-02-08
        • 1970-01-01
        • 2014-11-30
        • 1970-01-01
        • 2023-03-13
        • 2020-01-14
        • 1970-01-01
        相关资源
        最近更新 更多