Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating minimum value in cumsum function in R

set.seed(123)
dat <- data.frame(day = 1:365, rain = runif(min = 0, max = 5,365),tmean = runif(min = 15, max = 33, 365) )
dat <- dat %>% mutate(mean.daily.rain = mean(rain),mean.daily.tmean = mean(tmean)) %>% 
mutate(rain.acc = rain - mean.daily.rain,tmean.acc = tmean - mean.daily.tmean)

If I want to find which day of the year the cumsum value of rain.acc or tmean.acc was the minimum I can do this:

dat %>% summarise(which.min(cumsum(rain.acc)))
329

dat %>% summarise(which.min(cumsum(tmean.acc)))
159

However, I want to impose a condition that I only want to look at the doy >= 213 and <= 365 i.e. how do I extract the day of year between 213 and 365 with the lowest value of cumsum(rain.acc) and cumsum(tmean.acc). Note that cumsum has to be calculated over the entire year.

like image 767
89_Simple Avatar asked Mar 07 '23 14:03

89_Simple


2 Answers

Apply a filter to possible values using ifelse()

fun = function(x, i, min, max)
    which.min(cumsum(x) * ifelse(i >= min & i <= max, 1, NA))

with

> fun(dat$tmean.acc, dat$day, 213, 365)
[1] 248

or

> dat %>% summarize(
    rain.min = fun(rain.acc, day, 213, 365),
    tmean.min = fun(tmean.acc, day, 213, 365)
  )
  rain.min tmean.min
1      329       248

or

> filter(dat, row_number() == fun(tmean.acc, day, 213, 365))
  day     rain    tmean mean.daily.rain mean.daily.tmean rain.acc tmean.acc
1 248 4.846782 15.39589          2.4938         24.03155 2.352982 -8.635665
like image 78
Martin Morgan Avatar answered Mar 15 '23 20:03

Martin Morgan


Note: You have to add 212 to get the correct day of the year.

using base R

with(dat, which.min(cumsum(rain - mean(rain))[day>=213 & day<=365]) ) + 212  # 329
with(dat, which.min(cumsum(tmean - mean(tmean))[day>=213 & day<=365]) ) + 212  # 248

using data.table package

library('data.table')
setDT(dat)

# calculate cumsum over the entire year
dat[ , rain.acc := cumsum(rain - mean(rain)) ]
dat[ , tmean.acc := cumsum(tmean - mean(tmean)) ]

# For entire data    
dat[ dat[ , which.min( rain.acc) ], ]
#    day     rain    tmean  rain.acc tmean.acc
# 1: 329 1.691956 17.52186 -5.548483  13.31113
dat[ dat[ , which.min( tmean.acc) ], ]
#    day    rain    tmean  rain.acc tmean.acc
# 1: 159 2.22384 15.67266 0.1829257 -79.17573

# For data within a specified range    
dat[ dat[ day >=213 & day <= 365, which.min( rain.acc) + 213 - 1 ], ]
#    day     rain    tmean  rain.acc tmean.acc
# 1: 329 1.691956 17.52186 -5.548483  13.31113
dat[ dat[ day >=213 & day <= 365, which.min( tmean.acc) + 213 - 1 ], ]
#    day     rain    tmean rain.acc tmean.acc
# 1: 248 4.846782 15.39589 7.623054  -37.2419
like image 23
Sathish Avatar answered Mar 15 '23 19:03

Sathish