func (k *TriangleKMeans) recalculateCentroids() [][]float64 {
	classTotal := make([][]float64, len(k.Centroids))
	classCount := make([]int64, len(k.Centroids))
	for j := range k.Centroids {
		classTotal[j] = make([]float64, len(k.trainingSet[0]))
	}
	for i, x := range k.trainingSet {
		classCount[k.guesses[i]]++
		for j := range x {
			classTotal[k.guesses[i]][j] += x[j]
		}
	}
	centroids := append([][]float64{}, k.Centroids...)
	for j := range centroids {
		if classCount[j] == 0 {
			for l := range centroids[j] {
				centroids[j][l] = 10 * (rand.Float64() - 0.5)
			}
			continue
		}
		for l := range centroids[j] {
			centroids[j][l] = classTotal[j][l] / float64(classCount[j])
		}
	}
	return centroids
}
recalculateCentroids assigns each centroid to
the mean of all points assigned to it. This
method is abstracted within the Triangle
accelerated KMeans variant because you are
skipping a lot of distance calculations within
the actual algorithm, so finding the mean of
assigned points is harder to embed.

The method returns the new centers instead of
modifying the model's centroids.
package cluster
import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"time"
	"github.com/cdipaolo/goml/base"
)
type TriangleKMeans struct {
	maxIterations int
	alpha float64
	trainingSet [][]float64
	guesses     []int
	info        []pointInfo
	Centroids [][]float64 `json:"centroids"`
	centroidDist    [][]float64
	minCentroidDist []float64
	Output io.Writer
}
type pointInfo struct {
	lower []float64
	upper float64
	recompute bool
}
func NewTriangleKMeans(k, maxIterations int, trainingSet [][]float64) *TriangleKMeans {
	var features int
	if len(trainingSet) != 0 {
		features = len(trainingSet[0])
	}
	var guesses []int
	var info []pointInfo
	guesses = make([]int, len(trainingSet))
	info = make([]pointInfo, len(trainingSet))
	for i := range info {
		info[i] = pointInfo{
			lower:     make([]float64, k),
			upper:     0,
			recompute: true,
		}
	}
	rand.Seed(time.Now().UTC().Unix())
	centroids := make([][]float64, k)
	centroidDist := make([][]float64, k)
	minCentroidDist := make([]float64, k)
	for i := range centroids {
		centroids[i] = make([]float64, features)
		centroidDist[i] = make([]float64, k)
	}
	return &TriangleKMeans{
		maxIterations: maxIterations,
		trainingSet: trainingSet,
		guesses:     guesses,
		info:        info,
		Centroids:       centroids,
		centroidDist:    centroidDist,
		minCentroidDist: minCentroidDist,
		Output: os.Stdout,
	}
}
func (k *TriangleKMeans) UpdateTrainingSet(trainingSet [][]float64) error {
	if len(trainingSet) == 0 {
		return fmt.Errorf("Error: length of given training set is 0! Need data!")
	}
	k.trainingSet = trainingSet
	k.guesses = make([]int, len(trainingSet))
	return nil
}
func (k *TriangleKMeans) Examples() int {
	return len(k.trainingSet)
}
func (k *TriangleKMeans) MaxIterations() int {
	return k.maxIterations
}
func (k *TriangleKMeans) Predict(x []float64, normalize ...bool) ([]float64, error) {
	if len(x) != len(k.Centroids[0]) {
		return nil, fmt.Errorf("Error: Centroid vector should be the same length as input vector!\n\tLength of x given: %v\n\tLength of centroid: %v\n", len(x), len(k.Centroids[0]))
	}
	if len(normalize) != 0 && normalize[0] {
		base.NormalizePoint(x)
	}
	var guess int
	minDiff := diff(x, k.Centroids[0])
	for j := 1; j < len(k.Centroids); j++ {
		difference := diff(x, k.Centroids[j])
		if difference < minDiff {
			minDiff = difference
			guess = j
		}
	}
	return []float64{float64(guess)}, nil
}
func (k *TriangleKMeans) computeCentroidDistanceMatrix() {
	for i := range k.Centroids {
		for j := 0; j < i; j++ {
			k.centroidDist[i][j] = 0.5 * diff(k.Centroids[i], k.Centroids[j])
		}
	}
	for i := range k.Centroids {
		for j := len(k.Centroids) - 1; j > i; j-- {
			k.centroidDist[i][j] = k.centroidDist[j][i]
		}
	}
	for i := range k.Centroids {
		var min float64
		if i == 0 && len(k.Centroids) > 1 {
			min = k.centroidDist[i][1]
		} else {
			min = k.centroidDist[i][0]
		}
		for j := range k.Centroids {
			if i == j {
				continue
			}
			if k.centroidDist[i][j] < min {
				min = k.centroidDist[i][j]
			}
		}
		k.minCentroidDist[i] = min
	}
}