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)
|
||||
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"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
Coef *mat.Dense
|
||||
}
|
||||
|
@ -34,6 +27,12 @@ func (reg *LinearRegression) Predict(X [][]float64) ([]float64, error) {
|
|||
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) {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -55,5 +54,10 @@ func NewLinearRegressionJS(this js.Value, args []js.Value) interface{} {
|
|||
Y, _ := reg.Predict(X)
|
||||
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
|
||||
}
|
||||
|
|
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
|
||||
}
|
||||
|
||||
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 {
|
||||
arr := make([][]float64, arg.Length())
|
||||
for i := 0; i < len(arr); i++ {
|
||||
|
|
Loading…
Reference in a new issue