【问题标题】:How to create a "conditional" variable in R?如何在 R 中创建“条件”变量?
【发布时间】:2016-11-18 00:41:38
【问题描述】:

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

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 年(从Q1to3 的第一年开始计算)X1 = 1,则 Q1to3_no5 应该是 0。换句话说, Q1to3_noX1 应为 1,如果 a)最大 X 值为 3,b)如果 X1=0 后 5 年(否则为 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))

【问题讨论】:

  • 您是否尝试过 mutatedplyr 以及 ifelse
  • @JosephWood 嗨!不,我没有。谢谢,我现在去看看
  • 应该包含Subject B的行; 1990 年,Q1to3 值 = 1 而不是 0?
  • @JosephWood 没错,我马上改正
  • 这是使用@Zelazny7 建议的一般想法:data$dummy <- ave(data$X1, data$Subject, FUN = function(x) if (max(x) == 1) 1 else 0) 然后使用dplyr 我们有:data %>% mutate(Q1to3_noX1 = ifelse(dummy==0 & Q1to3==1, 1, 0)) %>% select(-dummy)

标签: r function dataframe data.table


【解决方案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)

【讨论】:

  • 谢谢,我会尽快尝试。我尝试了以前的版本,但它并没有真正按照我想要的方式工作。感谢您的宝贵时间!
【解决方案2】:

这是另一个使用 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)

【讨论】:

    猜你喜欢
    • 2020-03-13
    • 1970-01-01
    • 2015-05-07
    • 1970-01-01
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    相关资源
    最近更新 更多