2015-04-07 3 views
3

У меня есть таблица данных (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

Просьба воспроизводимый пример 'DT '. – Roland

+0

Просто быстро скажите, что вы должны начать с написания «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) 'как функция, а затем используйте' lapply'. Затем вместо использования внешнего 'for' попробуйте просто сделать истинное/ложное значение для условия, а затем включить его в вашу функцию. В общем, избавиться от циклов, где бы вы ни находились, и использовать векторизацию. – Elin

+0

спасибо за подсказку ...Я пытаюсь перейти к таким направлениям, чтобы повысить эффективность работы с R (а также бинарный поиск с помощью data.table) – user2165907

ответ

3

Использование девелоперской версии 'data.table', т.е. v1.9.5, мы можем создать столбец «ind», используя rleid по логическому условию TMEAN >0 по «YEAR», подмножество набора данных для строк больше 4 & положительных значений TMEAN (.SD[.N >4 & TMEAN >0]) на «ind» и «YEAR». Получите первую строку по YEAR (.SD[1L]) и присвойте столбцу «ind» значение 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 

Если 'ДАТА' не упорядочено, мы можем использовать 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][] 

ПРИМЕЧАНИЕ: Инструкции по установке версии разви является 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 в

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 
+0

Приятные объяснения (код не такой интуитивный!). Можно ли избежать использования rleid (по крайней мере, на время, когда оно не реализовано в «стабильной» версии)? – user2165907

+0

@ user2165907 Я обновил опцию с помощью 'rle'. – akrun

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  
} 

I будет использовать функцию 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