R |根据条件对多列进行突变

问题描述

如果该行中六个观测值中至少有三个是!= NA,我想连续计算平均值。如果存在四个或更多NA,则平均值应显示NA。

给出平均值的示例,而忽略了NA:

require(dplyr)

a <- 1:10
b <- a+10
c <- a+20
d <- a+30
e <- a+40
f <- a+50

df <- data.frame(a,b,c,d,e,f)

df[2,c(1,3,4,6)] <- NA
df[5,6)] <- NA
df[8,2,5,6)] <- NA


df <- df %>% mutate(mean = rowMeans(df[,1:6],na.rm=TRUE))

我考虑过使用

case_when

但是我不确定如何正确使用它:

df <- df %>% mutate(mean = case_when( ~ rowMeans(df[,na.rm=TRUE),TRUE ~ NA))

解决方法

您可以尝试使用base R解决方案,将非NA值的数量保存在新变量中,然后使用ifelse()作为均值:

#Data
a <- 1:10
b <- a+10
c <- a+20
d <- a+30
e <- a+40
f <- a+50

df <- data.frame(a,b,c,d,e,f)

df[2,c(1,3,4,6)] <- NA
df[5,6)] <- NA
df[8,2,5,6)] <- NA
#Code
#Count number of non NA
df$count <- rowSums( !is.na( df [,1:6]))
#Compute mean
df$Mean <- ifelse(df$count>=3,rowMeans(df [,1:6],na.rm=T),NA)

输出:

    a  b  c  d  e  f count     Mean
1   1 11 21 31 41 51     6 26.00000
2  NA 12 NA NA 42 NA     2       NA
3   3 13 23 33 43 53     6 28.00000
4   4 14 24 34 44 54     6 29.00000
5  NA 15 25 NA 45 NA     3 28.33333
6   6 16 26 36 46 56     6 31.00000
7   7 17 27 37 47 57     6 32.00000
8  NA NA 28 38 NA NA     2       NA
9   9 19 29 39 49 59     6 34.00000
10 10 20 30 40 50 60     6 35.00000
,

您可以这样做:

library(dplyr)

df %>% 
  rowwise %>%
  mutate(
    mean = case_when(
      sum(is.na(c_across())) < 4 ~ mean(c_across(),na.rm = TRUE),TRUE ~ NA_real_)
    ) %>% ungroup()

输出:

# A tibble: 10 x 7
       a     b     c     d     e     f  mean
   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1     1    11    21    31    41    51  26  
 2    NA    12    NA    NA    42    NA  NA  
 3     3    13    23    33    43    53  28  
 4     4    14    24    34    44    54  29  
 5    NA    15    25    NA    45    NA  28.3
 6     6    16    26    36    46    56  31  
 7     7    17    27    37    47    57  32  
 8    NA    NA    28    38    NA    NA  NA  
 9     9    19    29    39    49    59  34  
10    10    20    30    40    50    60  35  

这利用了rowwisec_across,这基本上意味着在行级别上进行操作,因此您可以按常规方式使用矢量化功能,例如summean等(也使用case_when)。

c_across还有一个cols参数,您可以在其中指定要考虑的列。例如,如果您想考虑列1:6,则可以将其指定为:

df %>% 
  rowwise %>%
  mutate(
    mean = case_when(
      sum(is.na(c_across(1:6))) < 4 ~ mean(c_across(),TRUE ~ NA_real_)
  ) %>% ungroup() 

或者,如果您愿意想要考虑除第2列以外的所有列,您可以进行c_across(-2)。您还可以使用列名,例如对于第一个示例c_across(a:f)(所有列)或第二个c_across(-b)(除b之外的所有列)。

这是在dplyr内部实现的,但是您也可以使用整个c_across()(默认为所有列,即everything())进行常规的向量子集设置,例如c_across()[1:6]c_across()[-2]

,

我们可以先创建一个索引,然后根据该索引进行分配

i1 <- rowSums(!is.na(df)) >=3
df$Mean[i1] <- rowMeans(df[i1,],na.rm = TRUE)

df
#    a  b  c  d  e  f     Mean
#1   1 11 21 31 41 51 26.00000
#2  NA 12 NA NA 42 NA       NA
#3   3 13 23 33 43 53 28.00000
#4   4 14 24 34 44 54 29.00000
#5  NA 15 25 NA 45 NA 28.33333
#6   6 16 26 36 46 56 31.00000
#7   7 17 27 37 47 57 32.00000
#8  NA NA 28 38 NA NA       NA
#9   9 19 29 39 49 59 34.00000
#10 10 20 30 40 50 60 35.00000

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...