forked from pa-m/sklearn
/
pipeline.go
98 lines (80 loc) · 2.26 KB
/
pipeline.go
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package pipeline
import (
"fmt"
"strings"
"github.com/gcla/sklearn/base"
"github.com/gcla/sklearn/preprocessing"
"gonum.org/v1/gonum/mat"
)
// Estimator is an interface for Predict
type Estimator interface {
Predict(X, Y *mat.Dense)
}
// NamedStep represents a pipeline named Step
type NamedStep struct {
Name string
Step base.Transformer
}
// Pipeline is a sequance of transformers and an estimator
type Pipeline struct {
NamedSteps []NamedStep
NOutputs int
}
// NewPipeline returns a *Pipeline
func NewPipeline(steps ...NamedStep) *Pipeline {
p := &Pipeline{NamedSteps: steps}
return p
}
// Fit for Pipeline
func (p *Pipeline) Fit(X, Y *mat.Dense) base.Transformer {
_, p.NOutputs = Y.Dims()
Xtmp, Ytmp := X, Y
for _, step := range p.NamedSteps {
step.Step.Fit(Xtmp, Ytmp)
Xtmp, Ytmp = step.Step.Transform(Xtmp, Ytmp)
}
return p
}
// Predict ...
func (p *Pipeline) Predict(X, Y *mat.Dense) base.Regressor {
Xtmp, Ytmp := X, Y
for _, step := range p.NamedSteps {
Xtmp, Ytmp = step.Step.Transform(Xtmp, Ytmp)
}
for iStep := len(p.NamedSteps) - 2; iStep >= 0; iStep-- {
step := p.NamedSteps[iStep]
_, Ytmp = step.Step.(preprocessing.InverseTransformer).InverseTransform(nil, Ytmp)
}
Y.Copy(Ytmp)
return p
}
// Transform for pipeline
func (p *Pipeline) Transform(X, Y *mat.Dense) (Xout, Yout *mat.Dense) {
nSamples, _ := X.Dims()
Xout = X
Yout = mat.NewDense(nSamples, p.NOutputs, nil)
p.Predict(Xout, Yout)
return
}
// Score for base.Regressor
func (p *Pipeline) Score(X, Y *mat.Dense) float64 {
Xtmp, Ytmp := X, Y
for _, step := range p.NamedSteps[:len(p.NamedSteps)-1] {
Xtmp, Ytmp = step.Step.Transform(Xtmp, Ytmp)
}
return p.NamedSteps[len(p.NamedSteps)-1].Step.(base.Regressor).Score(Xtmp, Y)
}
// MakePipeline returns a Pipeline from unnamed steps
func MakePipeline(steps ...base.Transformer) *Pipeline {
p := &Pipeline{}
for _, step := range steps {
/*if _, ok := step.(preprocessing.Transformer); (istep < len(steps)-1) && !ok {
panic(fmt.Errorf("%T is not a Transformer", step))
}
if _, ok := step.(lm.Regressor); (istep == len(steps)-1) && !ok {
panic(fmt.Errorf("%T is not a lm.Regressor", step))
}*/
p.NamedSteps = append(p.NamedSteps, NamedStep{Name: strings.ToLower(fmt.Sprintf("%T", step)), Step: step})
}
return p
}