1
0
mirror of https://github.com/sjwhitworth/golearn.git synced 2025-05-01 22:18:10 +08:00
golearn/knn.go

129 lines
2.7 KiB
Go
Raw Normal View History

2013-12-26 13:05:16 +00:00
package main
import (
mat "github.com/skelterjohn/go.matrix"
2013-12-27 00:59:06 +00:00
rand "math/rand"
2013-12-28 10:00:20 +00:00
"math"
2013-12-26 13:05:16 +00:00
"fmt"
2013-12-28 10:00:20 +00:00
"sort"
2013-12-28 18:41:13 +00:00
"/base/"
2013-12-28 10:00:20 +00:00
// "errors"
2013-12-26 13:05:16 +00:00
)
2013-12-28 10:00:20 +00:00
//Sorts a map by value size in .s property
type sortedMap struct {
m map[int]float64
s []int
}
func (sm *sortedMap) Len() int {
return len(sm.m)
}
func (sm *sortedMap) Less(i, j int) bool {
2013-12-28 18:41:13 +00:00
return sm.m[sm.s[i]] < sm.m[sm.s[j]]
2013-12-28 10:00:20 +00:00
}
func (sm *sortedMap) Swap(i, j int) {
sm.s[i], sm.s[j] = sm.s[j], sm.s[i]
}
func sortMap(m map[int]float64) []int {
sm := new(sortedMap)
sm.m = m
sm.s = make([]int, len(m))
i := 0
for key, _ := range m {
sm.s[i] = key
i++
}
sort.Sort(sm)
return sm.s
}
2013-12-26 13:05:16 +00:00
type KNNClassifier struct {
Data mat.DenseMatrix
Name string
2013-12-26 19:52:36 +00:00
Labels []string
2013-12-26 13:05:16 +00:00
}
2013-12-27 00:59:06 +00:00
func RandomArray(n int) []float64 {
ReturnedArray := make([]float64, n)
for i := 0; i < n; i++ {
ReturnedArray[i] = rand.Float64()
}
return ReturnedArray
}
//Mints a new classifier
2013-12-28 10:00:20 +00:00
func (KNN *KNNClassifier) New(name string, labels []string, numbers []float64, x int, y int) {
// if x != len(KNN.Labels) {
// return errors.New("KNN: There must be a label for each row")
// }
2013-12-26 19:52:36 +00:00
KNN.Data = *mat.MakeDenseMatrix(numbers, x, y)
KNN.Name = name
KNN.Labels = labels
2013-12-26 13:05:16 +00:00
}
2013-12-27 00:59:06 +00:00
//Computes a variety of distance metrics between two vectors
2013-12-28 10:00:20 +00:00
//Only returns Euclidean distance at the moment
2013-12-28 18:41:13 +00:00
func (KNN *KNNClassifier) ComputeDistance(vector *mat.DenseMatrix, testrow *mat.DenseMatrix) float64 {
2013-12-28 10:00:20 +00:00
var sum float64
2013-12-28 18:41:13 +00:00
difference, err := testrow.MinusDense(vector)
2013-12-28 10:00:20 +00:00
flat := difference.Array()
2013-12-27 00:59:06 +00:00
if err != nil {
fmt.Println(err)
}
2013-12-28 10:00:20 +00:00
for _, i := range flat {
squared := math.Pow(i, 2)
sum += squared
}
eucdistance := math.Sqrt(sum)
return eucdistance
2013-12-26 19:52:36 +00:00
}
2013-12-27 00:59:06 +00:00
//Returns a classification based on a vector input
2013-12-28 10:00:20 +00:00
//Just need to build the max voting function
func (KNN *KNNClassifier) Predict(vector *mat.DenseMatrix, K int) ([]string, []int) {
rows := KNN.Data.Rows()
rownumbers := make(map[int]float64)
labels := make([]string, K)
for i := 0; i < rows; i++{
2013-12-28 18:41:13 +00:00
row := KNN.Data.GetRowVector(i)
eucdistance := KNN.ComputeDistance(row, vector)
2013-12-28 10:00:20 +00:00
rownumbers[i] = eucdistance
}
sorted := sortMap(rownumbers)
values := sorted[:K]
for _, elem := range values {
labels = append(labels, KNN.Labels[elem])
}
2013-12-28 18:41:13 +00:00
return labels, values
2013-12-26 19:52:36 +00:00
}
2013-12-27 00:59:06 +00:00
//Returns a label, given an index
2013-12-26 19:52:36 +00:00
func (KNN *KNNClassifier) GetLabel(index int) string {
return KNN.Labels[index]
}
2013-12-26 13:05:16 +00:00
func main(){
2013-12-27 00:59:06 +00:00
for {
2013-12-28 18:41:13 +00:00
cols, rows, _, labels, data := base.ParseCsv("/Users/stephenwhitworth/Desktop/model.csv", 1, []int{2,3})
2013-12-27 00:59:06 +00:00
knn := KNNClassifier{}
2013-12-28 18:41:13 +00:00
random := mat.MakeDenseMatrix([]float64{410,433,400,400},1,2)
knn.New("Testing", labels, data, rows, cols)
labels, indexes := knn.Predict(random, 1)
fmt.Println(labels, indexes)
2013-12-27 00:59:06 +00:00
}
2013-12-26 13:05:16 +00:00
}