使用 dplyr 在缺失值中创建行式条件

Using dplyr to make row wise conditions amidst missing values

我有一个大型数据集,包含个人、他们的年龄以及 5 项测试的分数和一些缺失数据。数据集如下所示:

id<-c(1, 2, 3, 4, 5, 6, 7)
age<-c(25, 43, 55, 12, 15, 67, 71)
score1<-c(1, 2, 1, 2, 1, 2, 2)
score2<-c(5, NA, NA, 5, 6, 7, 5)
score3<-c(NA, NA, NA, NA, 6, 7, 6)
score4<-c( 5, NA, NA, NA, NA, 6, NA)
score5<-c(5, 5, 4, 4, 5, 5, NA)
df<-data.frame(id, age, score1, score2, score3, score4, score5)
df
  id age score1 score2 score3 score4 score5
1  1  25      1      5     NA      5      5
2  2  43      2     NA     NA     NA      5
3  3  55      1     NA     NA     NA      4
4  4  12      2      5     NA     NA      4
5  5  15      1      6      6     NA      5
6  6  67      2      7      7      6      5
7  7  71      2      5      6     NA     NA

对于分数 2-5,我想创建一个 Missing 条件,如果每个 id 在分数 2-5 中的缺失数据 (NA) 超过 30%,则 Missing=是 否则 Missing=否

所需的输出应如下所示:

  id age score1 score2 score3 score4 score5 missing
1  1  25      1      5     NA      5      5      no
2  2  43      2     NA     NA     NA      5     yes
3  3  55      1     NA     NA     NA      4     yes
4  4  12      2      5     NA     NA      4     yes
5  5  15      1      6      6     NA      5      no
6  6  67      2      7      7      6      5      no
7  7  71      2      5      6     NA     NA     yes

在 dplyr 中创建按行条件的最佳方法是什么?我尝试在 df %>% rowwise() %>% missing=ifelse(sum(is.na(.x))/length(.x)* 100 >=30), "yes", "no") 中使用 dplyr::mutateifelse,但我认为这是错误的并且似乎不起作用。

df %>%
rowwise %>%
mutate(missing=ifelse(mean(is.na(across(score2:score5)))>0.3,'yes','no')) %>% 
ungroup

输出;

    id   age score1 score2 score3 score4 score5 missing
  <dbl> <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <chr>  
1     1    25      1      5     NA      5      5 no     
2     2    43      2     NA     NA     NA      5 yes    
3     3    55      1     NA     NA     NA      4 yes    
4     4    12      2      5     NA     NA      4 yes    
5     5    15      1      6      6     NA      5 no     
6     6    67      2      7      7      6      5 no     
7     7    71      2      5      6     NA     NA yes    

我们可以使用rowMeans(condition)。我建议您在这里使用 num_range 选择,它非常适合您的列选择语句。

df %>% mutate(missing=ifelse(rowMeans(across(num_range('score', 2:5), is.na))>0.3, 'yes', 'no'))

  id age score1 score2 score3 score4 score5 missing
1  1  25      1      5     NA      5      5      no
2  2  43      2     NA     NA     NA      5     yes
3  3  55      1     NA     NA     NA      4     yes
4  4  12      2      5     NA     NA      4     yes
5  5  15      1      6      6     NA      5      no
6  6  67      2      7      7      6      5      no
7  7  71      2      5      6     NA     NA     yes

(我的建议与 GuedesBF 提供的几乎相同,但是当我点击“Post”时我没有看到它。为了基准和讨论。)

不使用 rowwise 的替代方案。

df %>%
  mutate(Missing = rowMeans(is.na(subset(., select=score2:score5))) > 0.3)
#   id age score1 score2 score3 score4 score5 Missing
# 1  1  25      1      5     NA      5      5   FALSE
# 2  2  43      2     NA     NA     NA      5    TRUE
# 3  3  55      1     NA     NA     NA      4    TRUE
# 4  4  12      2      5     NA     NA      4    TRUE
# 5  5  15      1      6      6     NA      5   FALSE
# 6  6  67      2      7      7      6      5   FALSE
# 7  7  71      2      5      6     NA     NA    TRUE

优点是性能。一般来说,按行操作会比较慢,如果您的数据显着大,那么这可能是个问题。

bench::mark(
  rowwise = df %>% rowwise() %>% mutate(missing=mean(is.na(across(score2:score5)))>0.3) %>% ungroup(), 
  rowMeans = df %>% mutate(Missing = rowMeans(is.na(subset(., select=score2:score5))) > 0.3),
  guedes = df %>% mutate(missing=rowMeans(across(num_range('score', 2:5), is.na))>0.3),
  check=FALSE)
# # A tibble: 3 x 13
#   expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result memory                  time           gc                
#   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list> <list>                  <list>         <list>            
# 1 rowwise      5.91ms   6.61ms      146.   10.05KB     0       74     0      507ms <NULL> <Rprofmem[,3] [21 x 3]> <bch:tm [74]>  <tibble [74 x 3]> 
# 2 rowMeans      1.7ms      2ms      439.    1.64KB     2.30   191     1      435ms <NULL> <Rprofmem[,3] [4 x 3]>  <bch:tm [192]> <tibble [192 x 3]>
# 3 guedes       2.97ms   3.44ms      272.   13.24KB     0      137     0      503ms <NULL> <Rprofmem[,3] [21 x 3]> <bch:tm [137]> <tibble [137 x 3]>

其中 rowMeans 方法大约是速度的 3 倍。