我有一个时间序列数据的数据框,每天都有温度观测值。我需要创建一个虚拟变量,计算每天温度高于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)
有人可以建议更简单的方法吗?
答案 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 ...
现在我们想要找到values
为TRUE
(即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)