如何在R中有效使用Rprof?


68

我想知道是否有可能从 R类似于-Profiler的方式-Codematlab。也就是说,要了解哪些行号特别慢。

到目前为止,我所取得的成就并不令人满意。我曾经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)我从未使用过eg deparse。此外,什么是[

所以我尝试了哈德利·威克姆(Hadley Wickham)的 profr,但考虑到下图,它不再有用: 替代文字

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

任何提示表示赞赏。

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

数据(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

基本图图: 替代文字

今天运行脚本还稍微改变了ggplot2图(基本上仅是标签),请参见此处。


你可以尝试使用plot,而不是ggplot与profr?查看原始代码也很有用。
哈德利2010年

3
我讨厌指出这一点。基于与gprof中相同的思想的事件探查器具有相同的错误。所有这些关于自拍时间,功能(而不是线条,图形和测量)的事情,都是经过预热的无用概念。大约有它简单的方法:stackoverflow.com/questions/1777556/alternatives-to-gprof/...
麦克Dunlavey

1
@hadely:看我的编辑。@迈克:我明白了发现问题而不是衡量某事。基本上无关的是您的观点。听起来完全符合我的要求。但这是在R中的某个地方实现的吗?
亨里克(Henrik)2010年

@Henrik:有人刚给我投票,让我的注意力回到了这里。实际上,我使用了Rprof,但只是(以较大的间隔)取样,而不是“分析”它们。样本最终保存在一个文件中,我只是看一下它们。尽管它们不包含行号信息,但它们可以工作。如果函数A在两个地方调用了函数B,则我改为让A调用B1和B2,而那些家伙则调用B。这样,我就可以知道这些调用来自哪里。Kludgy,但工作完成了。
Mike Dunlavey 2013年

Answers:


51

提醒读者注意昨天的突发新闻R 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

检查源代码可以发现有问题的行(#17)确实是愚蠢的if是for循环中语句。与基本上没有时间使用矢量化代码进行计算(第6行)相比。

我还没有尝试过任何图形输出,但是到目前为止,我已经对它印象深刻。


6
为什么不source("http://pastebin.com/download.php?i=KjdkSVZq")代替eval(parse(..., keep.source = TRUE))呢?
flodel

它可以按源代码行告诉该行在堆栈中的时间比例是多少?那是什么“ total.pct”?
Mike Dunlavey

解析是必要的吗?我不能只在Rprof行之间直接给出R表达式吗?
Avinash 2014年

1
@Avinash不,请参见上面的弗洛德尔评论。您可以简单地获取它。如果其他版本也可以使用,则需要自己尝试。
亨里克

我对类似问题的解决方案(我在发布我的问题后发现了这个问题)也可能会有所帮助:如何解释profr :: profr的输出?
Alex W

11

更新:此功能已被重写以处理行号。这是在github这里

我编写了此函数来解析文件,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或任何调用您的代码将其包装在许多函数中时,这将很有用。


看起来不错。但是,是否有机会获得我们所在的行的信息(即,从堆栈调用的那一行)?
Henrik

那是个好消息。您应该意识到,当前的实现中仍然存在一个错误(但可能不是R devel中的错误)。
亨里克

我重写了该函数以处理行号,并提高了长堆栈的可读性。在此处获取代码:github.com/noamross/noamtools/blob/master/R/proftable.R
Noam Ross

+ @Noam:刚刚看到了您的答案。我也使用过rprof,但是我不进行后处理,我只是看原始堆栈样本的随机选择。我的版本在堆栈样本中没有行号(或者可能有行号,但我没有意识到)。无论如何,它完成了工作。
Mike Dunlavey 2014年

2
@ naught101这不是错误。实际上是plyr :: aaply。您可以require(plyr)在函数顶部取消注释,或在github.com/noamross/noamtools上
Noam Ross

3

我目前在这里已卸载R,但是在SPlus中,您可以使用Escape键中断执行,然后执行traceback(),这将向您显示调用堆栈。那应该使您能够使用这种方便的方法

有一些原因导致为什么gprof具有相同概念的工具不能很好地定位性能问题。


似乎该问题已删除。您是否知道有关该主题的任何其他信息来源(围绕这些“温暖的无用概念”,正如您在上面的评论中所述)?
naught101

1
@ naught101:该帖子没有消失,您只需要足够的代表。我是这方面的主要负责人,但我确实努力做到这一点。此处的另一个链接是“这种方便的方法”,将其清楚地说明了而不会燃烧太多。简而言之,没有任何分析器可以像人类罐头一样在任何地方分析堆栈样本,可以快速找到任何需要修复的瓶颈,并且修复每个瓶颈使其他问题更容易找到,因此您可以继续滚动。“ CPU分析”错过了IO。递归不是问题。测量精度并不重要,也不是“自我时间”,也没有调用次数,等等,等等
麦克Dunlavey

嗯 听起来很有用,但是在进行概要分析和相关活动时我有点菜鸟。这将会是巨大的,如果有人有R isntalled会这样回答翻译成一种方法,我可以在R.使用
naught101

2
@ naught101:运行rprof(您可能需要翻阅文档)。当我运行它时,我将采样率设置得非常低,所以我不会得到大量采样。它生成堆栈样本的文本文件。我所要做的就是看那件事。如果您看到它在10个堆栈样本中有5个在做某事,这意味着如果您可以加快所见即所得的工作,则可以节省大约50%的时间,付出或付出。这是一个很大的节省。
Mike Dunlavey 2014年


3

不同的解决方案来自不同的问题:如何library(profr)在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::kernelMatrixR的开销也很大以及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的摘要方法可能是有用的请求。虽然我很想看看别人的建议!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.