我目前正在研究Clojure和Incanter作为R的替代方法(并不是因为我不喜欢R,而是尝试新语言很有趣)。我喜欢Incanter,并发现语法很有吸引力,但是矢量化操作比R或Python慢得多。
举个例子,我想使用Incanter向量运算、Clojure映射和R得到向量的一阶差。下面是所有版本的代码和时间。正如你所看到的,R显然更快。
Incanter和Clojure:
(use '(incanter core stats))
(def x (doall (sample-normal 1e7)))
(time (def y (doall (minus (rest x) (butlast x)))))
"Elapsed time: 16481.337 msecs"
(time (def y (doall (map - (rest x) (butlast x)))))
"Elapsed time: 16457.850 msecs"R:
rdiff <- function(x){
n = length(x)
x[2:n] - x[1:(n-1)]}
x = rnorm(1e7)
system.time(rdiff(x))
user system elapsed
1.504 0.900 2.561所以我想知道是否有一种方法来加速Incanter/Clojure中的向量运算?此外,还欢迎使用Clojure的循环、Java数组和/或库的解决方案。
我还向Incanter集团发布了这个问题,到目前为止还没有得到任何回应。
更新:我已经将Jouni的答案标记为已被接受,请参阅下面关于我自己的答案,其中我已经稍微清理了他的代码,并添加了一些基准测试。
发布于 2010-09-28 20:29:55
这里有一个Java数组实现,它在我的系统上比您的R代码(YMMV)更快。注意,启用反射警告是优化性能时必不可少的,重复的类型提示对y( def上的提示似乎无助于aset),并将所有内容转换为基本的双值(dotime确保我是一个原始int)。
(set! *warn-on-reflection* true)
(use 'incanter.stats)
(def ^"[D" x (double-array (sample-normal 1e7)))
(time
(do
(def ^"[D" y (double-array (dec (count x))))
(dotimes [i (dec (count x))]
(aset ^"[D" y
i
(double (- (double (aget x (inc i)))
(double (aget x i))))))))发布于 2010-09-29 12:15:44
我的最后解决方案
经过所有的测试后,我找到了两种稍微不同的方法来以足够的速度进行计算。
首先,我使用了具有不同类型的返回值的函数diff,下面是返回向量的代码,但我还计时了返回双数组(用y替换(vec y)和用矩阵y替换Incanter.matrix (vec y) )的版本。此函数仅基于java数组。这是基于Jouni的代码,删除了一些额外的类型提示。
另一种方法是使用Java数组进行计算,并将值存储在瞬态向量中。正如您从时间上看到的,如果没有返回和数组的函数,这比方法1稍微快一些。这是在函数difft中实现的。
所以选择真的取决于你不想和数据做什么。我想一个很好的选择是重载函数,以便它返回调用中使用的相同类型。实际上,将java数组传递给diff而不是向量会使~1s更快。
不同函数的时间:
diff返回向量:
(time (def y (diff x)))
"Elapsed time: 4733.259 msecs"diff返回Incanter.matrix:
(time (def y (diff x)))
"Elapsed time: 2599.728 msecs"返回双数组的diff:
(time (def y (diff x)))
"Elapsed time: 1638.548 msecs"difft:
(time (def y (difft x)))
"Elapsed time: 3683.237 msecs"函数
(use 'incanter.stats)
(def x (vec (sample-normal 1e7)))
(defn diff [x]
(let [y (double-array (dec (count x)))
x (double-array x)]
(dotimes [i (dec (count x))]
(aset y i
(- (aget x (inc i))
(aget x i))))
(vec y)))
(defn difft [x]
(let [y (vector (range n))
y (transient y)
x (double-array x)]
(dotimes [i (dec (count x))]
(assoc! y i
(- (aget x (inc i))
(aget x i))))
(persistent! y))) 发布于 2010-09-28 19:38:52
布拉德福德·克罗斯的博客有很多关于这方面的文章(他在链接文本上的初创公司使用这些东西)。一般来说,在内部循环中使用瞬变,类型提示(通过*warn-on-reflection*)等都有利于速度的提高。“Clojure的Joy”有一个关于性能调优的很好的章节,您应该读一下。
https://stackoverflow.com/questions/3814048
复制相似问题