【问题标题】:Running a quicker calculation运行更快的计算
【发布时间】:2018-06-21 17:07:57
【问题描述】:

我在 R 中有 2 个数据帧,其中一个是另一个的子集。我必须对其进行一些操作,并从主数据框中计算 6 个 x 值的子集数据的百分比(代码中的 DayTreat)。所以我创建了一个函数来进行计算并创建一个新列。我的问题是它非常缓慢。有什么建议么?

percDay <- function(fullDat, subDat)
{
  subDat$DaySum <- NULL
  for (i in fullDat$DayTreat) # for each DayTreat value in fullDat. Must be `psmelt()` made phyloseq object
  {
    r <- sum(fullDat$Abundance[fullDat$DayTreat == i])  # Take the sum of all the taxa for that day
    subDat$DaySum[subDat$DayTreat == i] <- r  # Add the value to the subset of data
  }
  subDat$DayPerc <- (subDat$Abundance/subDat$DaySum) # Make the percentage of the subset
  subDat
}

【问题讨论】:

  • 您是否尝试过using a profiler 来识别瓶颈?此外,一个可重复的示例将帮助我们帮助您。
  • 可以添加示例数据集吗?

标签: r performance loops


【解决方案1】:

检查您的代码,您似乎在进行冗余计算 行:

for (i in fullDat$DayTreat)

应该是:

for (i in unique(fullDat$DayTreat))

之后您可以使用 data.table 并且不要使用单独的数据框, 如果你说一个是另一个的子集

require(data.table)
setDT(fullDat)
fullDat[, subsetI := Abundance > 30] # for example, should be your Condition
fullDat[, DaySum:= sum(Abundance), by = DayTreat]
fullDat[, DayPerc := Abundance/DaySum]
# get subset:
fullDat[subsetI == T]

如果您提供示例数据和所需的输出,则可以提供更具体的代码。

【讨论】:

    【解决方案2】:

    所以,在高层次上,我认为解决方案是:

    • 如果您还没有使用更快的数据类
    • 避免循环
      • 手动矢量化或
      • 真正适用于使用更多 C 代码和/或“在后台”具有更多矢量化的更快函数/库
    • 尝试使用 data.table 和/或 tidyverse 以获得更快的速度和更简洁的代码
    • 基准测试和分析您的代码

    例子:

    require(tidyverse)
    require(data.table)
    
    percDay <- function(fullDat, subDat)
    {
      subDat$DaySum <- NULL
      for (i in fullDat$DayTreat) # for each DayTreat value in fullDat. Must be `psmelt()` made phyloseq object
      {
        r <- sum(fullDat$Abundance[fullDat$DayTreat == i])  # Take the sum of all the taxa for that day
        subDat$DaySum[subDat$DayTreat == i] <- r  # Add the value to the subset of data
      }
      subDat$DayPerc <- (subDat$Abundance/subDat$DaySum) # Make the percentage of the subset
      subDat
    }
    
    # My simulation of your data.frame:
    fullDat <- data.frame(Abundance=rnorm(200),
                          DayTreat=c(1:100,1:100))
    subDat  <- dplyr::sample_frac(fullDat, .25)
    
    # Your function modifies the data, so I'll make a copy. For a potential 
    #   speed improvement I'll try data.table class
    fullDat0 <- as.data.table(fullDat)
    subDat0  <- as.data.table(subDat)
    
    
    require(rbenchmark)
    benchmark("original" = {
      percDay(fullDat, subDat)
    },
    "example_improvement" = {
    
      # Tidy approach
      tmp <- fullDat0 %>% 
        group_by(DayTreat) %>% 
        summarize(DaySum = sum(Abundance))
    
      subDat0         <- merge(subDat, tmp, by="DayTreat")  # could use semi_join
      subDat0$DayPerc <- (subDat0$Abundance/subDat0$DaySum) # could use mutate
    
    },
    replications = 100,
    columns = c("test", "replications", "elapsed",
                "relative", "user.self", "sys.self"))
    
                     test replications elapsed relative user.self sys.self
     example_improvement          100    0.22    1.000      0.22     0.00
                original          100    1.42    6.455      1.23     0.01
    

    通常,data.table 方法的速度最快。基于 tibble 的“整洁”方法具有更清晰的语法,同时通常比 data.frame 快,但比 data.table 慢。像 @akrun 这样经验丰富的 data.table 专家可能只使用 1 个 data.table 语句就可以提供最高性能的解决方案。

    【讨论】:

    • @akrun 想证明我对您的提及是对还是错?这个问题似乎不适合你的才能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 2018-09-13
    • 2016-03-20
    • 2020-09-17
    • 2016-04-12
    • 1970-01-01
    相关资源
    最近更新 更多