代码之家  ›  专栏  ›  技术社区  ›  Matti Pastell

Clojure/白炽灯中的快速矢量数学

  •  22
  • Matti Pastell  · 技术社区  · 15 年前

    我目前正在研究Clojure和白炽灯作为R的替代品(不是说我不喜欢R,而是尝试新语言很有趣)。我喜欢白炽灯,并且发现语法很吸引人,但是与R或python相比,矢量化操作非常慢。

    作为一个例子,我想得到一个向量的一阶差分。 使用白炽向量运算,clojure map和r。下面是所有人的代码和时间安排 版本。如你所见,R显然更快。

    白炽灯和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
    

    所以我想知道有没有一种方法可以加速白炽灯/Clojure中的矢量运算?此外,欢迎使用Culjure中的循环、Java数组和/或库的解决方案。

    我也把这个问题发到了炙手可热的谷歌集团,到目前为止还没有回复。

    更新: 我已经将Jouni的答案标记为接受,下面是我自己的答案,我已经清理了他的代码并添加了一些基准。

    6 回复  |  直到 15 年前
        1
  •  13
  •   Jouni K. Seppänen    15 年前

    (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))))))))
    
        2
  •  20
  •   dnolen    15 年前

    diff

    difft

    (time (def y (diff x)))
    "Elapsed time: 4733.259 msecs"
    

    (time (def y (diff x)))
    "Elapsed time: 2599.728 msecs"
    

    (time (def y (diff x)))
    "Elapsed time: 1638.548 msecs"
    

    (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))) 
    
        3
  •  3
  •   Michael Kohl    15 年前
        4
  •  2
  •   Tom Crayford    15 年前
        5
  •  1
  •   Jouni K. Seppänen    15 年前

    (use 'incanter.stats)
    (set! *warn-on-reflection* true)
    (def x (doall (sample-normal 1e7)))
    
    (time
     (def y
          (loop [xs x
                 xs+ (rest x)
                 result (transient [])]
            (if (empty? xs+)
              (persistent! result)
              (recur (rest xs) (rest xs+)
                     (conj! result (- (double (first xs+))
                                      (double (first xs)))))))))
    
    推荐文章