poly regression works.

This commit is contained in:
Will Charczuk 2017-04-18 20:16:51 -07:00
parent 8445577ef4
commit 59ccf693bf
3 changed files with 135 additions and 12 deletions

View file

@ -0,0 +1,41 @@
package main
import (
"net/http"
"github.com/wcharczuk/go-chart"
)
func drawChart(res http.ResponseWriter, req *http.Request) {
/*
In this example we add a new type of series, a `PolynomialRegressionSeries` that takes another series as a required argument.
InnerSeries only needs to implement `ValueProvider`, so really you could chain `PolynomialRegressionSeries` together if you wanted.
*/
mainSeries := chart.ContinuousSeries{
Name: "A test series",
XValues: chart.Sequence.Float64(1.0, 100.0), //generates a []float64 from 1.0 to 100.0 in 1.0 step increments, or 100 elements.
YValues: chart.Sequence.Random(100, 100), //generates a []float64 randomly from 0 to 100 with 100 elements.
}
polyRegSeries := &chart.PolynomialRegressionSeries{
Degree: 3,
InnerSeries: mainSeries,
}
graph := chart.Chart{
Series: []chart.Series{
mainSeries,
polyRegSeries,
},
}
res.Header().Set("Content-Type", "image/png")
graph.Render(chart.PNG, res)
}
func main() {
http.HandleFunc("/", drawChart)
http.ListenAndServe(":8080", nil)
}

View file

@ -204,6 +204,22 @@ func TestMatrixRow(t *testing.T) {
assert.Equal([]float64{7, 8, 9}, m.Row(2))
}
func TestMatrixSwapRows(t *testing.T) {
assert := assert.New(t)
m := NewFromArrays([][]float64{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
})
m.SwapRows(0,1)
assert.Equal([]float64{4,5,6}, m.Row(0))
assert.Equal([]float64{1,2,3}, m.Row(1))
assert.Equal([]float64{7,8,9}, m.Row(2))
}
func TestMatrixCopy(t *testing.T) {
assert := assert.New(t)
@ -357,3 +373,24 @@ func TestMatrixQR(t *testing.T) {
assert.NotNil(q)
assert.NotNil(r)
}
func TestMatrixTranspose(t *testing.T) {
assert := assert.New(t)
m := NewFromArrays([][]float64{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12},
})
m2 := m.Transpose()
rows, cols := m2.Size()
assert.Equal(3, rows)
assert.Equal(4, cols)
assert.Equal(1, m2.Get(0,0))
assert.Equal(10, m2.Get(0,3))
assert.Equal(3, m2.Get(2,0))
)

View file

@ -1,6 +1,11 @@
package chart
import "fmt"
import (
"fmt"
"math"
"github.com/wcharczuk/go-chart/matrix"
)
// PolynomialRegressionSeries implements a polynomial regression over a given
// inner series.
@ -11,7 +16,7 @@ type PolynomialRegressionSeries struct {
Limit int
Offset int
Order int
Degree int
InnerSeries ValueProvider
coeffs []float64
@ -65,6 +70,12 @@ func (prs *PolynomialRegressionSeries) Validate() error {
if prs.InnerSeries == nil {
return fmt.Errorf("linear regression series requires InnerSeries to be set")
}
endIndex := prs.GetEndIndex()
if endIndex >= prs.InnerSeries.Len() {
return fmt.Errorf("invalid window; inner series has length %d but end index is %d", prs.InnerSeries.Len(), endIndex)
}
return nil
}
@ -73,18 +84,52 @@ func (prs *PolynomialRegressionSeries) GetValue(index int) (x, y float64) {
if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 {
return
}
if prs.coeffs == nil {
coeffs, err := prs.computeCoefficients()
if err != nil {
panic(err)
}
prs.coeffs = coeffs
}
offset := prs.GetOffset()
effectiveIndex := Math.MinInt(index+offset, prs.InnerSeries.Len())
x, y = prs.InnerSeries.GetValue(effectiveIndex)
y = prs.apply(x)
return
}
func (prs *PolynomialRegressionSeries) computeCoefficients() {
vandMatrix := make([][]float64, prs.Len(), prs.Order+1)
var xvalue float64
for i := 0; i < prs.Len(); i++ {
_, xvalue = prs.InnerSeries.GetValue(i)
var mult float64 = 1.0
for j := 0; j < prs.Order+1; j++ {
vandMatrix[i][j] = mult
mult = mult * xvalue
}
func (prs *PolynomialRegressionSeries) apply(v float64) (out float64) {
for index, coeff := range prs.coeffs {
out = out + (coeff * math.Pow(v, float64(index)))
}
return
}
func (prs *PolynomialRegressionSeries) computeCoefficients() ([]float64, error) {
xvalues, yvalues := prs.values()
return matrix.Poly(xvalues, yvalues, prs.Degree)
}
func (prs *PolynomialRegressionSeries) values() (xvalues, yvalues []float64) {
startIndex := prs.GetOffset()
endIndex := prs.GetEndIndex()
xvalues = make([]float64, endIndex-startIndex)
yvalues = make([]float64, endIndex-startIndex)
for index := startIndex; index < endIndex; index++ {
x, y := prs.InnerSeries.GetValue(index)
xvalues[index] = x
yvalues[index] = y
}
return
}
// Render renders the series.
func (prs *PolynomialRegressionSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
style := prs.Style.InheritFrom(defaults)
Draw.LineSeries(r, canvasBox, xrange, yrange, style, prs)
}