【问题标题】:R lookup time for very long vector很长向量的 R 查找时间
【发布时间】:2016-06-22 16:06:40
【问题描述】:

在 R 编程语言中...

我的代码中的瓶颈:

a  <-  a[b]

地点:

  • a,b 是长度为 9000 万的向量。
  • a 是一个逻辑向量。
  • ba 的索引的排列。

此操作很慢:大约需要 1.5 - 2.0 秒。

我认为直接索引会快得多,即使对于大型向量也是如此。

我只是卡住了吗?或者有什么办法可以加快速度?


上下文:

P 是一个大矩阵(10k 行,5k 列)。

行 = 名称,列 = 特征。值 = 实数。

问题:给定一个名字的子集,我需要得到矩阵Q,其中:

  • Q 的每一列都已排序(独立于 Q 的其他列)。
  • Q 列中的值来自 P 的对应列,并且仅来自 P 中给定名称子集中的行。

这是一个简单的实现:

Psub  <-  P[names,]
Q  <-  sapply( Psub , sort )

但是我得到了 10,000 个不同的名称子集(每个子集占总数的 20% 到 90%)。每次获取子集和排序都非常慢。

相反,我可以预先计算顺序向量:

b  <-  sapply( P , order )

b  <-  convert_to_linear_index( as.data.frame(b) , dim(P) )
# my own function. 
# Now b is a vector of length  nrow(P) * ncol(P)

a  <-  rownames(P)  %in%  myNames
a  <-  rep(a , ncol(P) )

a  <-  a[b]

a  <-  as.matrix(a , nrow = length(myNames) )

【问题讨论】:

  • 你认为什么是快?对于那种大小的向量,这对我来说似乎并不慢......
  • 我必须这样做 10k 次
  • 您能否为您的实际问题提供更多背景信息?
  • 您可以尝试使用 Rcpp。它(你的整个 10k 循环的东西)可能会更快。
  • @nrussell 我添加了上下文。

标签: r indexing lookup


【解决方案1】:

我不认为这会比这更快。您可以尝试编写一个优化的 C 函数来做到这一点,这可能会将时间缩短一半左右(这是乐观的——像这样的矢量化 R 操作没有太多开销),但仅此而已。

您需要处理大约 10^8 个值。每次通过内部循环,它需要递增迭代器,从内存中获取索引b[i],查找a[b[i]],然后将该值保存到newa[i]。我绝对不是编译器/汇编专家,但这听起来像是 5-10 条指令的顺序,这意味着您正在查看总共 10 亿条指令的“大 O”,因此存在时钟速率限制这能跑多快。

另外,R 将逻辑值存储为 32 位整数,因此数组 a 将占用大约 400 兆字节,这不适合缓存,所以如果 b 或多或少是随机排列,那么你' 会定期丢失缓存(事实上,在大多数查找 a 时)。同样,我不是专家,但我认为这里的缓存未命中很可能是瓶颈,如果是这种情况,优化的 C 将无济于事。

除了用 C 语言编写之外,要做的另一件事是确定您是否可以做出任何假设,以免您遍历整个数组。例如,如果您知道大多数索引不会发生变化,并且您可以找出哪些会发生变化,那么您可能会使其运行得更快。

编辑时,这里有一些数字。我有一个时钟速度为 2.8GHz 的 AMD。随机排列(即大量缓存未命中)需要 3.4 秒,1:nn:1(即很少缓存未命中)需要 0.7 秒,这分为 0.6 秒的执行时间和 0.1 秒的系统时间,大概是分配新数组。所以看起来缓存未命中是问题所在。也许优化后的 C 代码可以将基本时间缩短 0.2 或 0.3 秒,但如果排列是随机的,那不会有太大区别。

> x<-sample(c(T,F),90*10**6,T)
> prm<-sample(90*10**6)
> prm1<-1:length(prm)
> prm2<-rev(prm1)
> system.time(x<-x[prm])
   user  system elapsed 
  3.317   0.116   3.436 
> system.time(x<-x[prm1])
   user  system elapsed 
  0.593   0.140   0.734 
> system.time(x<-x[prm2])
   user  system elapsed 
  0.631   0.112   0.743 
>

【讨论】:

  • 关于缓存的好点。我正在研究 R 包bit,它以每位一个元素存储逻辑向量。这将 90x10^6 逻辑向量从 360 Mb 减少到 11.25 Mb 内存。这足以放入缓存吗?
  • 您需要检查 CPU 上的缓存,但可能不需要,至少 L2 中没有,可能 L3 中。要记住的另一件事是使用位向量是有成本的,因为保存和加载它们的速度较慢。我的 L2 是 2 Mb,L3 是 16Mb,这意味着如果排列是随机的,我在大多数情况下仍然会丢失 L2,在这种情况下,由于额外的开销,bitvec 可能会更慢。但值得一试。
猜你喜欢
  • 1970-01-01
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多