如何使用apply或dplyr有条件地转换特定变量

时间:2017-11-10 09:56:25

标签: r dplyr apply

我正在使用具有相似结构但值不同的3个数据帧。我想根据要转换的变量中的条件和数据集中的第二个变量来转换/变换特定变量。数据集中的其他变量应保持不变。

在我的示例数据中,我想将列VAR1-3转换为NA IF,相应的AGE< 65 AND如果它自己的列具有值0.

foo <- data.frame('AGE'=c(50,65,66,40,70,25,65,67,44,56), 'SMOKING'=c(0,0,0,0,0,1,1,1,1,1),
              'VAR1'=c(1,0,0,1,0,1,0,1,0,0),'VAR2'=c(0,0,1,0,0,1,0,0,0,1),'VAR3'=c(1,0,1,1,1,0,0,0,1,0))

VARv <- c('VAR1','VAR2','VAR3')
OTHERSv <- c('SMOKING')
AGEVARv <- c('AGE', VARv)

由于我的数据集很大(> 2000变量)且变量的顺序可能不同,我想使用保存在向量中的变量名。

我可以使用以下for循环执行此操作,但想学习如何使用dplyr或应用函数

for (i in 1: length(VARv)) {foo[,VARv[i]] <- replace(foo[VARv[i]], foo[VARv[i]]==0 & foo$AGE<65, NA)}

如果我在数据集中没有二进制变量SMOKING,我可以

foo <- apply(foo, 2,function(y) {
foo[foo==0 & foo$AGE < 65] <- NA
return(foo)
}) 

但这也会改变SMOKING变量。

问题:如果其中一个我想通过名称引用我想要自动处理的其他人,如何选择和引用应用函数中的变量?

我有这样的想法,但我如何正确引用变量AGE?此尝试生成具有正确NA操作的21列数据,但重复每列的所有列(AGE.SMOKING,AGE.AGE,AGE.VAR1 ...,VAR1.SMOKING,VAR1.AGE,VAR1.VAR1 ETC)

b <- data.frame(foo[colnames(foo) %in% OTHERSv], apply(foo[colnames(foo) %in% AGEVARv],2,function(y) {
foo[foo==0 & foo$AGE < 65] <- NA
return(foo)
}))

我很感激任何见解!

2 个答案:

答案 0 :(得分:1)

我们可以创建一个重用函数

library(dplyr)
f1 <- function(dat, varCols, AgeCol){
  Age <- rlang::sym(AgeCol)
  dat %>%
     mutate_at(vars(varCols), funs(replace(., .==0 & (!!Age) < 65, NA)))
}

AgeC <- 'AGE'

f1(foo, VARv, AgeC)
#   AGE SMOKING VAR1 VAR2 VAR3
#1   50       0    1   NA    1
#2   65       0    0    0    0
#3   66       0    0    1    1
#4   40       0    1   NA    1
#5   70       0    0    0    1
#6   25       1    1    1   NA
#7   65       1    0    0    0
#8   67       1    1    0    0
#9   44       1   NA   NA    1
#10  56       1   NA    1   NA

我们也可以使用base R方法

f2 <- function(dat, varCols, AgeCol){
    dat[varCols] <- (NA^(dat[[AgeCol]] < 65 & !dat[varCols]))*dat[varCols]

   dat
}

all.equal(f1(foo, VARv, AgeC), f2(foo, VARv, AgeC), check.attributes = FALSE)
#[1] TRUE

答案 1 :(得分:1)

您可以考虑使用case_when()

  

在我的示例数据中,我想将列VAR1-3转换为NA IF   相应的AGE&lt; 65 AND如果它自己的列具有值0.

以下是case_when()解决此问题的示例:

library(tidyverse)

foo %>% 
  as_tibble() %>% 
  mutate(VAR1 = case_when(AGE < 65 & VAR1 == 0 ~ "NA",
                          TRUE ~ as.character(.$VAR1)),
         VAR2 = case_when(AGE < 65 & VAR2 == 0 ~ "NA",
                          TRUE ~ as.character(.$VAR2)),
         VAR3 = case_when(AGE < 65 & VAR3 == 0 ~ "NA",
                          TRUE ~ as.character(.$VAR3)))

返回:

# A tibble: 10 x 5
     AGE SMOKING  VAR1  VAR2  VAR3
   <dbl>   <dbl> <chr> <chr> <chr>
 1    50       0     1    NA     1
 2    65       0     0     0     0
 3    66       0     0     1     1
 4    40       0     1    NA     1
 5    70       0     0     0     1
 6    25       1     1     1    NA
 7    65       1     0     0     0
 8    67       1     1     0     0
 9    44       1    NA    NA     1
10    56       1    NA     1    NA