我有一个数据表(DT),包含年份,日期和温度测量值(TMEAN):
YEAR DATE TMEAN
2010 2010-01-01 -5
2010 2010-01-02 -9
2010 2010-01-03 -6
2010 2010-01-04 0.1
2010 2010-01-05 -0.5
2010 2010-01-06 1
2010 2010-01-07 1.6
2010 2010-01-08 8
2010 2010-01-09 6
2010 2010-01-10 3
2010 2010-01-11 5
2010 2010-01-12 3
2011 2011-01-01 -3
2011 2011-01-02 -5.4
2011 2011-01-03 -3.6
2011 2011-01-04 0.06
2011 2011-01-05 -0.3
2011 2011-01-06 0.6
2011 2011-01-07 0.96
2011 2011-01-08 4.8
2011 2011-01-09 3.6
2011 2011-01-10 1.8
2011 2011-01-11 3
2011 2011-01-12 1.8
每年,我需要连续至少连续5天获得测量结果为正的第一天...
一个想法是:
for (y in min(DT$YEAR):max(DT$YEAR)) {
for (i in 1:nrow(DT)) {
DT$test <- ifelse(DT[i, TMEAN] > 0 & DT[i+1, TMEAN] > 0 & DT[i+2, TMEAN] > 0 & DT[i+3, TMEAN] > 0 & DT[i+4, TMEAN] > 0, 1, 0)
}
}
DT2 <- DT[test == 1, ][, list(START = min(DATE)), by = .(YEAR)]
但它超级慢(而且不那么优雅!)。
如何替换for和ifelse的多次使用?
答案 0 :(得分:3)
使用&#39; data.table&#39;的开发版本即。 v1.9.5
,我们可以创建一个&#39; ind&#39;在逻辑条件rleid
上使用TMEAN >0
的列按“年”&#39;,将数据集的子集大于4&amp; TMEAN的正值(.SD[.N >4 & TMEAN >0]
)由&#39; ind&#39;和&#39;年&#39;。按年份(.SD[1L]
)获取第一行并指定“&#39; ind&#39;列为NULL。
library(data.table)#v1.9.5+
DT[, ind:= rleid(TMEAN>0) ,YEAR][, .SD[.N>4 & TMEAN>0] ,
list(ind,YEAR)][,.SD[1L] , YEAR][, ind:=NULL][]
# YEAR DATE TMEAN
#1: 2010 2010-01-06 1.0
#2: 2011 2011-01-06 0.6
如果&#39;日期&#39;如果没有订购,我们可以使用which.min(DATE)
代替.SD[1L]
DT[, ind:= rleid(TMEAN>0) ,YEAR][, .SD[.N>4 & TMEAN>0] ,
list(ind, YEAR)][, .SD[which.min(DATE)], YEAR][, ind:=NULL][]
注意:安装devel版本的说明是here
我们也可以使用rle
base R
DT[, ind:=inverse.rle(within.list(rle(TMEAN >0),
values <- seq_along(values))), YEAR][,
.SD[ .N >4 & TMEAN >0], list(ind, YEAR)][,
.SD[which.min(DATE)], YEAR][, ind:=NULL][]
# YEAR DATE TMEAN
#1: 2010 2010-01-06 1.0
#2: 2011 2011-01-06 0.6
如果是@ VLC的帖子中显示的第5天
DT[, ind:=inverse.rle(within.list(rle(TMEAN >0),
values <- seq_along(values))), YEAR][,
.SD[ .N >4 & TMEAN >0], list(ind, YEAR)][
order(DATE), .SD[5L], YEAR][,ind:=NULL][]
# YEAR DATE TMEAN
#1: 2010 2010-01-10 3.0
#2: 2011 2011-01-10 1.8
答案 1 :(得分:1)
首先是数据集:
set.seed(1)
dataset <- data.frame(
date = seq(as.Date("2011/1/1"), as.Date("2014/1/31"), "day"),
year = format(date, "%Y"),
tmean = runif(length(date), -10, 35)
)
然后我们可以定义一个带有两个参数的函数(一个包含温度的向量和一个定义连续天数的数字),主要基于rle
函数:
getFirstDay <- function(x,d){
a1 <- rle(sign(x))
a2 <- which(a1$lengths >= d & a1$values == 1)
a3 <- rep(0, length(x))
if(length(a2) != 0) a3[(d + sum(a1$lengths[seq_len(a2[1] - 1)])] <- 1
a3
}
我将使用ddply
中的plyr
函数来提取每年的日期,但您也可以将其用于data.table
:
library(plyr)
dataset2 <- ddply(dataset, .(year), mutate, theDay = getFirstDay(tmean, 5))
subset(dataset2, dataset2$theDay == 1)
# date year tmean theDay
# 17 2011-01-17 2011 22.292833 1
# 372 2012-01-07 2012 15.297955 1
# 761 2013-01-30 2013 24.971524 1
# 1102 2014-01-06 2014 1.419521 1
使用您的数据集:
dataset2 <- ddply(DT, .(YEAR), mutate, theDay = getFirstDay(TMEAN, 5))
subset(dataset2, dataset2$theDay == 1)
# YEAR DATE TMEAN theDay
# 10 2010 2010-01-10 3.0 1
# 22 2011 2011-01-10 1.8 1