【问题标题】:processing speed difference between for loop and dplyrfor循环和dplyr之间的处理速度差异
【发布时间】:2020-07-24 03:21:35
【问题描述】:

一段时间后,我在 R 中编写了一个带有简单 for 循环的函数,有人向我提出了另一种方法来做同样的事情,但使用 dplyr。所以我尝试了一下,发现运行时间有很大差异我的脚本(- 1s !)。 我想知道所用时间的巨大差异从何而来。 dplyr 是否更加优化? dplyr 是否以某种加快进程的方式编译?我不知道

我原来的功能:

key.rythm <- function(key, data) {
  ## Un data frame vide pour recevoir les resultats
  results <-
    data.frame(
      "down.time" = numeric(),
      "duration" = numeric(),
      "touche" = factor()
    )
  down.time <- NULL
  
  ## On est oblige de passer par une boucle pour parser ligne par ligne
  for (i in 1:nrow(data)) {
    
    if (data[i, "K.TOUCHE"] != key)
      next
    
    ## Pour la bonne cle, si l'on rencontre un down, le stocker
    ##(ainsi, si l'on rencontre deux down de suite, sans up entre les deux,
    ##le premier sera effaee et seul le second comptera)
    if (data$K.EVENEMENT[i] == "Key Down") {
      down.time <- data$K.TEMPS[i]
      
    }  else {
      
      ## verifier si l'on a bien eu un down precedemment
      if (is.null(down.time)) {
        duration <- NA
        down.time <- NA
      } else{
        ## Calculer la duree entre down et up
        duration <- data$K.TEMPS[i] - down.time
        
      }
      
      ligne <- c(down.time, duration)
      results <- rbind (results, ligne)
      ## vider le down (en cas de deux up consecutifs, au cas ou)
      down.time <- NULL
    }
    
  }
  
  # 0 est considere comme FAUX on assigne que s'il y as des lignes
  if (nrow(results)){
    results$touche <- key
  }
  names (results) <- c ("down.time", "duration", "touche")
  return(results)
}

和 dplyr 方式:

tmp<-group_by(filter (data,K.EVENEMENT  == "Key Up"), K.TOUCHE)$K.TEMPS - group_by(filter (data,K.EVENEMENT  == "Key Down"), K.TOUCHE)$K.TEMPS

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    这不像一个完整的答案,而更像是一个扩展评论。免责声明,我经常使用 dplyr 等进行数据操作。

    我注意到您正在遍历列中的每个项目,并慢慢地将结果附加到向量中。这是有问题的,因为它是under growing an object and failing to vectorize

    不太确定您的代码的预期输出是什么,我在下面查看您的 dplyr 函数进行猜测。考虑以下情况,您可以使用 base R 和 dplyr 实现相同的结果:

    library(microbenchmark)
    library(dplyr)
    set.seed(111)
    
    data = data.frame(K.EVENEMENT=rep(c("Key Up","Key Down"),each=500),
    K.TEMPS = rnorm(1000),K.TOUCHE=rep(letters[1:2],500))
    data$K.EVENEMENT = factor(data$K.EVENEMENT,levels=c("Key Up","Key Down"))
    
    dplyr_f = function(data){
    group_by(filter (data,K.EVENEMENT  == "Key Up"), K.TOUCHE)$K.TEMPS - group_by(filter (data,K.EVENEMENT  == "Key Down"), K.TOUCHE)$K.TEMPS
    }
    
    spl_red = function(data)Reduce("-",split(data$K.TEMPS,data$K.EVENEMENT))
    

    查看您的 dplyr 函数,group_by 中的第二项本质上是无用的,因为它不排序或不做任何事情,因此我们可以将函数简化为:

    dplyr_nu = function(data){
    filter(data,K.EVENEMENT  == "Key Up")$K.TEMPS - filter (data,K.EVENEMENT  == "Key Down")$K.TEMPS
    }
    
    all.equal(dplyr_nu(data),dplyr_f(data),spl_red(data))
    1] TRUE
    

    我们可以看看速度:

    microbenchmark(dplyr_f(data),dplyr_nu(data),spl_red(data))
    
               expr      min        lq       mean    median        uq      max
      dplyr_f(data) 1466.180 1560.4510 1740.33763 1636.9685 1864.2175 2897.748
     dplyr_nu(data)  812.984  862.0530  996.36581  898.6775 1051.7215 4561.831
      spl_red(data)   30.941   41.2335   66.42083   46.8800   53.0955 1867.247
     neval cld
       100   c
       100  b 
       100 a  
    

    我认为可以通过某种排序或简单的拆分和减少以某种方式简化您的功能。也许 dplyr 下游有更复杂的用途,以上只是为了健康讨论。

    【讨论】:

    • group by 很有用,因为在某些情况下,它们是 2 键按下不同的键并且不分组会导致问题
    【解决方案2】:

    当然,您永远不应该通过 data.frame 自己编写循环。您可以使用许多包和函数来操作 R 中的数据。

    我发现您的 R 之旅才刚刚开始。我的朋友,这是一个奇妙的冒险。

    【讨论】:

      猜你喜欢
      • 2015-09-10
      • 2018-01-09
      • 2010-09-20
      • 2017-05-22
      • 2016-06-02
      • 2014-06-30
      • 2021-11-06
      • 2022-01-25
      相关资源
      最近更新 更多