Ali
Ali

Reputation: 19692

In clojure, what is an efficient way to calculate average of integer vectors

I have:

(def data [[1 3 4 7 9] [7 6 3 2 7] [1 9 8 6 2]])

I want to average these (element-wise to get):

[3 6 5 5 6]

Like you would in MATLAB:

mean([1 3 4 7 9; 7 6 3 2 7; 1 9 8 6 2])

With Incanter I can do:

(map #(/ % (count m)) (apply plus data))

If data is rather large (and I have lots of them) is there a better way to do this?
Does it help to calculate the (count m) beforehand?
Does it help to defn the #(/ % (count m)) beforehand?

Upvotes: 9

Views: 9271

Answers (3)

mikera
mikera

Reputation: 106351

As of 2013, my recommendation would be to just use core.matrix.stats to import all of this functionality:

(mean [[1 3 4 7 9] [7 6 3 2 7] [1 9 8 6 2]])
=> [3.0 6.0 5.0 5.0 6.0]

core.matrix.stats builds on the core.matrix API, so it will also work on other more optimised implementations of vectors and matrices - this is likely to be a better option if you are doing a lot of heavy matrix processing.

Upvotes: 8

mikera
mikera

Reputation: 106351

Here's a pretty clean and simple way to do it:

(def data [[1 3 4 7 9] [7 6 3 2 7] [1 9 8 6 2]])

(defn average [coll] 
  (/ (reduce + coll) (count coll)))

(defn transpose [coll]
   (apply map vector coll))

(map average (transpose data))
=> (3 6 5 5 6)

Upvotes: 8

amalloy
amalloy

Reputation: 91917

Without knowing how to use any of incanter, here's how you could do this "from scratch".

(let [data [[1 3 4 7 9] [7 6 3 2 7] [1 9 8 6 2]]
      num (count data)]
  (apply map (fn [& items]
               (/ (apply + items) num))
         data))

;=> (3 6 5 5 6)

Upvotes: 5

Related Questions