如果缺少的列少于 x 列,则替换缺失值

Replace missing values if fewer than x columns missing

提问人:Sam 提问时间:5/18/2023 最后编辑:Darren TsaiSam 更新时间:5/23/2023 访问量:89

问:

我想仅将列中缺失值少于 2 个的行替换为零。然后我想重新计算总和列(我可以很高兴地按照我的 reprex 使用)。var1:var6var1:var6rowwise()

我已经尝试了一些使用 ,或者 和 但正在努力寻找解决方案。across()rowwise()c_across()

library(tidyverse)

# Generate data
set.seed(40)
dat <- tibble(
  id = 1:6,
  var1 = sample(c(0:4, NA), 6, replace = TRUE),
  var2 = sample(c(0:4, NA), 6, replace = TRUE),
  var3 = sample(c(0:4, NA), 6, replace = TRUE),
  var4 = sample(c(0:4, NA), 6, replace = TRUE),
  var5 = sample(c(0:4, NA), 6, replace = TRUE),
  var6 = sample(c(0:4, NA), 6, replace = TRUE),
)

dat %>%
  rowwise() %>%
  mutate(sum = sum(c_across(var1:var6))) %>%
  ungroup()

这是当前的 tibble:

> dat
# A tibble: 6 × 8
     id  var1  var2  var3  var4  var5  var6   sum
  <int> <int> <int> <int> <int> <int> <int> <int>
1     1     3     4     4    NA    NA     2    NA
2     2    NA    NA     4     3     4     2    NA
3     3     4     4     1     1     4     1    15
4     4     1     2     4     4     4    NA    NA
5     5     2     1     4     4    NA     2    NA
6     6     1     3     1     0     0     4     9

我希望输出如下所示:

> new_dat
# A tibble: 6 × 8
     id  var1  var2  var3  var4  var5  var6   sum
  <int> <int> <int> <int> <int> <int> <int> <int>
1     1     3     4     4    NA    NA     2    NA
2     2    NA    NA     4     3     4     2    NA
3     3     4     4     1     1     4     1    15
4     4     1     2     4     4     4     0    15
5     5     2     1     4     4     0     2    13
6     6     1     3     1     0     0     4     9
r dplyr 缺失数据

评论


答:

5赞 Maël 5/18/2023 #1

您可以像这样使用:across

dat %>% 
  mutate(across(var1:var6, ~ replace(.x, is.na(.x) & rowSums(is.na(across(var1:var6))) < 2, 0)),
         sum = rowSums(across(var1:var6)))

# # A tibble: 6 × 8
#      id  var1  var2  var3  var4  var5  var6   sum
#   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1     1     3     4     4    NA    NA     2    NA
# 2     2    NA    NA     4     3     4     2    NA
# 3     3     4     4     1     1     4     1    15
# 4     4     1     2     4     4     4     0    15
# 5     5     2     1     4     4     0     2    13
# 6     6     1     3     1     0     0     4     9
3赞 Darren Tsai 5/18/2023 #2

若要使用 对代码进行最小程度的调整,可以将参数设置为灵活的逻辑值,以指示该行的缺失值是否少于 2。rowwise()na.rmsum()

dat %>%
  rowwise() %>%
  mutate(sum = c_across(var1:var6) %>% sum(na.rm = sum(is.na(.)) < 2)) %>%
  ungroup()

# # A tibble: 6 × 8
#      id  var1  var2  var3  var4  var5  var6   sum
#   <int> <int> <int> <int> <int> <int> <int> <int>
# 1     1     3     4     4    NA    NA     2    NA
# 2     2    NA    NA     4     3     4     2    NA
# 3     3     4     4     1     1     4     1    15
# 4     4     1     2     4     4     4    NA    15
# 5     5     2     1     4     4    NA     2    13
# 6     6     1     3     1     0     0     4     9

评论

1赞 Maël 5/18/2023
哇,不知道这个招数!我一定会把它添加到我的日常生活中na.rm
0赞 zx8754 5/18/2023
我认为您需要在第 4 行和第 5 行将 NA 转换为 0。
0赞 Sam 5/18/2023
很棒的技巧,也奏效了。我接受了 Maël 的回答,因为它最适合我的其余部分。但是你的回答很优雅!
0赞 diomedesdata 5/18/2023
我真的很困惑是什么在这里扮演了第一个论点的角色。来自其他任何人的文档:......如果占位符仅在嵌套函数调用中使用,则 LHS 也将作为第一个参数放置!这样做的原因是,在大多数用例中,这会生成最易读的代码。例如,相当于但稍微紧凑一些。sumiris %>% subset(1:nrow(.) %% 2 == 0)iris %>% subset(., 1:nrow(.) %% 2 == 0)
2赞 zx8754 5/18/2023 #3

基本替代方案,如果 NA 最多出现一次,则将 NA 转换为 0。然后像往常一样获取 rowSums:

cc <- grep("^var", colnames(dat), value = TRUE)
rr <- which(rowSums(is.na(dat[ cc ])) < 2)
dat[ rr, cc ][ is.na(dat[ rr, cc ]) ] <- 0

dat$sum <- rowSums(dat[ cc ])
#   id var1 var2 var3 var4 var5 var6 sum
# 1  1    3    4    4   NA   NA    2  NA
# 2  2   NA   NA    4    3    4    2  NA
# 3  3    4    4    1    1    4    1  15
# 4  4    1    2    4    4    4    0  15
# 5  5    2    1    4    4    0    2  13
# 6  6    1    3    1    0    0    4   9