001  (ns org.clojars.punit-naik.clj-ml.linear-regression
002    (:require [org.clojars.punit-naik.clj-ml.utils.matrix :as matrix]))
003  
004  (defn generate-input-matrix
005    "Receives a data matrix like [[x-1a x-1b x-1c...x-1z y-1]... [x-na x-nb x-nc...x-nz y-n]] with features and outputs
006     And generates an input matrix like [[1 x-1a x-1b x-1c...x-1z]... [1 x-na x-nb x-nc...x-nz]]"
007    [data]
008    (map (comp (partial cons 1) drop-last) data))
009  
010  (defn generate-output-matrix
011    "Receives a data matrix like [[x-1a x-1b x-1c...x-1z y-1]... [x-na x-nb x-nc...x-nz y-n]] with features and outputs
012     And generates an output matrix like [[y-1]... [y-n]]"
013    [data]
014    (map (comp list last) data))
015  
016  (defmulti betas
017    "Receives a dispath value `method` and data matrix like [[x-1a x-1b x-1c...x-1z y-1]... [x-na x-nb x-nc...x-nz y-n]] with features and outputs
018     And generates betas list like [b-0 b-a..b-z] using linear regression which can be used to predict output for any input [x-a...x-z]
019     Like Y = b-0 * 1 + b-a * x-a + .... + b-z * x-z"
020    (fn [method _]
021      method))
022  
023  (defmethod betas :matrix
024    [_ data]
025    (let [input-matrix (generate-input-matrix data)
026          input-matrix-transposed (matrix/transpose input-matrix)
027          output-matrix (generate-output-matrix data)
028          input-matrix-transposed-multiplied-by-input-matrix (matrix/matrix-multiply input-matrix-transposed input-matrix)
029          input-matrix-transposed-multiplied-by-output-matrix (matrix/matrix-multiply input-matrix-transposed output-matrix)
030          input-matrix-transposed-multiplied-by-input-matrix-inverse (matrix/inverse input-matrix-transposed-multiplied-by-input-matrix)]
031      (map first (matrix/matrix-multiply input-matrix-transposed-multiplied-by-input-matrix-inverse input-matrix-transposed-multiplied-by-output-matrix))))
032  
033  (defn predict
034    "Predicts output value for a set of features [x-a...x-z]
035     Given the beta values [b-0 b-a...b-z] for the training data"
036    [betas inputs]
037    (->> (cons 1 inputs)
038         (map * betas)
039         (reduce +)))