///|
pub struct Clusters {
features : Array[String]
basis : Basis
centers : Array[Array[Double]]
assignments : Array[Int]
counts : Array[Int]
inertia : Double
iterations : Int
converged : Bool
}
///|
fn squared_euclidean(a : Array[Double], b : Array[Double]) -> Double {
let mut total = 0.0
for j in 0.. (Int, Double) {
let mut best = 0
let mut value = squared_euclidean(row, centers[0])
for j in 1.. Clusters raise CodaError {
let n = data.row_count()
let p = data.part_count() - 1
if count < 1 || count > n || count > 64 {
raise Invalid("cluster count must be 1..min(N,64)")
}
if max_iterations < 1 || max_iterations > 500 {
raise Budget("iterations must be 1..500")
}
if n.to_double() *
p.to_double() *
count.to_double() *
max_iterations.to_double() >
2.0e7 {
raise Budget("k-means exceeds 20 million coordinate comparisons")
}
let b = helmert_basis(data.part_count())
let rows = data.ilr_rows(b)
let centers = [rows[0].copy()]
while centers.length() < count {
let mut farthest = 0
let mut separation = -1.0
for i, row in rows {
let (_, value) = closest_center(row, centers)
if value > separation {
separation = value
farthest = i
}
}
centers.push(rows[farthest].copy())
}
let assignments = Array::make(n, -1)
let mut converged = false
let mut iterations = 0
for iteration in 0.. 0 {
for j in 0.. Array[Int] {
self.assignments.copy()
}
///|
pub fn Clusters::counts(self : Clusters) -> Array[Int] {
self.counts.copy()
}
///|
pub fn Clusters::inertia(self : Clusters) -> Double {
self.inertia
}
///|
pub fn Clusters::iterations(self : Clusters) -> Int {
self.iterations
}
///|
pub fn Clusters::converged(self : Clusters) -> Bool {
self.converged
}
///|
pub fn Clusters::centers(
self : Clusters,
) -> Array[Array[Double]] raise CodaError {
self.centers.map(c => ilr_inverse(c, self.basis))
}
///|
pub fn Clusters::predict(
self : Clusters,
data : Dataset,
) -> Array[Int] raise CodaError {
matching_features(data.features, self.features)
data
.ilr_rows(self.basis)
.map(row => {
let (k, _) = closest_center(row, self.centers)
k
})
}