【问题标题】:Generating minimum value in cumsum function in R在R中的cumsum函数中生成最小值
【发布时间】:2018-03-21 20:19:14
【问题描述】:
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)

如果我想找出一年中的哪一天,rain.acctmean.acc 的 cumsum 值是我可以做到的最小值:

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

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

但是,我想施加一个条件,即我只想查看 doy >= 213 和 cumsum(rain.acc) 和 @ 987654326@。请注意,cumsum 必须计算全年。

【问题讨论】:

    标签: r tidyverse cumsum


    【解决方案1】:

    使用ifelse()对可能的值应用过滤器

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

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

    > 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
    

    > 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
    

    【讨论】:

    • 写得很巧妙。谢谢。
    【解决方案2】:

    注意:您必须加上 212 才能获得正确的年份。

    使用基础 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
    

    使用 data.table 包

    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
    

    【讨论】:

      【解决方案3】:

      你可以在 cumsum 之后但在 which.min 之前进行子集吗?

      dat %>% summarise(which.min(cumsum(rain.acc)[day>=213&day<=365]))
      

      【讨论】:

      • 这也可以。但是,@satish 显示的另一个步骤是添加 212 以获得一年中的实际日期。感谢您的宝贵时间。
      【解决方案4】:

      一种选择是将filter 用于第一个子集行,然后将条件与row_number() 匹配以找到确切的行:

        library(dplyr)
      
        dat %>%
          filter(day >= 213 & day <= 365) %>%
          filter(row_number() == which.min(cumsum(rain.acc)))
        # day     rain    tmean mean.daily.rain mean.daily.tmean   rain.acc tmean.acc
        # 1 329 1.691956 17.52186          2.4938         24.03155 -0.8018434 -6.509688
      
        dat %>%
          filter(day >= 213 & day <= 365) %>%
          filter(row_number() == which.min(cumsum(tmean.acc)))
        # 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
      

      【讨论】:

      • 这也可以。但是,我接受了 Martin 的回答,因为它允许我在单个数据框中实现。感谢您的宝贵时间
      • @Crop89 我很高兴你得到了想要的帮助。我认为您也可以根据我的回答在单个数据帧命令中实现这两个值。我一开始就让它更简单。我稍后会更新我的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-01
      • 2020-03-04
      • 2020-09-18
      • 1970-01-01
      • 1970-01-01
      • 2013-04-08
      • 2012-02-17
      相关资源
      最近更新 更多