pub fn kshape_fd(
data: &FdMatrix,
config: &KShapeConfig,
) -> Result<KShapeResult, FdarError>Expand description
Cluster a curve set with k-Shape.
Runs config.n_init random-partition restarts (each seeded
config.seed + restart_idx), keeping the lowest-total-inertia run. Every
series is z-normalized once up front; each restart iterates SBD assignment +
shape-extraction centroid refinement to convergence or max_iter. Empty
clusters are recovered in place by farthest-point reassignment; the algorithm
never panics.
§Errors
FdarError::InvalidDimensionifdatais empty (no series or no points).FdarError::InvalidParameterifn_clusters < 1,n_clusters > n, orn_init < 1.
§Examples
use fdars_core::kshape::{kshape_fd, KShapeConfig};
use fdars_core::FdMatrix;
// Two shape groups: rising ramps vs. falling ramps (column-major FdMatrix).
let rows = [
vec![0.0, 1.0, 2.0, 3.0, 4.0],
vec![0.1, 1.1, 2.0, 3.1, 3.9],
vec![4.0, 3.0, 2.0, 1.0, 0.0],
vec![3.9, 3.1, 2.0, 0.9, 0.1],
];
let (n, m) = (4, 5);
let mut data = vec![0.0; n * m];
for (i, r) in rows.iter().enumerate() {
for (j, &v) in r.iter().enumerate() {
data[i + j * n] = v; // column-major
}
}
let data = FdMatrix::from_slice(&data, n, m).unwrap();
let cfg = KShapeConfig::new(2);
let res = kshape_fd(&data, &cfg).unwrap();
assert_eq!(res.cluster.len(), 4);
// The two rising ramps share a cluster; the two falling ramps share the other.
assert_eq!(res.cluster[0], res.cluster[1]);
assert_eq!(res.cluster[2], res.cluster[3]);
assert_ne!(res.cluster[0], res.cluster[2]);