stat: optimize LinearRegression code, providing speedups of 40%
* stat: optimize LinearRegression code, providing speedups of 40%
Benchmarks
BenchmarkLinearRegression/n10000wfof-8 70687 42916 -39.29%
BenchmarkLinearRegression/n10000wfof-8 66305 40844 -38.40%
BenchmarkLinearRegression/n10000wfof-8 66262 40922 -38.24%
BenchmarkLinearRegression/n10000wfof-8 65864 42854 -34.94%
BenchmarkLinearRegression/n10000wfof-8 65366 40753 -37.65%
MODIFY
stat/stat.go
stat/stat.go
@@ -284,6 +284,13 @@ func Covariance(x, y, weights []float64) float64 {
}
xu := Mean(x, weights)
yu := Mean(y, weights)
+ return covarianceMeans(x, y, weights, xu, yu)
+}
+
+// covarianceMeans returns the weighted covariance between x and y with the mean
+// of x and y already specified. See the documentation of Covariance for more
+// information.
+func covarianceMeans(x, y, weights []float64, xu, yu float64) float64 {
var (
ss float64
xcompensation float64
@@ -761,8 +768,11 @@ func LinearRegression(x, y, weights []float64, origin bool) (alpha, beta float64
return 0, beta
}
- beta = Covariance(x, y, weights) / Variance(x, weights)
- alpha = Mean(y, weights) - beta*Mean(x, weights)
+ xu, xv := MeanVariance(x, weights)
+ yu := Mean(y, weights)
+ cov := covarianceMeans(x, y, weights, xu, yu)
+ beta = cov / xv
+ alpha = yu - beta*xu
return alpha, beta
}

MODIFY
stat/stat_test.go
stat/stat_test.go
@@ -8,8 +8,11 @@ import (
"fmt"
"math"
"reflect"
+ "strconv"
"testing"
+ "golang.org/x/exp/rand"
+
"gonum.org/v1/gonum/floats"
)
@@ -990,6 +993,49 @@ func TestLinearRegression(t *testing.T) {
}
}
+func BenchmarkLinearRegression(b *testing.B) {
+ rnd := rand.New(rand.NewSource(1))
+ slope, offset := 2.0, 3.0
+
+ maxn := 10000
+ xs := make([]float64, maxn)
+ ys := make([]float64, maxn)
+ weights := make([]float64, maxn)
+ for i := range xs {
+ x := rnd.Float64()
+ xs[i] = x
+ ys[i] = slope*x + offset
+ weights[i] = rnd.Float64()
+ }
+
+ for _, n := range []int{10, 100, 1000, maxn} {
+ for _, weighted := range []bool{true, false} {
+ for _, origin := range []bool{true, false} {
+ name := "n" + strconv.Itoa(n)
+ if weighted {
+ name += "wt"
+ } else {
+ name += "wf"
+ }
+ if origin {
+ name += "ot"
+ } else {
+ name += "of"
+ }
+ b.Run(name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var ws []float64
+ if weighted {
+ ws = weights[:n]
+ }
+ LinearRegression(xs[:n], ys[:n], ws, origin)
+ }
+ })
+ }
+ }
+ }
+}
+
func TestChiSquare(t *testing.T) {
for i, test := range []struct {
p []float64

stat: optimize LinearRegression code, providing speedups of 40% (#563)

* stat: optimize LinearRegression code, providing speedups of 40%

Benchmarks
BenchmarkLinearRegression/n10000wfof-8 70687 42916 -39.29%
BenchmarkLinearRegression/n10000wfof-8 66305 40844 -38.40%
BenchmarkLinearRegression/n10000wfof-8 66262 40922 -38.24%
BenchmarkLinearRegression/n10000wfof-8 65864 42854 -34.94%
BenchmarkLinearRegression/n10000wfof-8 65366 40753 -37.65%