## ----setup, include=FALSE-----------------------------------------------------
knitr::opts_chunk$set(
  collapse  = TRUE,
  comment   = "#>",
  fig.width = 6,
  fig.height = 4,
  out.width = "90%"
)
library(phynotype)
set.seed(42)

## -----------------------------------------------------------------------------
X <- iris[, 1:4]  # 150 x 4 numeric matrix
head(X)

## -----------------------------------------------------------------------------
iris_mixed <- iris          # 4 numeric + 1 factor column
iris_mixed$Group <- as.character(
  ifelse(iris$Sepal.Length > 5.8, "large", "small")
)
Xenc <- prepare_mixed_data(iris_mixed[, c(1:4, 6)], center = TRUE, scale = TRUE)
dim(Xenc)

## -----------------------------------------------------------------------------
d_gower <- mixed_distance(iris_mixed[, c(1:4, 6)])
class(d_gower)

## -----------------------------------------------------------------------------
fit_km <- cluster(X, method = "kmeans", k = 3, seed = 1)
fit_km

## -----------------------------------------------------------------------------
if (requireNamespace("cluster", quietly = TRUE)) {
  fit_pam <- cluster(X, method = "pam", k = 3)
  fit_pam
}

## -----------------------------------------------------------------------------
# From a distance object (supports mixed data via mixed_distance())
d <- mixed_distance(X)
fit_hc <- cluster(d, method = "hclust", k = 3)
fit_hc
plot_dendrogram(fit_hc)

## -----------------------------------------------------------------------------
if (requireNamespace("cluster", quietly = TRUE)) {
  fit_ag <- cluster(d, method = "agnes", k = 3)
  fit_ag
}

## -----------------------------------------------------------------------------
if (requireNamespace("dbscan", quietly = TRUE)) {
  fit_db <- cluster(X, method = "dbscan", eps = 0.5, minPts = 5)
  fit_db
  # Noise points
  sum(clusters(fit_db) == 0)
}

## -----------------------------------------------------------------------------
if (requireNamespace("mclust", quietly = TRUE)) {
  fit_gmm <- cluster(X, method = "gmm", k = 3, seed = 1)
  fit_gmm
  # Soft membership probabilities
  head(membership(fit_gmm))
}

## -----------------------------------------------------------------------------
if (requireNamespace("clustMixType", quietly = TRUE)) {
  fit_kp <- cluster(iris, method = "kproto", k = 3, seed = 1)
  fit_kp
  # Mixed prototypes (centroids + modes)
  prototypes(fit_kp)
}

## -----------------------------------------------------------------------------
iris_chr <- iris
iris_chr$Species <- as.character(iris_chr$Species)

fit_kmm <- cluster(iris_chr, method = "kmm", k = 3, seed = 1)
fit_kmm
summary(fit_kmm)
prototypes(fit_kmm)

## -----------------------------------------------------------------------------
# Integer assignment vector
head(clusters(fit_km))

# Numeric centroid matrix (k-means, hclust)
centers(fit_km)

# Named size vector
sizes(fit_km)

# Number of clusters
n_clusters(fit_km)

# Method label
method_used(fit_km)

## -----------------------------------------------------------------------------
val <- validate(fit_km)
val$metrics_table

## -----------------------------------------------------------------------------
val_ext <- validate(fit_km, truth = iris$Species)
val_ext$metrics_table

## -----------------------------------------------------------------------------
grid_val <- validate(X, method = "kmeans", k = 2:6)
grid_val$metrics_table

## -----------------------------------------------------------------------------
if (requireNamespace("cluster", quietly = TRUE)) {
  plot_silhouette(fit_km)
}

## -----------------------------------------------------------------------------
exp <- explore(fit_km)

## -----------------------------------------------------------------------------
exp$size_table
plot_cluster_sizes(fit_km)

## -----------------------------------------------------------------------------
head(exp$feature_summary)
plot_feature_profiles(exp)

## -----------------------------------------------------------------------------
exp$separation_table

## -----------------------------------------------------------------------------
plot_clusters(fit_km)

if (requireNamespace("FactoMineR", quietly = TRUE)) {
  mixed_embed <- data.frame(
    x = c(1, 2, 8, 9, 1.5, 8.5),
    group = factor(c("a", "a", "b", "b", "a", "b"))
  )
  fit_famd <- cluster(mixed_embed, method = "kmm", k = 2, seed = 1)
  plot_clusters(fit_famd)

  cat_embed <- data.frame(
    a = factor(c("x", "x", "y", "y")),
    b = factor(c("u", "v", "u", "v"))
  )
  fit_mca <- cluster(cat_embed, method = "kmm", k = 2, seed = 1)
  plot_clusters(fit_mca)
}

plot_clusters(fit_hc)

## -----------------------------------------------------------------------------
plot_biplot(fit_km)
plot_biplot(fit_km, variant = "cos2")
plot_biplot(fit_km, variant = "label")

## -----------------------------------------------------------------------------
new_obs <- data.frame(
  Sepal.Length = c(5.0, 6.5, 7.2),
  Sepal.Width  = c(3.5, 2.9, 3.2),
  Petal.Length = c(1.5, 4.5, 6.0),
  Petal.Width  = c(0.3, 1.5, 2.2)
)

pred <- predict(fit_km, new_obs)
pred$clusters

## -----------------------------------------------------------------------------
head(pred$distances)

## -----------------------------------------------------------------------------
mfit <- metacluster(
  X,
  methods = c("kmeans", "pam", "hclust"),
  k       = 2:5,
  seed    = 1
)
mfit

## -----------------------------------------------------------------------------
head(mfit$candidate_table)

## -----------------------------------------------------------------------------
mfit$stability_summary

## -----------------------------------------------------------------------------
mfit$selection_summary

## -----------------------------------------------------------------------------
validate(mfit)$metrics_table
plot_coassoc(mfit)
plot_consensus(mfit)

## -----------------------------------------------------------------------------
plot_dendrogram(mfit)

## -----------------------------------------------------------------------------
imp <- feature_importance(fit_km, n_repeats = 5, seed = 1)
imp$summary
plot(imp)

## -----------------------------------------------------------------------------
lx <- lime_explain(fit_km, iris[c(1, 51, 101), 1:4],
                   n_permutations = 100, n_features = 4, seed = 1)
lx$explanations[, c("observation", "feature", "estimate", "direction")]
plot(lx)

## -----------------------------------------------------------------------------
cp <- ceteris_paribus(
  fit_km,
  iris[c(1, 51, 101), 1:4],
  features  = c("Petal.Length", "Petal.Width"),
  grid_size = 20
)
plot(cp)

## ----eval=FALSE---------------------------------------------------------------
# # 1. Fit
# fit <- cluster(iris[, 1:4], method = "kmeans", k = 3, seed = 1)
# 
# # 2. Validate
# val <- validate(fit, truth = iris$Species)
# 
# # 3. Explore
# exp <- explore(fit)
# 
# # 4. Predict
# pred <- predict(fit, iris[1:5, 1:4])
# 
# # 5. Interpret
# imp <- feature_importance(fit, n_repeats = 10, seed = 1)
# lx  <- lime_explain(fit, iris[1:3, 1:4], n_permutations = 200, seed = 1)
# cp  <- ceteris_paribus(fit, iris[1:3, 1:4])
# 
# # 6. Consensus (when a single solution is uncertain)
# mfit <- metacluster(iris[, 1:4],
#                     methods = c("kmeans", "pam", "hclust"),
#                     k = 2:5, seed = 1)
# validate(mfit)$metrics_table

