如何在R中创建“条件”变量?

时间:2016-07-14 22:40:56

标签: r function dataframe data.table

我想创建一个条件虚拟变量。假设我有一个看起来像这样的数据集:

Subject Year    X   X1
   A    1990    1   0
   A    1991    1   0
   A    1992    2   0
   A    1993    3   0
   A    1994    4   0
   A    1995    4   1
   B    1990    0   0
   B    1991    1   0
   B    1992    1   0
   B    1993    2   0
   B    1994    3   0
   C    1990    1   0
   C    1991    2   0
   C    1992    3   1
   C    1993    3   0
   D    1990    1   0
   D    1991    2   0
   D    1992    3   0
   D    1993    4   1
   D    1994    5   0
   E    1990    1   0
   E    1991    1   0
   E    1992    2   1
   E    1993    3   0

让我们调用这个条件变量: Q1to3_noX1 。另一个感兴趣的变量是 Q1to3

Q1to3 变量也是一个虚拟变量,当X达到值3时指示1,否则为0(对于每个主题)。如果X为4或更大,则 Q1to3 变量应为0.X是累积变量(0,1,2,3,4 ......)。换句话说,如果最大X值为3, Q1to3 为1。

我使用:data$Q1to3 <- ave(data$X, data$Subject, FUN = function(x) if (max(x) == 3) 1 else 0)创建了这个变量(感谢@ Zelazny7)。

Q1to3_noX1 变量与 Q1to3 变量非常相似,但与 Q1to3 相反,它以X1变量为条件。更确切地说,如果在接下来的5年中X1 = 1(从 Q1to3 的第一年开始计算), Q1to3_no5 应为0.换句话说,如果a)最大X值为3,则 Q1to3_noX1 应为1; b)如果5年后X1 = 0(否则为0)。

我从question了解到我应该使用rle函数。但是,我无法在这种特殊情况下应用它。你有什么建议吗?

理想的结果应如下所示:

Subject Year    X   X1  Q1to3   Q1to3_noX1
   A    1990    1   0   0          0
   A    1991    1   0   0          0
   A    1992    2   0   0          0
   A    1993    3   0   0          0
   A    1994    4   0   0          0
   A    1995    4   1   0          0
   B    1990    0   0   1          0
   B    1991    1   0   1          1
   B    1992    1   0   1          1
   B    1993    2   0   1          1
   B    1994    3   0   1          1
   C    1990    1   0   1          0
   C    1991    2   0   1          0
   C    1992    3   1   1          0
   C    1993    3   0   1          0
   D    1990    1   0   0          0
   D    1991    2   0   0          0
   D    1992    3   0   0          0
   D    1993    4   1   0          0
   D    1994    5   0   0          0
   E    1990    1   0   1          0
   E    1991    1   0   1          0
   E    1992    2   1   1          0
   E    1993    3   0   1          0

可重复的样本:

    > dput(data)
structure(list(Subject = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 
2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 
5L, 5L), .Label = c("A", "B", "C", "D", "E"), class = "factor"), 
    Year = c(1990L, 1991L, 1992L, 1993L, 1994L, 1995L, 1990L, 
    1991L, 1992L, 1993L, 1994L, 1990L, 1991L, 1992L, 1993L, 1990L, 
    1991L, 1992L, 1993L, 1994L, 1990L, 1991L, 1992L, 1993L), 
    X = c(1L, 1L, 2L, 3L, 4L, 4L, 0L, 1L, 1L, 2L, 3L, 1L, 2L, 
    3L, 3L, 1L, 2L, 3L, 4L, 5L, 1L, 1L, 2L, 3L), X1 = c(0L, 0L, 
    0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 
    0L, 1L, 0L, 0L, 0L, 1L, 0L), Q1to3 = c(0L, 0L, 0L, 0L, 0L, 
    0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 
    1L, 1L, 1L, 1L), Q1to3_noX1 = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 
    1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
    0L, 0L)), .Names = c("Subject", "Year", "X", "X1", "Q1to3", 
"Q1to3_noX1"), class = "data.frame", row.names = c(NA, -24L))

2 个答案:

答案 0 :(得分:1)

这个怎么样?

data$cX1 <- do.call("c",tapply(data$X1, data$Subject, FUN = function(x){
  nx=length(x) #i=1
  sx=c()
  if (nx<5) sx[1:nx]<-sum(x[1:nx]) else
  for(i in 1:nx)sx[i]<-sum(x[i:min(i+5-1,nx)])
  sx
},simplify = T))

data$Q1to3_noX1f2<-ifelse(data$Q1to3==1 & data$cX1==0,1,0)

答案 1 :(得分:1)

这是使用Base R的另一个例子。我不是100%我理解问题的确切细节,但这种模式应该可以解决你的问题。

ave非常适合将汇总向量广播回数据的原始维度。但是如果你看一下ave的函数体,它只是在引擎盖下使用split。我们可以做同样的事情并为每个块创建多个列而不只是一个:

# split the data.frame
s <- split(df, df$Subject)

## calculate both columns at once per subject
both <- lapply(s, function(chunk) {
  Q1to3 <- if (max(chunk$X) == 3) 1 else 0
  Q1to3_noX1 <- if (Q1to3 == 1 & all(chunk$X1 == 0)) 1 else 0
  data.frame(Q1to3, Q1to3_noX1)
})

## cbind them back together and unsplit
out <- unsplit(Map(cbind, s, both), df$Subject)