【问题标题】:vectorizing "expansion of date range" per row in dplyr of R在 R 的 dplyr 中对每行的“日期范围扩展”进行矢量化
【发布时间】:2018-08-26 23:50:06
【问题描述】:

我在 R 的 tibble 中有一个数据集,如下所示:

# A tibble: 50,045 x 5
   ref_key start_date end_date  
   <chr>   <date>     <date>    
 1 123     2010-01-08 2010-01-13
 2 123     2010-01-21 2010-01-23
 3 123     2010-03-10 2010-04-14

我需要创建另一个 tibble,每行只存储一个日期,如下所示:

   ref_key date      
   <chr>   <date>    
 1 123     2010-01-08
 2 123     2010-01-09
 3 123     2010-01-10
 4 123     2010-01-11
 5 123     2010-01-12
 6 123     2010-01-13
 7 123     2010-01-21
 8 123     2010-01-22
 9 123     2010-01-23

目前我正在为此编写一个显式循环,如下所示:

for (loop in (1:nrow(input.df))) {
  if (loop%%100==0) {
    print(paste(loop,'/',nrow(input.df)))
  }
  temp.df.st00 <- input.df[loop,] %>% data.frame
  temp.df.st01 <- tibble(ref_key=temp.df.st00[,'ref_key'],
                    date=seq(temp.df.st00[,'start_date'],
                             temp.df.st00[,'end_date'],1))
  if (loop==1) {
    output.df <- temp.df.st01
  } else {
    output.df <- output.df %>%
      bind_rows(temp.df.st01)
  }
}

它正在工作,但速度很慢,因为我有超过 50k 行要处理,完成循环需要几分钟。

不知道这一步能不能向量化,是不是和dplyr中的row_wise有关系?

【问题讨论】:

标签: r date for-loop dplyr vectorization


【解决方案1】:

我们创建一个行名列 (rownames_to_column),然后 nest 'rn' 和 'ref_key',mutate 通过在 map 和 @987654325 中采用 'start_date' 和 'end_date' 的顺序@select删除不需要的列之后的@

library(tidyverse)
res <- df1 %>%
         rownames_to_column('rn') %>% 
         nest(-rn, -ref_key) %>%
         mutate(date = map(data, ~ seq(.x$start_date, .x$end_date, by = "1 day"))) %>%
         select(-data, -rn) %>%
         unnest
head(res, 9)
#  ref_key       date
#1     123 2010-01-08
#2     123 2010-01-09
#3     123 2010-01-10
#4     123 2010-01-11
#5     123 2010-01-12
#6     123 2010-01-13
#7     123 2010-01-21
#8     123 2010-01-22
#9     123 2010-01-23

【讨论】:

    【解决方案2】:

    一种解决方案是使用tidyr::complete 来扩展行。由于行扩展基于行的start-dateend_date,因此group_by 上的row_number 将有助于在start-dateend_date 之间生成Date 序列。

    library(dplyr)
    library(tidyr)
    
      df %>% #mutate(rnum = row_number()) %>%
      group_by(row_number()) %>%
      complete(start_date = seq.Date(max(start_date), max(end_date), by="day")) %>%
      fill(ref_key) %>%
      ungroup() %>%
      select(ref_key, date = start_date)
    
    
    
    # # A tibble: 45 x 2
    # ref_key date      
    # <int> <date>    
    # 1     123 2010-01-08
    # 2     123 2010-01-09
    # 3     123 2010-01-10
    # 4     123 2010-01-11
    # 5     123 2010-01-12
    # 6     123 2010-01-13
    # 7     123 2010-01-21
    # 8     123 2010-01-22
    # 9     123 2010-01-23
    # 10     123 2010-03-10
    # # ... with 35 more rows
    

    数据

    df <- read.table(text = "ref_key start_date end_date  
    123     2010-01-08 2010-01-13
    123     2010-01-21 2010-01-23
    123     2010-03-10 2010-04-14", header = TRUE, stringsAsFactor = FALSE)
    df$start_date <- as.Date(df$start_date)
    df$end_date <- as.Date(df$end_date)
    

    【讨论】:

      猜你喜欢
      • 2022-01-13
      • 2017-05-12
      • 1970-01-01
      • 1970-01-01
      • 2014-11-15
      • 2019-01-24
      • 1970-01-01
      • 1970-01-01
      • 2018-01-31
      相关资源
      最近更新 更多