Skip to content

Commit dc65075

Browse files
committed
added Support and supportVectors in SVC members. +coverage improvement
1 parent 64c95c4 commit dc65075

File tree

7 files changed

+99
-26
lines changed

7 files changed

+99
-26
lines changed

cluster/distance_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package cluster
2+
3+
import (
4+
"gonum.org/v1/gonum/mat"
5+
"math"
6+
"testing"
7+
)
8+
9+
func TestMinkowskiDistanceP(t *testing.T) {
10+
a := mat.NewVecDense(2, []float64{0, 0})
11+
b := mat.NewVecDense(2, []float64{1, 2})
12+
if MinkowskiDistanceP(a, a, 2) != 0 {
13+
t.Fail()
14+
}
15+
if MinkowskiDistanceP(b, b, 2) != 0 {
16+
t.Fail()
17+
}
18+
if math.Abs(5-MinkowskiDistanceP(a, b, 2)) > 1e-9 {
19+
t.Fail()
20+
}
21+
actual := MinkowskiDistanceP(a, b, math.Inf(1))
22+
if math.Abs(2-actual) > 1e-9 {
23+
t.Errorf("got %g", actual)
24+
}
25+
}

metrics/regression_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ func ExampleR2Score() {
6060

6161
yTrue = mat.NewDense(3, 1, []float64{1, 2, 3})
6262
yPred = mat.NewDense(3, 1, []float64{3, 2, 1})
63-
fmt.Printf("%g\n", R2Score(yTrue, yPred, nil, "").At(0, 0))
63+
sampleWeight := mat.NewDense(3, 1, []float64{1, 1, 1})
64+
fmt.Printf("%g\n", R2Score(yTrue, yPred, sampleWeight, "").At(0, 0))
6465
// Output:
6566
// 0.949
6667
// 0.938

neighbors/kdtree.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ func NewRectangle(Maxes, Mins []float64) *Rectangle {
2323
func (r *Rectangle) String() string {
2424
s := "<Rectangle "
2525
for axis := 0; axis < len(r.Maxes); axis++ {
26+
if axis > 0 {
27+
s += ", "
28+
}
2629
s += fmt.Sprint(r.Mins[axis], r.Maxes[axis])
2730
}
2831
s += ">"

neighbors/kdtree_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,27 @@ import (
55
"math"
66

77
"gonum.org/v1/gonum/mat"
8+
"testing"
89
)
910

11+
func TestRectangle(t *testing.T) {
12+
R := NewRectangle([]float64{3, 4}, []float64{1, 2})
13+
expected := "<Rectangle 1 3, 2 4>"
14+
actual := R.String()
15+
if expected != actual {
16+
t.Errorf("expected %s, got %s", expected, actual)
17+
}
18+
if R.Volume() != 4. {
19+
t.Errorf("wrong volume")
20+
}
21+
if math.Abs(2.237-R.MinDistancePoint([]float64{0, 0}, 2)) > 1.e-3 {
22+
t.Error("err MinDistancePoint")
23+
}
24+
if math.Abs(5-R.MaxDistancePoint([]float64{0, 0}, 2)) > 1.e-3 {
25+
t.Error("err MaxDistancePoint")
26+
}
27+
}
28+
1029
func ExampleKDTree() {
1130
// v https://github.com/scipy/scipy/blob/v1.1.0/scipy/spatial/kdtree.py
1231
X := mat.NewDense(30, 2, nil)

neighbors/unsupervised_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,19 @@ func ExampleNearestNeighbors_Tree() {
8686
// [1 5 8]
8787
// [1 6 8]
8888
}
89+
90+
func ExampleNearestNeighbors_RadiusNeighbors() {
91+
// adapted example from http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.RadiusNeighborsRegressor.html#sklearn.neighbors.RadiusNeighborsRegressor
92+
samples := mat.NewDense(3, 3, []float64{0, 0, 0, 0, .5, 0, 1, 1, .5})
93+
neigh := NewNearestNeighbors()
94+
neigh.Fit(samples)
95+
distances, indices := neigh.RadiusNeighbors(mat.NewDense(1, 3, []float64{1, 1, 1}), 1.6)
96+
fmt.Println(distances[0])
97+
fmt.Println(indices[0])
98+
// unlike the python example, distances are sorted by increasing distances
99+
100+
// Output:
101+
// [0.5 1.5]
102+
// [2 1]
103+
104+
}

svm/svm.go

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Model struct {
2424
B float64
2525
Alphas []float64
2626
W []float64
27+
Support []int
2728
}
2829

2930
// %svmTrain Trains an SVM classifier using a simplified version of the SMO
@@ -160,12 +161,12 @@ func svmTrain(X *mat.Dense, Y []float64, C float64, KernelFunction func(X1, X2 [
160161
B: b,
161162
Alphas: make([]float64, len(idx)),
162163
W: make([]float64, n, n),
164+
Support: idx,
163165
}
164166
for ii, i := range idx {
165167
model.X.SetRow(ii, X.RawRowView(i))
166168
model.Y[ii] = Y[i]
167169
model.Alphas[ii] = alphas[i]
168-
169170
}
170171
for j := 0; j < n; j++ {
171172
for _, i := range idx {
@@ -196,7 +197,6 @@ func svmPredict(model *Model, X *mat.Dense) (pred []float64) {
196197
}
197198
}
198199
return
199-
200200
}
201201

202202
// Kernel is the interface for kernels
@@ -252,18 +252,20 @@ func (kdata SigmoidKernel) Func(a, b []float64) (sumprod float64) {
252252

253253
// SVC struct
254254
type SVC struct {
255-
C float64
256-
Kernel interface{}
257-
Degree float64
258-
Gamma float64
259-
Coef0 float64
260-
Shrinking bool
261-
Probability bool
262-
Tol float64
263-
CacheSize uint
264-
ClassWeight []float64
265-
MaxIter int
266-
Model []*Model
255+
C float64
256+
Kernel interface{}
257+
Degree float64
258+
Gamma float64
259+
Coef0 float64
260+
Shrinking bool
261+
Probability bool
262+
Tol float64
263+
CacheSize uint
264+
ClassWeight []float64
265+
MaxIter int
266+
Model []*Model
267+
Support [][]int
268+
SupportVectors [][][]float64
267269
}
268270

269271
// NewSVC ...
@@ -310,12 +312,19 @@ func (m *SVC) Fit(X, Y *mat.Dense) base.Transformer {
310312
if m.MaxIter <= 0 {
311313
m.MaxIter = math.MaxInt32
312314
}
315+
m.Support = make([][]int, Noutputs)
316+
m.SupportVectors = make([][][]float64, Noutputs)
313317
base.Parallelize(-1, Noutputs, func(th, start, end int) {
314318
y := make([]float64, NSamples)
315319
for output := start; output < end; output++ {
316320
mat.Col(y, output, Y)
317321
m.Model[output] = svmTrain(X, y, m.C, K, m.Tol, m.MaxIter, m.CacheSize)
318-
322+
model := m.Model[output]
323+
m.Support[output] = model.Support
324+
m.SupportVectors[output] = make([][]float64, len(model.Support))
325+
for i := range model.Support {
326+
m.SupportVectors[output][i] = model.X.RawRowView(i)
327+
}
319328
}
320329
})
321330
return m

svm/svm_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,26 @@ func ExampleSVC() {
3232
X1 := X
3333
Y1, _ := yscaler.FitTransform(Y, nil)
3434
plots := [][]*plot.Plot{make([]*plot.Plot, 0, 4)}
35+
var clf *SVC
3536
for _, kernel := range []string{
3637
"linear",
3738
"poly",
3839
"rbf",
3940
} {
40-
m := NewSVC()
41-
m.Kernel = kernel
42-
m.C = 1.
43-
m.Gamma = 2.
44-
m.Tol = 1.e-3
45-
m.MaxIter = 20
46-
m.Fit(X1, Y1)
41+
clf = NewSVC()
42+
clf.Kernel = kernel
43+
//clf.C = 1.
44+
clf.Gamma = 2.
45+
//clf.Tol = 1.e-3
46+
clf.MaxIter = 20
47+
clf.Fit(X1, Y1)
4748
Ypred := mat.NewDense(16, 1, nil)
48-
m.Predict(X, Ypred)
49+
clf.Predict(X, Ypred)
4950
fmt.Printf("%s kernel, accuracy:%.3f\n", kernel, metrics.AccuracyScore(Y, Ypred, true, nil))
5051
// Put the result into a color plot
5152
if *visualDebug {
5253
// Plot the decision boundary. For that, we will assign a color to each point in the mesh [x_min, x_max]x[y_min, y_max].
5354
var xmin, xmax = -3., 3.
54-
5555
var ymin, ymax = -3., 3.
5656
h := (ymax - ymin) / 100
5757

@@ -82,7 +82,7 @@ func ExampleSVC() {
8282
var xx, yy = npmeshgrid(nparange(xmin, xmax, h), nparange(ymin, ymax, h))
8383
Xgrid := npc(xx, yy)
8484
Z := &mat.Dense{}
85-
m.Predict(Xgrid, Z)
85+
clf.Predict(Xgrid, Z)
8686
plt, _ := plot.New()
8787
xys := func(X, Y mat.Matrix, cls int) (xy plotter.XYs) {
8888
imax, _ := Y.Dims()

0 commit comments

Comments
 (0)