【问题标题】:Efficient way to build complex dataframe row by row in R在 R 中逐行构建复杂数据框的有效方法
【发布时间】:2019-09-06 00:56:39
【问题描述】:

:) 大家好

是的,我知道已经有一些技巧和窍门如何有效地逐行构建数据帧,但是我的 for 循环仍然很慢。也许对于你们中的一个人来说,如何加快速度/速度如此之慢的原因是什么。

如您所见,我已经按照以下说明将其转换为列表:Creating an R dataframe row-by-row,但这并不比 rbind 快得多。

index = 1

for (i in 1:nrow(predictionDf)) {

  startDate = predictionDf$ApropYMD[i]
  amountPerMonth = (predictionDf$PredictionExp[i]/12)
  amountPerMonthMax = (predictionDf$PredictionMax[i]/12)

  print(i)

  for (j in 1:12) {

    plotDf[index, ] = list(ApropYMD=startDate, AmountExp = amountPerMonth, AmountMax = amountPerMonthMax)
    month(startDate) <- month(startDate) + 1
    index = index + 1
  }


}

这个我也试过了,快一点

plotDf = data.frame("ApropYMD" =  c(seq(firstDayNextMonth, highestDate, by="months")))
plotDf$AmountExp = 0
plotDf$AmountMax = 0

for (i in 1:nrow(tmpPredictionDf)) { 

  startDate = tmpPredictionDf$ApropYMD[i]
  amountPerMonth = (tmpPredictionDf$PredictionExp[i]/12)
  amountPerMonthMax = (tmpPredictionDf$PredictionMax[i]/12)

  print(i)

  for (j in 1:12) {

    plotDf$AmountExp[which(plotDf$ApropYMD == startDate)] = plotDf$AmountExp[which(plotDf$ApropYMD == startDate)] + amountPerMonth
    plotDf$AmountMax[which(plotDf$ApropYMD == startDate)] = plotDf$AmountMax[which(plotDf$ApropYMD == startDate)] + amountPerMonthMax
    month(startDate) <- month(startDate) + 1

  }

我想在接下来的 12 个月中为 ~5.500 行中的每一行 -> 5.500*12 = 66.000 行插入分配一个日期的数量

Input       
ApropYMD    AmountExp   AmountMax
2019-01-01  6000    12000

Output      
ApropYMD    AmountExp   AmountMax
2019-01-01  500 1000
2019-01-02  500 1000
2019-01-03  500 1000
2019-01-04  500 1000
2019-01-05  500 1000
2019-01-06  500 1000
2019-01-07  500 1000
2019-01-08  500 1000
2019-01-09  500 1000
2019-01-10  500 1000
2019-01-11  500 1000
2019-01-12  500 1000

【问题讨论】:

    标签: r performance loops dataframe rbind


    【解决方案1】:

    不建议在循环中填充数据帧,而且通常很慢。我们可以使用预先存在的函数来做到这一点。例如,使用tidyr::complete 执行此操作的一种方法。假设您有“日期”类的ApropYMD,我们可以通过将每一行分组并为每个月创建一个日期序列,然后将first 的值除以AmountExpAmountMax,将每行扩展到 12 行。使其均匀分布。

    library(dplyr)
    library(tidyr)
    
    df %>%
      group_by(group = row_number()) %>%
      complete(ApropYMD = seq(ApropYMD, length.out = 12, by = "month"), 
               fill = list(AmountExp = 0, AmountMax = 0)) %>%
      mutate(AmountExp = first(AmountExp)/12, 
             AmountMax = first(AmountMax)/12) %>% 
      ungroup() %>%
      select(-group)
    
    
    # A tibble: 24 x 3
    #   ApropYMD   AmountExp AmountMax
    #   <date>         <dbl>     <dbl>
    # 1 2019-01-01       500      1000
    # 2 2019-02-01       500      1000
    # 3 2019-03-01       500      1000
    # 4 2019-04-01       500      1000
    # 5 2019-05-01       500      1000
    # 6 2019-06-01       500      1000
    # 7 2019-07-01       500      1000
    # 8 2019-08-01       500      1000
    # 9 2019-09-01       500      1000
    #10 2019-10-01       500      1000
    # … with 14 more rows
    

    数据

    添加了一个额外的行来测试解决方案

    df <- read.table(text = "ApropYMD    AmountExp   AmountMax
    2019-01-01  6000    12000
    2018-01-01  12000    24000", header = T)
    df$ApropYMD <- as.Date(df$ApropYMD)
    

    【讨论】:

    • 哇,感谢您快速而详细的回答!很有意义。您知道为什么在运行脚本时会出现此错误吗? (0L:(length.out - 1L)) * by 中的错误:二进制运算符的非数字参数
    • @agentdoublea 是的,因为ApropYMD 不属于“日期”类。执行df$ApropYMD &lt;- as.Date(df$ApropYMD) 并再次运行。
    【解决方案2】:

    我们可以在没有任何分组的情况下做到这一点。先做除法,然后用map展开'ApropYMD'和unnest

    library(tidyverse)
    df %>% 
       mutate_at(2:3, list(~ ./ 12)) %>%
       mutate(ApropYMD = map(ApropYMD, seq, length.out = 12, by = "month")) %>%
       unnest
    #   AmountExp AmountMax   ApropYMD
    #1        500      1000 2019-01-01
    #2        500      1000 2019-02-01
    #3        500      1000 2019-03-01
    #4        500      1000 2019-04-01
    #5        500      1000 2019-05-01
    #6        500      1000 2019-06-01
    #7        500      1000 2019-07-01
    #8        500      1000 2019-08-01
    #9        500      1000 2019-09-01
    #10       500      1000 2019-10-01
    #11       500      1000 2019-11-01
    #12       500      1000 2019-12-01
    #13      1000      2000 2018-01-01
    #14      1000      2000 2018-02-01
    #15      1000      2000 2018-03-01
    #16      1000      2000 2018-04-01
    #17      1000      2000 2018-05-01
    #18      1000      2000 2018-06-01
    #19      1000      2000 2018-07-01
    #20      1000      2000 2018-08-01
    #21      1000      2000 2018-09-01
    #22      1000      2000 2018-10-01
    #23      1000      2000 2018-11-01
    #24      1000      2000 2018-12-01
    

    数据

    df <- structure(list(ApropYMD = structure(c(17897, 17532), class = "Date"), 
    AmountExp = c(6000L, 12000L), AmountMax = c(12000L, 24000L
    )), row.names = c(NA, -2L), class = "data.frame")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 2015-12-13
      • 2022-08-10
      相关资源
      最近更新 更多