score functions
This commit is contained in:
parent
59ba9d0c72
commit
d8264d72cf
48
notebooks/regressions.ipynb
vendored
48
notebooks/regressions.ipynb
vendored
File diff suppressed because one or more lines are too long
BIN
regr/mod.wasm
BIN
regr/mod.wasm
Binary file not shown.
|
@ -93,4 +93,9 @@ func setjsmethods(obj js.Value, regr *ElasticNet) {
|
||||||
Y, _ := regr.Predict(X)
|
Y, _ := regr.Predict(X)
|
||||||
return ToJSArray(Y)
|
return ToJSArray(Y)
|
||||||
}))
|
}))
|
||||||
|
obj.Set("score", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
X := JSFloatArray2D(args[0])
|
||||||
|
Y := JSFloatArray2D(args[1])
|
||||||
|
return regr.Score(X, Y)
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,6 @@ import (
|
||||||
"gonum.org/v1/gonum/mat"
|
"gonum.org/v1/gonum/mat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ref: mat.Dense
|
|
||||||
// fit: solve least squares
|
|
||||||
// predict: predict y from x
|
|
||||||
// save: save model
|
|
||||||
// load: load model
|
|
||||||
// note: separate wasm/js glue
|
|
||||||
|
|
||||||
type LinearRegression struct {
|
type LinearRegression struct {
|
||||||
Coef *mat.Dense
|
Coef *mat.Dense
|
||||||
}
|
}
|
||||||
|
@ -34,6 +27,12 @@ func (reg *LinearRegression) Predict(X [][]float64) ([]float64, error) {
|
||||||
return YDense.RawMatrix().Data, nil
|
return YDense.RawMatrix().Data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (reg *LinearRegression) Score(YT, Y [][]float64) float64 {
|
||||||
|
TDense := Array2DToDense(YT)
|
||||||
|
YDense := Array2DToDense(Y)
|
||||||
|
return R2Score(TDense, YDense, nil, "raw_values").At(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
func (l *LinearRegression) Save() ([]byte, error) {
|
func (l *LinearRegression) Save() ([]byte, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -55,5 +54,10 @@ func NewLinearRegressionJS(this js.Value, args []js.Value) interface{} {
|
||||||
Y, _ := reg.Predict(X)
|
Y, _ := reg.Predict(X)
|
||||||
return ToJSArray(Y)
|
return ToJSArray(Y)
|
||||||
}))
|
}))
|
||||||
|
obj.Set("score", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
X := JSFloatArray2D(args[0])
|
||||||
|
Y := JSFloatArray2D(args[1])
|
||||||
|
return reg.Score(X, Y)
|
||||||
|
}))
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
87
regr/src/score.go
Normal file
87
regr/src/score.go
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
package src
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"gonum.org/v1/gonum/mat"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MatConst struct {
|
||||||
|
Rows, Columns int
|
||||||
|
Value float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MatConst) Dims() (int, int) { return m.Rows, m.Columns }
|
||||||
|
|
||||||
|
func (m MatConst) At(i, j int) float64 { return m.Value }
|
||||||
|
|
||||||
|
func (m MatConst) T() mat.Matrix { return MatConst{Rows: m.Columns, Columns: m.Rows, Value: m.Value} }
|
||||||
|
|
||||||
|
func R2Score(yTrue, yPred mat.Matrix, sampleWeight *mat.Dense, multioutput string) *mat.Dense {
|
||||||
|
nSamples, nOutputs := yTrue.Dims()
|
||||||
|
if sampleWeight == nil {
|
||||||
|
sampleWeight = mat.DenseCopyOf(MatConst{Rows: nSamples, Columns: 1, Value: 1.})
|
||||||
|
}
|
||||||
|
numerator := mat.NewDense(1, nOutputs, nil)
|
||||||
|
diff := mat.NewDense(nSamples, nOutputs, nil)
|
||||||
|
diff.Sub(yPred, yTrue)
|
||||||
|
diff2 := mat.NewDense(nSamples, nOutputs, nil)
|
||||||
|
diff2.MulElem(diff, diff)
|
||||||
|
numerator.Mul(sampleWeight.T(), diff2)
|
||||||
|
|
||||||
|
sampleWeightSum := mat.Sum(sampleWeight)
|
||||||
|
|
||||||
|
yTrueAvg := mat.NewDense(1, nOutputs, nil)
|
||||||
|
yTrueAvg.Mul(sampleWeight.T(), yTrue)
|
||||||
|
yTrueAvg.Scale(1./sampleWeightSum, yTrueAvg)
|
||||||
|
|
||||||
|
diff2.Apply(func(i int, j int, _ float64) float64 {
|
||||||
|
v := yTrue.At(i, j) - yTrueAvg.At(0, j)
|
||||||
|
return v * v
|
||||||
|
}, diff2)
|
||||||
|
denominator := mat.NewDense(1, nOutputs, nil)
|
||||||
|
denominator.Mul(sampleWeight.T(), diff2)
|
||||||
|
|
||||||
|
r2score := mat.NewDense(1, nOutputs, nil)
|
||||||
|
r2score.Apply(func(i int, j int, v float64) float64 {
|
||||||
|
d := math.Max(denominator.At(i, j), 1e-20)
|
||||||
|
return 1. - numerator.At(i, j)/d
|
||||||
|
}, r2score)
|
||||||
|
switch multioutput {
|
||||||
|
case "raw_values":
|
||||||
|
return r2score
|
||||||
|
case "variance_weighted":
|
||||||
|
r2 := mat.NewDense(1, 1, nil)
|
||||||
|
r2.Mul(denominator, r2score.T())
|
||||||
|
sumden := mat.Sum(denominator)
|
||||||
|
r2.Scale(1./sumden, r2)
|
||||||
|
return r2
|
||||||
|
default: // "uniform_average":
|
||||||
|
return mat.NewDense(1, 1, []float64{mat.Sum(r2score) / float64(nOutputs)})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func MeanSquaredError(yTrue, yPred mat.Matrix, sampleWeight *mat.Dense, multioutput string) *mat.Dense {
|
||||||
|
nSamples, nOutputs := yTrue.Dims()
|
||||||
|
tmp := mat.NewDense(1, nOutputs, nil)
|
||||||
|
tmp.Apply(func(_ int, j int, v float64) float64 {
|
||||||
|
N, D := 0., 0.
|
||||||
|
for i := 0; i < nSamples; i++ {
|
||||||
|
ydiff := yPred.At(i, j) - yTrue.At(i, j)
|
||||||
|
w := 1.
|
||||||
|
if sampleWeight != nil {
|
||||||
|
w = sampleWeight.At(0, j)
|
||||||
|
}
|
||||||
|
N += w * (ydiff * ydiff)
|
||||||
|
D += w
|
||||||
|
}
|
||||||
|
return N / D
|
||||||
|
}, tmp)
|
||||||
|
switch multioutput {
|
||||||
|
case "raw_values":
|
||||||
|
return tmp
|
||||||
|
default: // "uniform_average":
|
||||||
|
return mat.NewDense(1, 1, []float64{mat.Sum(tmp) / float64(nOutputs)})
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,14 @@ func Array2DToDense(X [][]float64) *mat.Dense {
|
||||||
return dense
|
return dense
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JSFloatArray(arg js.Value) []float64 {
|
||||||
|
arr := make([]float64, arg.Length())
|
||||||
|
for i := 0; i < len(arr); i++ {
|
||||||
|
arr[i] = arg.Index(i).Float()
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
func JSFloatArray2D(arg js.Value) [][]float64 {
|
func JSFloatArray2D(arg js.Value) [][]float64 {
|
||||||
arr := make([][]float64, arg.Length())
|
arr := make([][]float64, arg.Length())
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
|
|
Loading…
Reference in a new issue