Skip to content

Instantly share code, notes, and snippets.

@mthomure
Last active August 3, 2020 06:31
Show Gist options
  • Save mthomure/19377b4821041e693fff9361bea590db to your computer and use it in GitHub Desktop.
Save mthomure/19377b4821041e693fff9361bea590db to your computer and use it in GitHub Desktop.
simple PCA implementation in clojure
(ns pca
(:require [clojure.core.matrix :as m]
[clojure.core.matrix.linear :as ml]
[clojure.core.matrix.utils :as mu]
[clojure.core.matrix.stats :as ms]))
;; dependency: [net.mikera/core.matrix "0.57.0"]
(defn fit! [m & {:keys [num-components transform?]}]
(let [mean (ms/mean m) ;; per-column mean
{:keys [U S V*]} (ml/svd (m/sub! m mean))
[U S V*] (if (and num-components (not= num-components (m/column-count m)))
[(m/submatrix U 1 [0 num-components])
(m/subvector S 0 num-components)
(m/submatrix V* 1 [0 num-components])]
[U S V*])
n (m/row-count m)]
(merge {:m (m/ecount S)
:explained-variance (m/emap #(/ (* % %) n) S)
:components V*
:mean mean}
(when transform?
(let [impl U ;; defines matrix implementation
S (m/diagonal-matrix impl S)]
{:transform (m/mmul U S)})))))
(defn transform! [model m]
(let [{:keys [components mean]} model]
(m/mmul (m/sub! m mean) components)))
(defn- apply-kv [f & args]
(apply f (concat (butlast args) (apply concat (last args)))))
(defn fit
"Choose principal axes from matrix m."
[m & {:keys [num-components transform?] :as args}]
(apply-kv fit! (m/clone m) args))
(defn transform
"Project rows of matrix m onto principal axes of model."
[model m]
(transform! model (mu/copy-double-array m)))
(require '[pca :refer :all])
(require '[clojure.core.matrix :as m])
(require 'apache-commons-matrix.core)
;; dependency: [apache-commons-matrix "0.3.1"]
(pca/fit (m/matrix :apache-commons
[[-1 -1]
[-2 -1]
[-3 -2]
[1 1]
[2 1]
[3 2]]))
;; {:m 2,
;; :explained-variance [6.616285933932034, 0.05038073273463172],
;; :components
;; [[0.8384922379048739 0.5449135408239331]
;; [0.5449135408239331 -0.8384922379048739]],
;; :mean [0.0 0.0]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment