【问题标题】:How to efficiently use Rprof in R?如何在 R 中有效地使用 Rprof?
【发布时间】:2011-04-08 17:30:04
【问题描述】:

我想知道是否可以通过类似于matlab 的 Profiler 的方式从 R-Code 获取配置文件。也就是说,要知道哪些行号是特别慢的。

到目前为止,我所取得的成绩并不令人满意。我使用Rprof 为我制作了个人资料文件。使用 summaryRprof 我得到如下内容:

$by.self
                  self.time self.pct total.time total.pct
[.data.frame               0.72     10.1       1.84      25.8
inherits                   0.50      7.0       1.10      15.4
data.frame                 0.48      6.7       4.86      68.3
unique.default             0.44      6.2       0.48       6.7
deparse                    0.36      5.1       1.18      16.6
rbind                      0.30      4.2       2.22      31.2
match                      0.28      3.9       1.38      19.4
[<-.factor                 0.28      3.9       0.56       7.9
levels                     0.26      3.7       0.34       4.8
NextMethod                 0.22      3.1       0.82      11.5
...

$by.total
                      total.time total.pct self.time self.pct
data.frame                  4.86      68.3      0.48      6.7
rbind                       2.22      31.2      0.30      4.2
do.call                     2.22      31.2      0.00      0.0
[                           1.98      27.8      0.16      2.2
[.data.frame                1.84      25.8      0.72     10.1
match                       1.38      19.4      0.28      3.9
%in%                        1.26      17.7      0.14      2.0
is.factor                   1.20      16.9      0.10      1.4
deparse                     1.18      16.6      0.36      5.1
...

说实话,从这个输出中我没有找到我的瓶颈在哪里,因为 (a) 我经常使用 data.frame 并且 (b) 我从不使用例如 deparse。还有,[是什么?

所以我尝试了 Hadley Wickham 的 profr,但考虑到下图,它不再有用了:

有没有更方便的方法来查看哪些行号和特定的函数调用很慢?
或者,我应该查阅一些文献吗?

任何提示表示赞赏。

编辑 1:
根据 Hadley 的评论,我将在下面粘贴我的脚本代码和该图的基本图版本。但请注意,我的问题与此特定脚本无关。这只是我最近写的一个随机脚本。 我正在寻找一种通用的方法来找出瓶颈并加速R-code。

数据 (x) 如下所示:

type      word    response    N   Classification  classN
Abstract  ANGER   bitter      1   3a              3a
Abstract  ANGER   control     1   1a              1a
Abstract  ANGER   father      1   3a              3a
Abstract  ANGER   flushed     1   3a              3a
Abstract  ANGER   fury        1   1c              1c
Abstract  ANGER   hat         1   3a              3a
Abstract  ANGER   help        1   3a              3a
Abstract  ANGER   mad         13  3a              3a
Abstract  ANGER   management  2   1a              1a
... until row 1700

脚本(带有简短的解释)是这样的:

Rprof("profile1.out")

# A new dataset is produced with each line of x contained x$N times 
y <- vector('list',length(x[,1]))
for (i in 1:length(x[,1])) {
  y[[i]] <- data.frame(rep(x[i,1],x[i,"N"]),rep(x[i,2],x[i,"N"]),rep(x[i,3],x[i,"N"]),rep(x[i,4],x[i,"N"]),rep(x[i,5],x[i,"N"]),rep(x[i,6],x[i,"N"]))
}
all <- do.call('rbind',y)
colnames(all) <- colnames(x)

# create a dataframe out of a word x class table
table_all <- table(all$word,all$classN)
dataf.all <- as.data.frame(table_all[,1:length(table_all[1,])])
dataf.all$words <- as.factor(rownames(dataf.all))
dataf.all$type <- "no"
# get type of the word.
words <- levels(dataf.all$words)
for (i in 1:length(words)) {
  dataf.all$type[i] <- as.character(all[pmatch(words[i],all$word),"type"])
}
dataf.all$type <- as.factor(dataf.all$type)
dataf.all$typeN <- as.numeric(dataf.all$type)

# aggregate response categories
dataf.all$c1 <- apply(dataf.all[,c("1a","1b","1c","1d","1e","1f")],1,sum)
dataf.all$c2 <- apply(dataf.all[,c("2a","2b","2c")],1,sum)
dataf.all$c3 <- apply(dataf.all[,c("3a","3b")],1,sum)

Rprof(NULL)

library(profr)
ggplot.profr(parse_rprof("profile1.out"))

最终数据如下所示:

1a    1b  1c  1d  1e  1f  2a  2b  2c  3a  3b  pa  words   type    typeN   c1  c2  c3  pa
3 0   8   0   0   0   0   0   0   24  0   0   ANGER   Abstract    1   11  0   24  0
6 0   4   0   1   0   0   11  0   13  0   0   ANXIETY Abstract    1   11  11  13  0
2 11  1   0   0   0   0   4   0   17  0   0   ATTITUDE    Abstract    1   14  4   17  0
9 18  0   0   0   0   0   0   0   0   8   0   BARREL  Concrete    2   27  0   8   0
0 1   18  0   0   0   0   4   0   12  0   0   BELIEF  Abstract    1   19  4   12  0

基础图表:

Running the script today also changed the ggplot2 graph a little (basically only the labels), see here.

【问题讨论】:

  • 您可以尝试使用plot 代替ggplot 与profr 吗?查看您的原始代码也很有用。
  • 我已经厌倦了指出这一点。基于与 gprof 中相同想法的分析器具有相同的错误。所有这些关于自我时间、函数而不是线、图形和一般测量的业务,都是相同的过热无用的概念。有一些简单的方法:*.com/questions/1777556/alternatives-to-gprof/…
  • @hadely:查看我的编辑。 @Mike:我发现问题而不是衡量某事。基本上不相关的是你的观点。听起来和我要找的完全一样。但这是否在 R 中的某个地方实现?
  • @Henrik:刚刚有人给了我一票,把我的注意力带回到这里。事实上,我使用了 Rprof,但只是为了(以大间隔)取样,而不是“分析”它们。样本最终保存在一个文件中,我只是查看它们。尽管它们不包含行号信息,但它们可以工作。如果函数 A 在两个地方调用函数 B,我会改为让 A 调用 B1 和 B2,而那些人调用 B。这样我就可以知道调用来自 A 中的哪个位置。 Kludgy,但它完成了工作。

标签: r profiling profiler


【解决方案1】:

提醒昨天的读者breaking newsR 3.0.0 终于出来了)可能已经注意到与这个问题直接相关的一些有趣的事情:

  • 现在通过 Rprof() 进行分析可以选择在语句级别记录信息,而不仅仅是函数级别。

事实上,这个新功能回答了我的问题,我将展示如何。


比方说,我们想比较向量化和预分配在计算诸如平均值之类的汇总统计数据时是否真的比旧的 for 循环和增量数据构建更好。相对愚蠢的代码如下:

# create big data frame:
n <- 1000
x <- data.frame(group = sample(letters[1:4], n, replace=TRUE), condition = sample(LETTERS[1:10], n, replace = TRUE), data = rnorm(n))

# reasonable operations:
marginal.means.1 <- aggregate(data ~ group + condition, data = x, FUN=mean)

# unreasonable operations:
marginal.means.2 <- marginal.means.1[NULL,]

row.counter <- 1
for (condition in levels(x$condition)) {
  for (group in levels(x$group)) {  
    tmp.value <- 0
    tmp.length <- 0
    for (c in 1:nrow(x)) {
      if ((x[c,"group"] == group) & (x[c,"condition"] == condition)) {
        tmp.value <- tmp.value + x[c,"data"]
        tmp.length <- tmp.length + 1
      }
    }
    marginal.means.2[row.counter,"group"] <- group 
    marginal.means.2[row.counter,"condition"] <- condition
    marginal.means.2[row.counter,"data"] <- tmp.value / tmp.length
    row.counter <- row.counter + 1
  }
}

# does it produce the same results?
all.equal(marginal.means.1, marginal.means.2)

要将此代码与Rprof 一起使用,我们需要parse 它。也就是说,它需要保存在一个文件中,然后从那里调用。因此,我将它上传到pastebin,但它与本地文件完全相同。

现在,我们

  • 只需创建一个配置文件并指明我们要保存的行号,
  • 使用令人难以置信的组合 eval(parse(..., keep.source = TRUE)) 获取代码(似乎臭名昭著的 fortune(106) 不适用于此处,因为我还没有找到其他方法)
  • 停止分析并指示我们需要基于行号的输出。

代码是:

Rprof("profile1.out", line.profiling=TRUE)
eval(parse(file = "http://pastebin.com/download.php?i=KjdkSVZq", keep.source=TRUE))
Rprof(NULL)

summaryRprof("profile1.out", lines = "show")

这给出了:

$by.self
                           self.time self.pct total.time total.pct
download.php?i=KjdkSVZq#17      8.04    64.11       8.04     64.11
<no location>                   4.38    34.93       4.38     34.93
download.php?i=KjdkSVZq#16      0.06     0.48       0.06      0.48
download.php?i=KjdkSVZq#18      0.02     0.16       0.02      0.16
download.php?i=KjdkSVZq#23      0.02     0.16       0.02      0.16
download.php?i=KjdkSVZq#6       0.02     0.16       0.02      0.16

$by.total
                           total.time total.pct self.time self.pct
download.php?i=KjdkSVZq#17       8.04     64.11      8.04    64.11
<no location>                    4.38     34.93      4.38    34.93
download.php?i=KjdkSVZq#16       0.06      0.48      0.06     0.48
download.php?i=KjdkSVZq#18       0.02      0.16      0.02     0.16
download.php?i=KjdkSVZq#23       0.02      0.16      0.02     0.16
download.php?i=KjdkSVZq#6        0.02      0.16      0.02     0.16

$by.line
                           self.time self.pct total.time total.pct
<no location>                   4.38    34.93       4.38     34.93
download.php?i=KjdkSVZq#6       0.02     0.16       0.02      0.16
download.php?i=KjdkSVZq#16      0.06     0.48       0.06      0.48
download.php?i=KjdkSVZq#17      8.04    64.11       8.04     64.11
download.php?i=KjdkSVZq#18      0.02     0.16       0.02      0.16
download.php?i=KjdkSVZq#23      0.02     0.16       0.02      0.16

$sample.interval
[1] 0.02

$sampling.time
[1] 12.54

检查source code 告诉我们有问题的行(#17)确实是for循环中愚蠢的if语句。与使用矢量化代码(第 6 行)基本没有时间进行计算相比。

我还没有尝试过任何图形输出,但我已经对我目前所得到的印象深刻。

【讨论】:

  • 为什么不用source("http://pastebin.com/download.php?i=KjdkSVZq") 而不是eval(parse(..., keep.source = TRUE))
  • 它能否通过源代码行判断该行在堆栈上的时间比例是多少?这就是“total.pct”吗?
  • 是否需要解析?我不能直接在 Rprof 行之间给出 R 表达式吗?
  • @Avinash 不,请参阅上面 flodel 的评论。您可以简单地获取它。如果其他版本也可以使用,您需要自行尝试。
  • 我对类似问题的解决方案(我在发布我的问题后发现了这个问题),也可能会有所帮助:How does one interpret the output from profr::profr?
【解决方案2】:

更新:此函数已被重写以处理行号。它在github上here

我编写了这个函数来解析来自Rprof 的文件并输出一个比summaryRprof 更清晰的结果表。它显示完整的函数堆栈(如果line.profiling=TRUE 则显示行号),以及它们对运行时间的相对贡献:

proftable <- function(file, lines=10) {
# require(plyr)
  interval <- as.numeric(strsplit(readLines(file, 1), "=")[[1L]][2L])/1e+06
  profdata <- read.table(file, header=FALSE, sep=" ", comment.char = "",
                         colClasses="character", skip=1, fill=TRUE,
                         na.strings="")
  filelines <- grep("#File", profdata[,1])
  files <- aaply(as.matrix(profdata[filelines,]), 1, function(x) {
                        paste(na.omit(x), collapse = " ") })
  profdata <- profdata[-filelines,]
  total.time <- interval*nrow(profdata)
  profdata <- as.matrix(profdata[,ncol(profdata):1])
  profdata <- aaply(profdata, 1, function(x) {
                      c(x[(sum(is.na(x))+1):length(x)],
                        x[seq(from=1,by=1,length=sum(is.na(x)))])
              })
  stringtable <- table(apply(profdata, 1, paste, collapse=" "))
  uniquerows <- strsplit(names(stringtable), " ")
  uniquerows <- llply(uniquerows, function(x) replace(x, which(x=="NA"), NA))
  dimnames(stringtable) <- NULL
  stacktable <- ldply(uniquerows, function(x) x)
  stringtable <- stringtable/sum(stringtable)*100
  stacktable <- data.frame(PctTime=stringtable[], stacktable)
  stacktable <- stacktable[order(stringtable, decreasing=TRUE),]
  rownames(stacktable) <- NULL
  stacktable <- head(stacktable, lines)
  na.cols <- which(sapply(stacktable, function(x) all(is.na(x))))
  stacktable <- stacktable[-na.cols]
  parent.cols <- which(sapply(stacktable, function(x) length(unique(x)))==1)
  parent.call <- paste0(paste(stacktable[1,parent.cols], collapse = " > ")," >")
  stacktable <- stacktable[,-parent.cols]
  calls <- aaply(as.matrix(stacktable[2:ncol(stacktable)]), 1, function(x) {
                   paste(na.omit(x), collapse= " > ")
                     })
  stacktable <- data.frame(PctTime=stacktable$PctTime, Call=calls)
  frac <- sum(stacktable$PctTime)
  attr(stacktable, "total.time") <- total.time
  attr(stacktable, "parent.call") <- parent.call
  attr(stacktable, "files") <- files
  attr(stacktable, "total.pct.time") <- frac
  cat("\n")
  print(stacktable, row.names=FALSE, right=FALSE, digits=3)
  cat("\n")
  cat(paste(files, collapse="\n"))
  cat("\n")
  cat(paste("\nParent Call:", parent.call))
  cat(paste("\n\nTotal Time:", total.time, "seconds\n"))
  cat(paste0("Percent of run time represented: ", format(frac, digits=3)), "%")

  invisible(stacktable)
}

在 Henrik 的示例文件上运行它,我得到了这个:

> Rprof("profile1.out", line.profiling=TRUE)
> source("http://pastebin.com/download.php?i=KjdkSVZq")
> Rprof(NULL)
> proftable("profile1.out", lines=10)

 PctTime Call                                                      
 20.47   1#17 > [ > 1#17 > [.data.frame                            
  9.73   1#17 > [ > 1#17 > [.data.frame > [ > [.factor             
  8.72   1#17 > [ > 1#17 > [.data.frame > [ > [.factor > NextMethod
  8.39   == > Ops.factor                                           
  5.37   ==                                                        
  5.03   == > Ops.factor > noNA.levels > levels                    
  4.70   == > Ops.factor > NextMethod                              
  4.03   1#17 > [ > 1#17 > [.data.frame > [ > [.factor > levels    
  4.03   1#17 > [ > 1#17 > [.data.frame > dim                      
  3.36   1#17 > [ > 1#17 > [.data.frame > length                   

#File 1: http://pastebin.com/download.php?i=KjdkSVZq

Parent Call: source > withVisible > eval > eval >

Total Time: 5.96 seconds
Percent of run time represented: 73.8 %

请注意,“父调用”适用于表上表示的所有堆栈。当您的 IDE 或任何调用您的代码将其包装在一堆函数中时,这非常有用。

【讨论】:

  • 看起来不错。但是有没有机会获得我们在哪一行的信息(即,从哪一行调用了堆栈)?
  • 这是个好消息。您应该知道,仍然有一个 bug in the current implementation(但可能不在 R 开发中)。
  • 我重写了函数来处理行号,同时也提高了长堆栈的可读性。在此处获取代码:github.com/noamross/noamtools/blob/master/R/proftable.R
  • + @Noam:刚刚看到你的答案。我也使用了rprof,但我不进行后期处理,我只是查看随机选择的原始堆栈样本。我的版本在堆栈示例中没有行号(或者它可能有,但我没有意识到)。无论如何,它完成了工作。
  • @naught101 这不是错误。它实际上是 plyr::aaply。你可以在函数顶部取消注释require(plyr),或者在github.com/noamross/noamtools安装包含这个的包
【解决方案3】:

我目前在这里卸载了 R,但在 SPlus 中,您可以使用 Escape 键中断执行,然后执行 traceback(),这将显示调用堆栈。这应该使您能够使用this handy method

Here are some reasons why 工具基于与 gprof 相同的概念构建,但并不擅长定位性能问题。

【讨论】:

  • 看起来该问题已被删除。您是否知道有关该主题的任何其他信息来源(如您在上面的评论中所说,围绕这些“过热的无用概念”的方法)?
  • @naught101:那个帖子没有消失,你只需要足够的代表。我是这个主题的主要煽动者,我真的很想不这样做。这里的另一个链接,“这个方便的方法”在没有太多火焰的情况下把它拼出来。简而言之,没有分析器可以像人类那样分析堆栈样本,任何值得修复的瓶颈都可以快速找到,并且修复每个瓶颈会使其他瓶颈更容易找到,因此您可以继续滚动。 “CPU 分析”错过了 IO。递归不是问题。测量的准确性并不重要,“自我时间”、通话次数等也不重要。
  • 人力资源部。听起来很有用,但在分析和相关活动方面我有点菜鸟。如果安装了 R 的人可以将此答案翻译成我可以在 R 中使用的方法,那就太好了。
  • @naught101:运行rprof(您可能需要翻找一下文档)。当我运行它时,我将采样率设置得非常低,所以我不会得到大量的样本。它生成堆栈样本的文本文件。我所做的就是看看那个。如果你看到它在 10 个堆栈样本中的 5 个上做某事,这意味着如果你可以加快你看到它做的事情,你可能会节省大约 50% 的时间,无论是付出还是付出。这是一个很大的节省。
【解决方案4】:

不同的解决方案来自不同的问题:how to effectively use library(profr) in R:

例如:

install.packages("profr")
devtools::install_github("alexwhitworth/imputation")

x <- matrix(rnorm(1000), 100)
x[x>1] <- NA
library(imputation)
library(profr)
a <- profr(kNN_impute(x, k=5, q=2), interval= 0.005)

似乎(至少对我而言)这些情节在这里完全没有帮助(例如plot(a))。但数据结构本身似乎确实提出了一个解决方案:

R> head(a, 10)
   level g_id t_id                f start   end n  leaf  time     source
9      1    1    1       kNN_impute 0.005 0.190 1 FALSE 0.185 imputation
10     2    1    1        var_tests 0.005 0.010 1 FALSE 0.005       <NA>
11     2    2    1            apply 0.010 0.190 1 FALSE 0.180       base
12     3    1    1         var.test 0.005 0.010 1 FALSE 0.005      stats
13     3    2    1              FUN 0.010 0.110 1 FALSE 0.100       <NA>
14     3    2    2              FUN 0.115 0.190 1 FALSE 0.075       <NA>
15     4    1    1 var.test.default 0.005 0.010 1 FALSE 0.005       <NA>
16     4    2    1           sapply 0.010 0.040 1 FALSE 0.030       base
17     4    3    1    dist_q.matrix 0.040 0.045 1 FALSE 0.005 imputation
18     4    4    1           sapply 0.045 0.075 1 FALSE 0.030       base

单次迭代解:

即数据结构建议使用tapply来汇总数据。对于profr::profr的单次运行,这可以非常简单地完成

t <- tapply(a$time, paste(a$source, a$f, sep= "::"), sum)
t[order(t)] # time / function
R> round(t[order(t)] / sum(t), 4) # percentage of total time / function

base::!                    base::%in%                       base::|           base::anyDuplicated 
                       0.0015                        0.0015                        0.0015                        0.0015 
                      base::c                 base::deparse                     base::get                   base::match 
                       0.0015                        0.0015                        0.0015                        0.0015 
                   base::mget                     base::min                       base::t                   methods::el 
                       0.0015                        0.0015                        0.0015                        0.0015 
          methods::getGeneric        NA::.findMethodInTable               NA::.getGeneric      NA::.getGenericFromCache 
                       0.0015                        0.0015                        0.0015                        0.0015 
NA::.getGenericFromCacheTable                   NA::.identC             NA::.newSignature        NA::.quickCoerceSelect 
                       0.0015                        0.0015                        0.0015                        0.0015 
                NA::.sigLabel          NA::var.test.default                 NA::var_tests               stats::var.test 
                       0.0015                        0.0015                        0.0015                        0.0015 
                  base::paste                 methods::as<-     NA::.findInheritedMethods        NA::.getClassFromCache 
                       0.0030                        0.0030                        0.0030                        0.0030 
               NA::doTryCatch              NA::tryCatchList               NA::tryCatchOne               base::crossprod 
                       0.0030                        0.0030                        0.0030                        0.0045 
                    base::try                base::tryCatch          methods::getClassDef      methods::possibleExtends 
                       0.0045                        0.0045                        0.0045                        0.0045 
          methods::loadMethod                   methods::is     imputation::dist_q.matrix          methods::validObject 
                       0.0075                        0.0090                        0.0120                        0.0136 
       NA::.findNextFromTable        methods::addNextMethod               NA::.nextMethod                  base::lapply 
                       0.0166                        0.0346                        0.0361                        0.0392 
                 base::sapply     imputation::impute_fn_knn                  methods::new        imputation::kNN_impute 
                       0.0392                        0.0392                        0.0437                        0.0557 
      methods::callNextMethod      kernlab::as.kernelMatrix                   base::apply         kernlab::kernelMatrix 
                       0.0572                        0.0633                        0.0663                        0.0753 
          methods::initialize                       NA::FUN         base::standardGeneric 
                       0.0798                        0.0994                        0.1325 

由此,我可以看到用户最多的时间是 kernlab::kernelMatrix 以及来自 R 的 S4 类和泛型的开销。

首选:

我注意到,鉴于采样过程的随机性,我更喜欢使用平均值来获得更可靠的时间分布图:

prof_list <- replicate(100, profr(kNN_impute(x, k=5, q=2), 
    interval= 0.005), simplify = FALSE)

fun_timing <- vector("list", length= 100)
for (i in 1:100) {
  fun_timing[[i]] <- tapply(prof_list[[i]]$time, paste(prof_list[[i]]$source, prof_list[[i]]$f, sep= "::"), sum)
}

# Here is where the stochastic nature of the profiler complicates things.
# Because of randomness, each replication may have slightly different 
# functions called during profiling
sapply(fun_timing, function(x) {length(names(x))})

# we can also see some clearly odd replications (at least in my attempt)
> sapply(fun_timing, sum)
[1]    2.820    5.605    2.325    2.895    3.195    2.695    2.495    2.315    2.005    2.475    4.110    2.705    2.180    2.760
 [15] 3130.240    3.435    7.675    7.155    5.205    3.760    7.335    7.545    8.155    8.175    6.965    5.820    8.760    7.345
 [29]    9.815    7.965    6.370    4.900    5.720    4.530    6.220    3.345    4.055    3.170    3.725    7.780    7.090    7.670
 [43]    5.400    7.635    7.125    6.905    6.545    6.855    7.185    7.610    2.965    3.865    3.875    3.480    7.770    7.055
 [57]    8.870    8.940   10.130    9.730    5.205    5.645    3.045    2.535    2.675    2.695    2.730    2.555    2.675    2.270
 [71]    9.515    4.700    7.270    2.950    6.630    8.370    9.070    7.950    3.250    4.405    3.475    6.420 2948.265    3.470
 [85]    3.320    3.640    2.855    3.315    2.560    2.355    2.300    2.685    2.855    2.540    2.480    2.570    3.345    2.145
 [99]    2.620    3.650

删除异常复制并转换为data.frames:

fun_timing <- fun_timing[-c(15,83)]
fun_timing2 <- lapply(fun_timing, function(x) {
  ret <- data.frame(fun= names(x), time= x)
  dimnames(ret)[[1]] <- 1:nrow(ret)
  return(ret)
})

合并复制(几乎可以肯定会更快)并检查结果:

# function for merging DF's in a list
merge_recursive <- function(list, ...) {
  n <- length(list)
  df <- data.frame(list[[1]])
  for (i in 2:n) {
    df <- merge(df, list[[i]], ... = ...)
  }
  return(df)
}

# merge
fun_time <- merge_recursive(fun_timing2, by= "fun", all= FALSE)
# do some munging
fun_time2 <- data.frame(fun=fun_time[,1], avg_time=apply(fun_time[,-1], 1, mean, na.rm=T))
fun_time2$avg_pct <- fun_time2$avg_time / sum(fun_time2$avg_time)
fun_time2 <- fun_time2[order(fun_time2$avg_time, decreasing=TRUE),]
# examine results
R> head(fun_time2, 15)
                         fun  avg_time    avg_pct
4      base::standardGeneric 0.6760714 0.14745123
20                   NA::FUN 0.4666327 0.10177262
12       methods::initialize 0.4488776 0.09790023
9      kernlab::kernelMatrix 0.3522449 0.07682464
8   kernlab::as.kernelMatrix 0.3215816 0.07013698
11   methods::callNextMethod 0.2986224 0.06512958
1                base::apply 0.2893367 0.06310437
7     imputation::kNN_impute 0.2433163 0.05306731
14              methods::new 0.2309184 0.05036331
10    methods::addNextMethod 0.2012245 0.04388708
3               base::sapply 0.1875000 0.04089377
2               base::lapply 0.1865306 0.04068234
6  imputation::impute_fn_knn 0.1827551 0.03985890
19           NA::.nextMethod 0.1790816 0.03905772
18    NA::.findNextFromTable 0.1003571 0.02188790

结果

从结果来看,一个类似但更可靠的情况出现在一个案例中。也就是说,R 有很多开销,而且library(kernlab) 让我慢了下来。值得注意的是,由于kernlab 是在 S4 中实现的,因此 R 中的开销是相关的,因为 S4 类比 S3 类慢得多。

我还要注意,我个人的观点是,它的清理版本可能是一个有用的拉取请求,作为profr 的摘要方法。虽然我很想看看其他人的建议!

【讨论】:

    最近更新 更多