在R中创建条件新变量

时间:2015-05-27 01:48:51

标签: r dplyr tidyr

我需要重新创建一个非常大的数据帧的原始变量(900+个变量)。 这是我正在尝试做的一个例子:

dat <- data.frame(
    id=c('user1','user2','user3'),
    agePanel1=c(20,25,32),
    agePanel2=c(21,NA,33),
    favColPanel1=c('blue','red','blue'),
    favColPanel2=c('red',NA,'red')
    )

     id      agePanel1 agePanel2 favColPanel1 favColPanel2
  1 user1        20        21         blue          red
  2 user2        25        NA          red           NA
  3 user3        32        33         blue          red

对于每个变量,我需要在有面板数据的情况下创建一个新变量(age和favCol,以下是NA),否则是第一个面板观察。在面板数据不完整的情况下,所有面板值都应设置为NA。此示例的结果如下所示:

        id    age  agePanel1 agePanel2 favCol favColPanel1 favColPanel2
    1 user1    NA      20        21      NA        blue          red           
    2 user2    25      NA        NA     red         NA            NA         
    3 user3    NA      32        33      NA        blue          red     

我开始尝试使用dplyr和tidyr:

mutate(dat, age = ifelse(is.na(test$agePanel2),agePanel1,NA))

我正在努力寻找一种方法来做一个循环或可以自动化这个过程的东西。

3 个答案:

答案 0 :(得分:1)

您可以遍历要操作的列组的名称,对每个列进行操作:

cols <- c("age", "favCol")
for (col in cols) {
  dat[,col] <- dat[,paste0(col, "Panel1")]
  dat[!is.na(dat[,paste0(col, "Panel2")]), col] <- NA
  dat[is.na(dat[,paste0(col, "Panel2")]),paste0(col, "Panel1")] <- NA
}
dat
#      id agePanel1 agePanel2 favColPanel1 favColPanel2 age favCol
# 1 user1        20        21         blue          red  NA   <NA>
# 2 user2        NA        NA         <NA>         <NA>  25    red
# 3 user3        32        33         blue          red  NA   <NA>

答案 1 :(得分:1)

您可以使用Map

 dat[c('age', 'favcol')] <-Map(function(x,y) {
            indx <- rowSums(is.na(cbind(x,y)))
             x[seq_along(x)*NA^!indx]}, dat[c(2,4)], dat[c(3,5)])
 dat[rowSums(is.na(dat[2:5]))!=0,2:5] <- NA
 dat
 #    id agePanel1 agePanel2 favColPanel1 favColPanel2 age favcol
 #1 user1        20        21         blue          red  NA   <NA>
 #2 user2        NA        NA         <NA>         <NA>  25    red
 #3 user3        32        33         blue          red  NA   <NA>

答案 2 :(得分:1)

这不是您原始问题的最直接解决方案。但在我看来,将数据放在很长的时间里是可取的。然后你想要做的操作(和大多数其他操作)会容易得多。

# required packages
require(dplyr)
require(tidyr)
# get data in long format
dat_long <- dat %>% 
  gather(key, value, -id) %>% 
  separate(key, c("key", "panel"), sep = "Panel") %>%
  spread(key, value, convert = TRUE) %>% 
  arrange(id, panel) %>%
  group_by(id)
dat_long
## Source: local data frame [6 x 4]
## Groups: id
## 
##      id panel age favCol
## 1 user1     1  20   blue
## 2 user1     2  21    red
## 3 user2     1  25    red
## 4 user2     2  NA     NA
## 5 user3     1  32   blue
## 6 user3     2  33    red

# functon that does desired operation
panel_fct <- function(x){
  ifelse(is.na(x[2]), x[1], as(NA, class(x)))
}
# use mutate_each to do desired operation
dat_long %>% summarise_each(funs(panel_fct), -panel)
## Source: local data frame [3 x 3]
##
##      id age favCol
## 1 user1  NA     NA
## 2 user2  25    red
## 3 user3  NA     NA

当然,您可以将最终结果合并回原始数据,但对于大多数操作,最好使用长数据。

dat_long %>% summarise_each(funs(panel_fct), -panel) %>% left_join(dat, by = "id")
## Source: local data frame [3 x 7]
## 
##      id age favCol agePanel1 agePanel2 favColPanel1 favColPanel2
## 1 user1  NA     NA        20        21         blue          red
## 2 user2  25    red        25        NA          red           NA
## 3 user3  NA     NA        32        33         blue          red