替换条件语句

时间:2015-04-07 15:44:58

标签: r data.table

我有一个数据表(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的多次使用?

2 个答案:

答案 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