/
pls.js
81 lines (72 loc) · 1.53 KB
/
pls.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import Matrix from '../util/matrix.js'
/**
* Partial least squares regression
*/
export default class PLS {
/**
* @param {number} l Limit on the number of latent factors
*/
constructor(l) {
this._l = l
}
/**
* Initialize model.
*
* @param {Array<Array<number>>} x Training data
* @param {Array<Array<number>>} y Target values
*/
init(x, y) {
this._x = Matrix.fromArray(x)
this._y = Matrix.fromArray(y)
}
/**
* Fit model.
*/
fit() {
if (this._y.cols === 1) {
;[this._b, this._b0] = this._pls1()
} else {
throw ''
}
}
_pls1() {
// https://ja.wikipedia.org/wiki/部分的最小二乗回帰
let x = this._x.copy()
let w = x.tDot(this._y)
w.div(w.norm())
const ws = []
const ps = []
const qs = []
for (let k = 0; k < this._l; k++) {
const t = x.dot(w)
const tk = t.tDot(t).toScaler()
t.div(tk)
const p = x.tDot(t)
const qk = this._y.tDot(t).toScaler()
ps.push(p.value)
qs.push(qk)
ws.push(w.value)
if (qk === 0) break
const xsub = t.dot(p.t)
xsub.mult(tk)
x.sub(xsub)
w = x.tDot(this._y)
}
const W = Matrix.fromArray(ws).t
const P = Matrix.fromArray(ps).t
const q = new Matrix(qs.length, 1, qs)
const B = W.dot(P.tDot(W).solve(q))
const B0 = qs[0] - P.col(0).tDot(B).toScaler()
return [B, B0]
}
/**
* Returns predicted values.
*
* @param {Array<Array<number>>} x Sample data
* @returns {Array<Array<number>>} Predicted values
*/
predict(x) {
x = Matrix.fromArray(x)
return Matrix.add(x.dot(this._b), this._b0).toArray()
}
}