Clojure での高速ベクトル計算 / Incanter 質問する

Clojure での高速ベクトル計算 / Incanter 質問する

現在、R の代替として Clojure と Incanter を検討しています。(R が嫌いなわけではありませんが、新しい言語を試してみるのは興味深いです。) Incanter は気に入っており、構文も魅力的ですが、ベクトル化された操作は、R や Python などと比較するとかなり遅くなります。

例として、Incanter ベクトル演算、Clojure マップ、および R を使用してベクトルの 1 次差分を取得したいとします。以下は、すべてのバージョンのコードとタイミングです。ご覧のとおり、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 でベクトル演算を高速化する方法があるかどうか知りたいです。また、ループ、Java 配列、Clojure のライブラリを使用するソリューションも歓迎します。

この質問を Incanter Google グループにも投稿しましたが、今のところ返答はありません。

アップデート:私は Jouni の回答を承認済みとしてマークしました。彼のコードを少し整理し、ベンチマークをいくつか追加した私自身の回答については以下を参照してください。

ベストアンサー1

私の最終的な解決策

すべてのテストを終えた後、十分な速度で計算を実行するわずかに異なる 2 つの方法を見つけました。

まず、異なるタイプの戻り値を持つ関数を使用しましたdiff。以下はベクトルを返すコードですが、double 配列 (replace (vec y) with y) と Incanter.matrix (replace (vec y) with matrix y) を返すバージョンも計測しました。この関数は、Java 配列のみに基づいています。これは、いくつかの余分な型ヒントを削除した Jouni のコードに基づいています。

もう 1 つのアプローチは、Java 配列を使用して計算を行い、値を一時ベクトルに格納することです。タイミングからわかるように、関数が配列を返すようにしたい場合は、この方法の方がアプローチ 1 よりもわずかに高速です。これは関数で実装されていますdifft

したがって、選択は、データで何をしたいかによって決まります。良い選択肢は、関数をオーバーロードして、呼び出しで使用されたのと同じ型を返すようにすることだと思います。実際には、ベクトルではなく Java 配列を diff に渡すと、約 1 秒速くなります。

さまざまな機能のタイミング:

diff はベクトルを返します:

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

Incanter.matrix を返す diff:

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

diff は double 配列を返します:

(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))) 

おすすめ記事