【问题标题】:R - faster alternative to hist(XX, plot=FALSE)$countR - hist(XX, plot=FALSE)$count 的更快替代方案
【发布时间】:2016-07-18 12:58:55
【问题描述】:

我正在寻找 R 的 hist(x, breaks=XXX, plot=FALSE)$count 函数的更快替代方案,因为我不需要生成的任何其他输出(因为我想在 sapply 调用中使用它,需要 100 万次迭代将在其中调用此函数),例如

x = runif(100000000, 2.5, 2.6)
bincounts = hist(x, breaks=seq(0,3,length.out=100), plot=FALSE)$count

有什么想法吗?

【问题讨论】:

  • 也许可以查看hist.default 的代码并扔掉不需要的部分?例如,是否存在无限数? hist 进行检查。
  • 好吧,调用 .Call(C_BinCount, x,fuzzybreaks, right, include.lowest) 似乎很容易——从任何常规脚本中调用它的最佳方法是什么?我只有有限的值。
  • 在每次迭代中,您是创建一个新的x 还是使用相同的x?如果x 在您的sapply 期间相同,请考虑在开始时使用sort,因为它通常会减少hist/findInterval 中的任何一个的计算时间
  • 哈哈,这都是不同的向量!

标签: r histogram binning


【解决方案1】:

第一次尝试使用tablecut

table(cut(x, breaks=seq(0,3,length.out=100)))

它避免了额外的输出,但在我的电脑上大约需要 34 秒:

system.time(table(cut(x, breaks=seq(0,3,length.out=100))))
   user  system elapsed 
 34.148   0.532  34.696 

hist 的 3.5 秒相比:

system.time(hist(x, breaks=seq(0,3,length.out=100), plot=FALSE)$count)
   user  system elapsed 
  3.448   0.156   3.605

使用tabulate.bincode 运行速度比hist 快一点:

tabulate(.bincode(x, breaks=seq(0,3,length.out=100)), nbins=100)

system.time(tabulate(.bincode(x, breaks=seq(0,3,length.out=100))), nbins=100)
   user  system elapsed 
  3.084   0.024   3.107

使用tablulatefindInterval 相对于tablecut 提供了显着的性能提升,并且相对于hist 有一个不错的改进:

tabulate(findInterval(x, vec=seq(0,3,length.out=100)), nbins=100)

system.time(tabulate(findInterval(x, vec=seq(0,3,length.out=100))), nbins=100)
   user  system elapsed 
  2.044   0.012   2.055

【讨论】:

  • 是的,但是这个问题是它太慢了......所以这对我来说不是一个选择,因为我必须迭代它 100 万次......
  • 是的。 hist 似乎快了大约 10 倍。我现在正在尝试多种替代方案,看看是否能找到任何加快速度。
  • 对不起,只是注意到一个问题 - 似乎在制表中您仍然需要添加参数 nbins=length(x) 以匹配 hist() 的输出
  • 我通过减少开销又获得了 10% 的加速:.Internal(tabulate(.Internal(findInterval(breaks, x, FALSE, FALSE)), 100L))
  • 只需在控制台输入tabulate查看tabulatefindInterval的代码
【解决方案2】:

看来你最好的办法是去掉hist.default 的所有开销。

nB1 <- 99
delt <- 3/nB1
fuzz <- 1e-7 * c(-delt, rep.int(delt, nB1))
breaks <- seq(0, 3, by = delt) + fuzz

.Call(graphics:::C_BinCount, x, breaks, TRUE, TRUE)

我通过运行debugonce(hist.default) 来减少这一点,以了解hist 的工作原理(并使用更小的向量进行测试——n = 100 而不是1000000)。

比较:

x = runif(100, 2.5, 2.6)
y1 <- .Call(graphics:::C_BinCount, x, breaks + fuzz, TRUE, TRUE)
y2 <- hist(x, breaks=seq(0,3,length.out=100), plot=FALSE)$count
identical(y1, y2)
# [1] TRUE

【讨论】:

  • @TomWenseleers 不管这很慢很奇怪......为什么hist 不只是调用tabulate(findInterval) 如果它更好?我想知道使用graphics::: 是否有很大的开销...
猜你喜欢
  • 2010-12-22
  • 2022-01-09
  • 2020-11-14
  • 2023-01-17
  • 2018-12-11
  • 2012-07-05
  • 2012-01-23
  • 2013-07-13
相关资源
最近更新 更多