【问题标题】:How to filter a data set and calculate a new variable faster in R?如何在 R 中更快地过滤数据集并计算新变量?
【发布时间】:2019-07-04 18:05:41
【问题描述】:

我有一个每分钟都有值的数据集,我想计算每小时的平均值。我尝试使用 dplyr 包中的 group_by()、filter() 和 summarise() 来减少每小时的数据。当我只使用这些函数时,我能够获得每小时但每个月的平均值,并且我每天都想要它。

> head(DF)
         datetime        pw        cu          year m  d hr min
1 2017-08-18 14:56:00 0.0630341 1.94065        2017 8 18 14  53
2 2017-08-18 14:57:00 0.0604653 1.86771        2017 8 18 14  57
3 2017-08-18 14:58:00 0.0601318 1.86596        2017 8 18 14  58
4 2017-08-18 14:59:00 0.0599276 1.83761        2017 8 18 14  59
5 2017-08-18 15:00:00 0.0598998 1.84177        2017 8 18 15   0

我不得不使用 for 循环来减少我的表格,我写了以下内容来做到这一点:

datetime <- c()
eg_bf <-c ()

for(i in 1:8760){  
    hour= start + 3600

    DF= DF %>% 
      filter(datetime >= start & datetime < hour) %>% 
      summarise(eg= mean(pw))

    datetime= append(datetime, start)
    eg_bf= append(eg_bf, DF$eg)

    start= hour
    }
new_DF= data.frame(datetime, eg_bf)

所以。我能够获得一年中每个小时的平均值的新数据集。

  datetime             eg_bf
1 2018-01-01 00:00:00  0.025
2 2018-01-01 01:00:00  0.003
3 2018-01-01 02:00:00  0.002
4 2018-01-01 03:00:00  0.010
5 2018-01-01 04:00:00  0.015

我面临的问题是这需要很多时间。我们的想法是将此计算添加到闪亮的 UI 中,因此每次我进行更改时,都必须使更改更快。知道如何改进这个计算吗?

【问题讨论】:

    标签: r for-loop dplyr


    【解决方案1】:

    你可以试试这个。使用 lubridate 包中的 make_date 使用数据集的年、月、日和小时列创建新的 date_time 列。然后在新列上进行分组和总结

    library(dplyr)
    library(lubridate)
     df %>% 
       mutate(date_time = make_datetime(year, m, d, hr)) %>%  
       group_by(date_time) %>% 
       summarise(eg_bf = mean(pw))
    

    【讨论】:

    • 正是我想要的。谢谢!
    【解决方案2】:

    @Adam Gruer 的回答为应该解决您的问题的日期变量提供了一个很好的解决方案。不过,每小时平均值的计算仅适用于 dplyr:

    df %>%
      group_by(year, m, d, hr) %>%
      summarise(test = mean(pw))
    
    # A tibble: 2 x 5
    # Groups:   year, m, d [?]
       year     m     d    hr   test
      <int> <int> <int> <int>  <dbl>
    1  2017     8    18    14 0.0609
    2  2017     8    18    15 0.0599
    

    你在你的问题中说:

    当我只使用这些函数时,我能够得到每个小时的平均值,但只能得到每个月的平均值,而且我每天都想要它。

    你做了什么不同的事情?

    【讨论】:

    • 是的,问题是我使用了 filter() 一年,然后我按月或小时分组。我没有在 group_by() 中包含 m、d 和 hr
    【解决方案3】:

    即使你找到了答案,我相信这也值得一提:

    如果您正在处理大量数据并且速度是个问题,那么您可能想看看是否可以使用 data.table 而不是 dplyr

    您可以通过简单的基准测试看到data.table 的速度有多快:

    library(dplyr)
    library(lubridate)
    library(data.table)
    library(microbenchmark)
    set.seed(123)
    
    # dummy data, one year, one entry per minute
    # first as data frame
    DF <- data.frame(datetime = seq(as.POSIXct("2018-01-01 00:00:00"), 
                                    as.POSIXct("2019-01-02 00:00:00"), 60),
                     pw = runif(527041)) %>% 
      mutate(year = year(datetime), m=month(datetime), 
             d=day(datetime), hour = hour(datetime))
    
    # save it as a data.table
    dt <- as.data.table(DF)
    
    # transformation with dplyr
    f_dplyr <- function(){
      DF %>% 
        group_by(year, m, d, hour) %>% 
        summarize(eg_bf = mean(pw))
    }
    
    
    # transformation with data.table
    f_datatable <- function() {
      dt[, mean(pw), by=.(year, m, d, hour)]
    }
    
    # benchmarking
    microbenchmark(f_dplyr(), f_datatable())
    
    # 
    # Unit: milliseconds
    #          expr       min        lq     mean   median       uq      max neval cld
    #     f_dplyr() 41.240235 44.075019 46.85497 45.64998 47.95968 76.73714   100   b
    # f_datatable()  9.081295  9.712694 12.53998 10.55697 11.33933 41.85217   100  a
    

    看看这篇文章,它告诉了很多 data.table vs dplyr: can one do something well the other can't or does poorly?

    【讨论】:

      【解决方案4】:

      据我了解,您有一个 365 * 24 * 60 行的数据框。下面的代码立即返回结果。结果是按一年中的每个小时分组的平均值 (pw)。

      
      remove(list = ls())
      
      library(dplyr)
      library(lubridate)
      library(purrr)
      library(tibble)
      
      date_time <- seq.POSIXt(
          as.POSIXct("2018-01-01"),
          as.POSIXct("2019-01-01"),
          by = "1 min"
      )
      
      n <- length(date_time)
      
      data <- tibble(
          date_time = date_time,
          pw = runif(n),
          cu = runif(n),
          ye = year(date_time),
          mo = month(date_time),
          da = day(date_time),
          hr = hour(date_time)
      )
      
      grouped <- data %>% 
          group_by(
              ye, mo, da, hr
          ) %>% 
          summarise(
              mean_pw = mean(pw)
          )
      
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-06
        • 1970-01-01
        • 1970-01-01
        • 2022-08-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多