<commit_before>package golearn

import (
		mat "github.com/skelterjohn/go.matrix"
		rand "math/rand"
		"math"
		"fmt"
		"sort"
		"github.com/sjwhitworth/golearn/base/"
		// "errors""
		)
 
//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 {
	return sm.m[sm.s[i]] < sm.m[sm.s[j]]
}
 
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
}

//A KNN Classifier. Consists of a data matrix, associated labels in the same order as the matrix, and a name.
type KNNClassifier struct {
	BasePredictor
}

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.
func (KNN *KNNClassifier) New(name string, labels []string, numbers []float64, x int, y int) {
	
	//Write in some error handling here
	// if x != len(KNN.Labels) {
	// 	return errors.New("KNN: There must be a label for each row")
	// }

	KNN.Data = *mat.MakeDenseMatrix(numbers, x, y)
	KNN.Name = name
	KNN.Labels = labels
}

//Computes the Euclidean distance between two vectors.
func (KNN *KNNClassifier) ComputeDistance(vector *mat.DenseMatrix, testrow *mat.DenseMatrix) float64 {
	var sum float64

	difference, err := testrow.MinusDense(vector)
	flat := difference.Array()

	if err != nil {
		fmt.Println(err)
	}

	for _, i := range flat {
		squared := math.Pow(i, 2)
		sum += squared
	}

	eucdistance := math.Sqrt(sum)
	return eucdistance
}

//Returns a classification for the vector, based on a vector input, using the KNN algorithm.
func (KNN *KNNClassifier) Predict(vector *mat.DenseMatrix, K int) ([]string, []int) {

	rows := KNN.Data.Rows()
	rownumbers := make(map[int]float64)
	labels := make([]string, 1)

	for i := 0; i < rows; i++{
		row := KNN.Data.GetRowVector(i)
		eucdistance := KNN.ComputeDistance(row, vector)
		rownumbers[i] = eucdistance
	}

	sorted := sortMap(rownumbers)
	values := sorted[:K]

	for _, elem := range values {
		labels = append(labels, KNN.Labels[elem])
	}

	return labels, values
}

func main(){
	cols, rows, _, labels, data := base.ParseCsv("/Users/stephenwhitworth/Desktop/model.csv", 1, []int{2,3})
	knn := KNNClassifier{}
	random := mat.MakeDenseMatrix([]float64{4,4},1,2)
	knn.New("Testing", labels, data, rows, cols)
	
	for {
		labels, _ := knn.Predict(random, 20)
		fmt.Println(labels)
	}
}<commit_msg>Split it out, created iris example, debugged KNN<commit_after>package main

import (
		mat "github.com/skelterjohn/go.matrix"
		"math"
		"fmt"
		util "golearn/utilities"
		base "golearn/base"
		// "errors""
		)

//A KNN Classifier. Consists of a data matrix, associated labels in the same order as the matrix, and a name.
type KNNClassifier struct {
	base.BaseClassifier
}

//Mints a new classifier.
func (KNN *KNNClassifier) New(name string, labels []string, numbers []float64, x int, y int) {
	
	//Write in some error handling here
	// if x != len(KNN.Labels) {
	// 	return errors.New("KNN: There must be a label for each row")
	// }

	KNN.Data = *mat.MakeDenseMatrix(numbers, x, y)
	KNN.Name = name
	KNN.Labels = labels
}

//Computes the Euclidean distance between two vectors.
func (KNN *KNNClassifier) ComputeDistance(vector *mat.DenseMatrix, testrow *mat.DenseMatrix) float64 {
	var sum float64

	difference, err := testrow.MinusDense(vector)
	flat := difference.Array()

	if err != nil {
		fmt.Println(err)
	}

	for _, i := range flat {
		squared := math.Pow(i, 2)
		sum += squared
	}

	eucdistance := math.Sqrt(sum)
	return eucdistance
}

//Returns a classification for the vector, based on a vector input, using the KNN algorithm.
func (KNN *KNNClassifier) Predict(vector *mat.DenseMatrix, K int) (string, []int) {

	rows := KNN.Data.Rows()
	rownumbers := make(map[int]float64)
	labels := make([]string, 1)
	maxmap := make(map[string]int)

	for i := 0; i < rows; i++{
		row := KNN.Data.GetRowVector(i)
		eucdistance := KNN.ComputeDistance(row, vector)
		rownumbers[i] = eucdistance
	}

	sorted := util.SortIntMap(rownumbers)
	values := sorted[:K]

	for _, elem := range values {
		labels = append(labels, KNN.Labels[elem])

		if _, ok := maxmap[KNN.Labels[elem]]; ok {
			maxmap[KNN.Labels[elem]] += 1
		} else {
			maxmap[KNN.Labels[elem]] = 1
		}
	}

	sortedlabels := util.SortStringMap(maxmap)
	label := sortedlabels[0]

	return label, values
}

func main(){
	cols, rows, _, labels, data := base.ParseCsv("../datasets/iris.csv", 4, []int{0,1,2})
	knn := KNNClassifier{}
	knn.New("Testing", labels, data, rows, cols)
	
	for {
		randArray := util.RandomArray(3)
		random := mat.MakeDenseMatrix(randArray,1,3)
		labels, _ := knn.Predict(random, 3)
		fmt.Println(labels)
	}
}
{'fraction_non_alphanumeric': 0.1517893043827905, 'fraction_numerical': 0.011258544431041415, 'mean_word_length': 3.7928709055876686, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '555500', 'n_tokens_mistral': 2030, 'n_tokens_neox': 1888, 'n_words': 509}