如何在R中创建条件虚拟?

时间:2016-02-01 14:16:58

标签: r loops dataframe

我有一个时间序列数据的数据框,每天都有温度观测值。我需要创建一个虚拟变量,计算每天温度高于5C的阈值。这本身很容易,但存在一个附加条件:计数仅在超过阈值连续十天后开始计数。这是一个示例数据框:

df <- data.frame(date = seq(365), 
         temp = -30 + 0.65*seq(365) - 0.0018*seq(365)^2 + rnorm(365))

我想我已经完成了,但是我喜欢的循环太多了。这就是我所做的:

df$dummyUnconditional <- 0
df$dummyHead <- 0
df$dummyTail <- 0

for(i in 1:nrow(df)){
    if(df$temp[i] > 5){
        df$dummyUnconditional[i] <- 1
    }
}

for(i in 1:(nrow(df)-9)){
    if(sum(df$dummyUnconditional[i:(i+9)]) == 10){
        df$dummyHead[i] <- 1
    }
}

for(i in 9:nrow(df)){
    if(sum(df$dummyUnconditional[(i-9):i]) == 10){
        df$dummyTail[i] <- 1
    }
}

df$dummyConditional <- ifelse(df$dummyHead == 1 | df$dummyTail == 1, 1, 0)

有人可以建议更简单的方法吗?

3 个答案:

答案 0 :(得分:5)

这是使用rle的基本R选项:

df$dummy <- with(rle(df$temp > 5), rep(as.integer(values & lengths >= 10), lengths))

一些解释:该任务是运行长度编码(rle)函数imo的经典用例。我们首先检查temp的值是否大于5(创建逻辑向量)并在该向量上应用rle导致:

> rle(df$temp > 5)
#Run Length Encoding
#  lengths: int [1:7] 66 1 1 225 2 1 69
#  values : logi [1:7] FALSE TRUE FALSE TRUE FALSE TRUE ...

现在我们想要找到valuesTRUE(即temp大于5)且同时lengths大于10的情况(即at {至少十个连续temp值大于5)。我们通过运行:

来做到这一点
values & lengths >= 10

最后,由于我们想要返回与nrow(df)长度相同的向量,我们使用rep(..., lengths)as.integer来返回1/0而不是{{1} } / TRUE

答案 1 :(得分:5)

我认为您可以在zoo package中结合使用简单的ifelse和roll apply函数来实现您的目标。最后一步只是将结果填充到第一个N-1天,其中没有足够的信息来填充窗口。

library(zoo)

df <- data.frame(date = seq(365), 
                 temp = -30 + 0.65*seq(365) - 0.0018*seq(365)^2 + rnorm(365))

df$above5 <- ifelse(df$temp > 5, 1, 0)
temp <- rollapply(df$above5, 10, sum)
df$conseq <- c(rep(0, 9),temp)

答案 2 :(得分:2)

我会这样做:

set.seed(42)
df <- data.frame(date = seq(365), 
                 temp = -30 + 0.65*seq(365) - 0.0018*seq(365)^2 + rnorm(365))
thr <- 5
df$dum <- 0

#find first 10 consecutive values above threshold
test1 <- filter(df$temp > thr, rep(1,10), sides = 1) == 10L
test1[1:9] <- FALSE
n <- which(cumsum(test1) == 1L)

#count days above threshold after that
df$dum[(n+1):nrow(df)] <- cumsum(df$temp[(n+1):nrow(df)] > thr)