---
title: "mlr3 Integration"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{mlr3 Integration}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
options(datatable.print.topn = 3L)
```

This vignette demonstrates how to integrate the G-means algorithm with the
[mlr3](https://mlr3.mlr-org.com/) framework for [clustering](https://mlr3cluster.mlr-org.com/).
G-means extends k-means by adapting the number of clusters based on statistical tests.

We'll start by loading the necessary libraries:

```{r setup, message = FALSE}
library(gmeans)
library(mlr3cluster)
library(mlr3misc)
library(mlr3viz)
library(paradox)
```

We define a custom `LearnerClustGMeans` class by extending the
[`mlr3cluster::LearnerClust`](https://mlr3cluster.mlr-org.com/reference/LearnerClust.html)
class for G-means clustering.

```{r}
LearnerClustGMeans <- R6::R6Class("LearnerClustGMeans",
  inherit = LearnerClust,
  public = list(
    initialize = function() {
      param_set <- ps(
        k_init = p_int(2L, default = 2L, tags = "train"),
        k_max = p_int(2L, default = 10L, tags = "train"),
        level = p_dbl(0, 1, default = 0.05, tags = "train"),
        iter.max = p_int(1L, default = 10L, tags = "train"),
        algorithm = p_fct(
          levels = c("Hartigan-Wong", "Lloyd", "Forgy", "MacQueen"),
          default = "Hartigan-Wong",
          tags = "train"
        ),
        trace = p_lgl(default = FALSE, tags = "train")
      )

      super$initialize(
        id = "clust.gmeans",
        feature_types = c("logical", "integer", "numeric"),
        predict_types = "partition",
        param_set = param_set,
        properties = c("partitional", "exclusive", "complete"),
        packages = "gmeans",
        man = "mlr3cluster::mlr_learners_clust.gmeans",
        label = "G-means"
      )
    }
  ),
  private = list(
    .train = function(task) {
      pv <- self$param_set$get_values(tags = "train")
      m <- invoke(gmeans::gmeans, x = task$data(), .args = pv)
      if (self$save_assignments) {
        self$assignments <- m$cluster
      }
      m
    },
    .predict = function(task) {
      partition <- invoke(predict, self$model,
        newdata = task$data(), type = "class_ids"
      )
      PredictionClust$new(task = task, partition = partition)
    }
  )
)

mlr_learners$add("clust.gmeans", LearnerClustGMeans)
```

We create a clustering task using the `usarrests` dataset and train the G-means learner.

```{r}
task <- tsk("usarrests")
learner <- lrn("clust.gmeans")
learner$train(task)
prediction <- learner$predict(task = task)
prediction
```

We use `autoplot()` to visualize the clusters produced by the G-means learner.
This provides a simple scatter plot of the cluster assignments.

```{r, message = FALSE, warning = FALSE, dpi = 300}
autoplot(prediction, task)
```

We calculate performance metrics such as within-cluster sum of squares (`clust.wss`)
and silhouette width (`clust.silhouette`), which measure cluster compactness and
separation, respectively.

```{r}
measures <- msrs(c("clust.wss", "clust.silhouette"))
prediction$score(measures, task)
```

Alternatively, evaluate the clustering with PCA (Principal Component Analysis) and
Silhouette plots:

```{r, dpi = 300}
autoplot(prediction, task, type = "pca")
autoplot(prediction, task, type = "sil")
```

Lastly, we can now easily run a benchmark experiment to compare G-means with other
clustering algorithms.

```{r}
learners <- list(
  lrn("clust.featureless"),
  lrn("clust.kmeans"),
  lrn("clust.gmeans")
)
measures <- list(msr("clust.wss"), msr("clust.silhouette"))
bmr <- benchmark(benchmark_grid(tsk("ruspini"), learners, rsmp("insample")))
bmr$aggregate(measures)[, c(4, 7, 8)]
```
