2016-08-03 10 views
0

Ich möchte das gewichtete Mittel der Vektoren idiomatisch berechnen. Um zu zeigen, was ich will, stelle ich mir diese Daten haben:Clojure: idiomatisch gewichtetes Mittel der Vektoren

Daten 1 = [2 1], Gewicht 1 = 1 Daten 2 = [3 4], Gewicht 2 = 2

Dann mean = [ (2 * 1 + 3 * 2)/(1 + 2) (1 * 1 + 2 * 4)/(1 + 2)] = [2.67 3.0]

Hier ist mein Code:

(defn meanv 
    "Returns the vector that is the mean of input ones. 
    You can also pass weights just like apache-maths.stats/mean" 
    ([data] 
    (let [n (count (first data))] 
    (->> (for [i (range 0 n)] 
      (vec (map (i-partial nth i) data))) 
      (mapv stats/mean)))) 
    ([data weights] 
    (let [n (count (first data))] 
    (->> (for [i (range 0 n)] 
      (vec (map (i-partial nth i) data))) 
      (mapv (i-partial stats/mean weights)))))) 

Dann

(meanv [[2 1] [3 4]] [1 2]) = [2.67 3.0] 

Anmerkungen:

stats/means benötigt 1 oder 2 Eingänge.
Eine Eingabeversion hat standardmäßig Gewichte = 1.
Zwei Eingänge ist die gewichtete Version.

i-partial wie teilweise ist aber die fn hat args umgekehrt

Ex : ((partial/2) 1) = 2 
    ((i-partial/2) 1 = 1/2 

So funktioniert meine Funktion, kein Problem. Aber in gewisser Weise möchte ich es in einer idiomatischen Clojure implementieren.

Ich habe viele Kombinationen mit Dingen wie (map (fn [&xs ... versucht, aber es funktioniert nicht. Ist es möglich, alle n-ten Elemente einer nicht definierten Anzahl von Vektoren zu verwenden und direkt stats/mean anzuwenden? Ich meine, ein Einzeiler

Dank

EDIT (birdspider Antwort)

(defn meanv 
    ([data] 
    (->> (apply mapv vector data) 
     (mapv stats/mean))) 
    ([data weights] 
    (->> (apply mapv vector data) 
     (mapv (i-partial stats/mean weights))))) 

Und mit

(defn transpose [m] 
    (apply mapv vector m)) 

(defn meanv 
    ([data] 
    (->> (transpose data) 
     (mapv stats/mean))) 
    ([data weights] 
    (->> (transpose data) 
     (mapv (i-partial stats/mean weights))))) 
+0

Warum werden beide Daten durch '(1 + 2)' geteilt? – birdspider

+0

nvm, wird es durch Gewicht geteilt Summe – birdspider

+0

Ich bin verwirrt - in Ihrem Text descr Sie sagen, Daten ist '[[2 1] [3 4]]' Gewicht ist '[1 2]' - in Ihrer Probe verwenden Sie '[[1 2] [3 4]]' - also welches ist es? – birdspider

Antwort

0

Das erste, was Sie tun möchten, ist die Matrix transponieren (Holen Sie sich die ersten, Sekunden, Drittel, etc.)

Siehe this SO Seite.

; https://stackoverflow.com/a/10347404/2645347 
(defn transpose [m] 
    (apply mapv vector m)) 

Dann würde ich es tun, wie folgt, Eingangsprüfungen sind völlig abwesend.

(defn meanv 
    ([data] 
    ; no weigths default to (1 1 1 ... 
    (meanv data (repeat (count data) 1)))) 
    ([data weigths] 
    (let [wf (mapv #(partial * %) weigths) ; vector of weight mult fns 
     wsum (reduce + weigths)] 
    (map-indexed 
     (fn [i datum] 
     (/ 
     ; map over datum apply corresponding weight-fn - then sum 
     (apply + (map-indexed #((wf %1) %2) datum)) 
     wsum)) 
     (transpose data))))) 

(meanv [[2 1] [3 4]] [1 2]) => (8/3 3) ; (2.6666 3.0) 

Gewinn!

+0

Danke für die Antwort, ich sehe, wo ist Ihre Logik schwierig, es ist schwer, Ihren Beitrag zu bewerten, da es die mittlere Berechnung Job macht. Ich werde versuchen, es mit meinem Mean-Fn zu verschmelzen und sehen, ob es besser ist! –

+0

Ok ich habe es versucht, offensichtlich besser!Bearbeitet meinen Beitrag mit der Zusammenführung –

1
(def mult-v (partial mapv *)) 
(def sum-v (partial reduce +)) 
(def transpose (partial apply mapv vector)) 

(defn meanv [data weights] 
    (->> data 
     transpose 
     (map (partial mult-v weights)) 
     (map sum-v) 
     (map #(/ % (sum-v weights))))) 
+0

'(Karte (comp f1 f2 f3))' da wir golfen :) – birdspider

+0

Ich wollte nicht Golf spielen. Habe gerade meine Version vorgeschlagen, um das zu lösen. – OlegTheCat

+0

Danke auch! Ich habe nur meinen eigenen fn für meinen, der ein Apache-Mathe-Wrapper ist –