From 7bfe96ef4da68d8d7b6ce694d2fb8794c0b1f31e Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:35:18 -0800 Subject: [PATCH 01/44] add dbscan file using hier_clust.R as template --- R/dbscan.R | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 R/dbscan.R diff --git a/R/dbscan.R b/R/dbscan.R new file mode 100644 index 0000000..338ce84 --- /dev/null +++ b/R/dbscan.R @@ -0,0 +1,193 @@ +#' Density-Based Spatial Clustering of Applications with Noise +#' +#' @description +#' +#' `dbscan` defines a model that fits clusters based on areas with observations +#' that are densly packed together +#' +#' There are different ways to fit this model, and the method of estimation is +#' chosen by setting the model engine. The engine-specific pages for this model +#' are listed below. +#' +#' - \link[=details_hier_clust_stats]{stats} +#' +#' @param mode A single character string for the type of model. The only +#' possible value for this model is "partition". +#' @param engine A single character string specifying what computational engine +#' to use for fitting. Possible engines are listed below. The default for this +#' model is `"stats"`. +#' @param num_clusters Positive integer, number of clusters in model (optional). +#' @param cut_height Positive double, height at which to cut dendrogram to +#' obtain cluster assignments (only used if `num_clusters` is `NULL`) +#' @param linkage_method the agglomeration method to be used. This should be (an +#' unambiguous abbreviation of) one of `"ward.D"`, `"ward.D2"`, `"single"`, +#' `"complete"`, `"average"` (= UPGMA), `"mcquitty"` (= WPGMA), `"median"` (= +#' WPGMC) or `"centroid"` (= UPGMC). +#' +#' @details +#' +#' ## What does it mean to predict? +#' +#' To predict the cluster assignment for a new observation, we find the closest +#' cluster. How we measure “closeness” is dependent on the specified type of +#' linkage in the model: +#' +#' - *single linkage*: The new observation is assigned to the same cluster as +#' its nearest observation from the training data. +#' - *complete linkage*: The new observation is assigned to the cluster with the +#' smallest maximum distances between training observations and the new +#' observation. +#' - *average linkage*: The new observation is assigned to the cluster with the +#' smallest average distances between training observations and the new +#' observation. +#' - *centroid method*: The new observation is assigned to the cluster with the +#' closest centroid, as in prediction for k_means. +#' - *Ward’s method*: The new observation is assigned to the cluster with the +#' smallest increase in **error sum of squares (ESS)** due to the new +#' addition. The ESS is computed as the sum of squared distances between +#' observations in a cluster, and the centroid of the cluster. +#' +#' @return A `dbscan` cluster specification. +#' +#' @examples +#' # Show all engines +#' modelenv::get_from_env("dbscan") +#' +#' dbscan() +#' @export +dbscan <- + function(mode = "partition", + engine = "dbscan", + radius = NULL, + minpts = NULL) { + args <- list( + radius = enquo(radius), + minpts = enquo(minpts) + ) + + new_cluster_spec( + "dbscan", + args = args, + eng_args = NULL, + mode = mode, + method = NULL, + engine = engine + ) + } + +#' @export +print.dbscan <- function(x, ...) { + cat("DBSCAN Clustering Specification (", x$mode, ")\n\n", sep = "") + model_printer(x, ...) + + if (!is.null(x$method$fit$args)) { + cat("Model fit template:\n") + print(show_call(x)) + } + + invisible(x) +} + +# ------------------------------------------------------------------------------ + +#' @method update dbscan +#' @rdname tidyclust_update +#' @export +update.dbscan <- function(object, + parameters = NULL, + radius = NULL, + minpts = NULL, + fresh = FALSE, ...) { + eng_args <- parsnip::update_engine_parameters( + object$eng_args, + fresh = fresh, ... + ) + + if (!is.null(parameters)) { + parameters <- parsnip::check_final_param(parameters) + } + args <- list( + num_clusters = enquo(num_clusters), + cut_height = enquo(cut_height), + linkage_method = enquo(linkage_method) + ) + + args <- parsnip::update_main_parameters(args, parameters) + + if (fresh) { + object$args <- args + object$eng_args <- eng_args + } else { + null_args <- map_lgl(args, null_value) + if (any(null_args)) { + args <- args[!null_args] + } + if (length(args) > 0) { + object$args[names(args)] <- args + } + if (length(eng_args) > 0) { + object$eng_args[names(eng_args)] <- eng_args + } + } + + new_cluster_spec( + "dbscan", + args = object$args, + eng_args = object$eng_args, + mode = object$mode, + method = NULL, + engine = object$engine + ) +} + +# # ---------------------------------------------------------------------------- + +#' @export +check_args.dbscan <- function(object) { + args <- lapply(object$args, rlang::eval_tidy) + + if (all(is.numeric(args$num_clusters)) && any(args$num_clusters < 0)) { + rlang::abort("The number of centers should be >= 0.") + } + + invisible(object) +} + +#' @export +translate_tidyclust.hier_clust <- function(x, engine = x$engine, ...) { + x <- translate_tidyclust.default(x, engine, ...) + x +} + +# ------------------------------------------------------------------------------ + +#' Simple Wrapper around hclust function +#' +#' This wrapper prepares the data into a distance matrix to send to +#' `stats::hclust` and retains the parameters `num_clusters` or `h` as an +#' attribute. +#' +#' @param x matrix or data frame +#' @param num_clusters the number of clusters +#' @param cut_height the height to cut the dendrogram +#' @param linkage_method the agglomeration method to be used. This should be (an +#' unambiguous abbreviation of) one of `"ward.D"`, `"ward.D2"`, `"single"`, +#' `"complete"`, `"average"` (= UPGMA), `"mcquitty"` (= WPGMA), `"median"` (= +#' WPGMC) or `"centroid"` (= UPGMC). +#' @param dist_fun A distance function to use +#' +#' @return A dendrogram +#' @keywords internal +#' @export +.hier_clust_fit_stats <- function(x, + num_clusters = NULL, + cut_height = NULL, + linkage_method = NULL, + dist_fun = Rfast::Dist) { + dmat <- dist_fun(x) + res <- stats::hclust(stats::as.dist(dmat), method = linkage_method) + attr(res, "num_clusters") <- num_clusters + attr(res, "cut_height") <- cut_height + attr(res, "training_data") <- x + return(res) +} From a3f3d73065852fe0e0c1f6776ec3c022a2f231ac Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 16 Nov 2024 14:31:59 -0800 Subject: [PATCH 02/44] dbscan --> db_clust + add documentation --- R/db_clust.R | 169 ++++++++++++++++++++++++++++++++++++++++++++ R/dbscan.R | 193 --------------------------------------------------- 2 files changed, 169 insertions(+), 193 deletions(-) create mode 100644 R/db_clust.R delete mode 100644 R/dbscan.R diff --git a/R/db_clust.R b/R/db_clust.R new file mode 100644 index 0000000..28ce960 --- /dev/null +++ b/R/db_clust.R @@ -0,0 +1,169 @@ +#' Density-Based Spatial Clustering of Applications with Noise +#' +#' @description +#' +#' `db_clust` defines a model that fits clusters based on areas with observations +#' that are densely packed together +#' +#' There are different ways to fit this model, and the method of estimation is +#' chosen by setting the model engine. The engine-specific pages for this model +#' are listed below. +#' +#' - \link[=details_hier_clust_stats]{stats} +#' +#' @param mode A single character string for the type of model. The only +#' possible value for this model is "partition". +#' @param engine A single character string specifying what computational engine +#' to use for fitting. The engine for this model is `"dbscan"`. +#' @param radius Positive integer, Radius used to determine core-points and cluster points together (required). +#' @param minpts Positive double, Minimum number of points needed to form a cluster (required) +#' +#' +#' @details +#' +#' ## What does it mean to predict? +#' +#' To predict the cluster assignment for a new observation, we determine if a point +#' is within the radius of a core point. If so, we predict the same cluster as the core point. +#' If not, we predict the observation to be an outlier. +#' +#' +#' @return A `db_clust` cluster specification. +#' +#' @examples +#' # Show all engines +#' modelenv::get_from_env("db_clust") +#' +#' dbscan() +#' @export +db_clust <- + function(mode = "partition", + engine = "dbscan", + radius = NULL, + minpts = NULL) { + args <- list( + radius = enquo(radius), + minpts = enquo(minpts) + ) + + new_cluster_spec( + "db_clust", + args = args, + eng_args = NULL, + mode = mode, + method = NULL, + engine = engine + ) + } + +#' @export +print.db_clust <- function(x, ...) { + cat("DBSCAN Clustering Specification (", x$mode, ")\n\n", sep = "") + model_printer(x, ...) + + if (!is.null(x$method$fit$args)) { + cat("Model fit template:\n") + print(show_call(x)) + } + + invisible(x) +} + +# ------------------------------------------------------------------------------ + +#' @method update db_clust +#' @rdname tidyclust_update +#' @export +update.db_clust <- function(object, + parameters = NULL, + radius = NULL, + minpts = NULL, + fresh = FALSE, ...) { + eng_args <- parsnip::update_engine_parameters( + object$eng_args, + fresh = fresh, ... + ) + + if (!is.null(parameters)) { + parameters <- parsnip::check_final_param(parameters) + } + args <- list( + radius = enquo(radius), + minpts = enquo(minpts), + ) + + args <- parsnip::update_main_parameters(args, parameters) + + if (fresh) { + object$args <- args + object$eng_args <- eng_args + } else { + null_args <- map_lgl(args, null_value) + if (any(null_args)) { + args <- args[!null_args] + } + if (length(args) > 0) { + object$args[names(args)] <- args + } + if (length(eng_args) > 0) { + object$eng_args[names(eng_args)] <- eng_args + } + } + + new_cluster_spec( + "db_clust", + args = object$args, + eng_args = object$eng_args, + mode = object$mode, + method = NULL, + engine = object$engine + ) +} + +# # ---------------------------------------------------------------------------- + +#' @export +check_args.db_clust <- function(object) { + args <- lapply(object$args, rlang::eval_tidy) + + if (all(is.numeric(args$minpts)) && any(args$minpts < 0)) { + rlang::abort("The number of points in a cluster should be > 0.") + } + + if (all(is.numeric(args$radius)) && any(args$radius < 0)) { + rlang::abort("The radius used to create a cluster should be > 0.") + } + + invisible(object) +} + +#' @export +translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { + x <- translate_tidyclust.default(x, engine, ...) + x +} + +# ------------------------------------------------------------------------------ + +#' Simple Wrapper around dbscan function +#' +#' This wrapper prepares the data into a distance matrix to send to +#' `dbscan::dbscan` and retains the parameters `radius` or `minpts` as an +#' attribute. +#' +#' @param x matrix or data frame +#' @param radius Radius used to determine core-points and cluster points together +#' @param minpts Minimum number of points needed to form a cluster +#' +#' @return dbscan object +#' @keywords internal +#' @export +.db_clust_fit_dbscan <- function(x, + radius = NULL, + minpts = NULL) { + res <- dbscan::dbscan(x, eps = raidus, minPts = minPts) + attr(res, "radius") <- radius + attr(res, "minpts") <- minpts + attr(res, "training_data") <- x + return(res) +} diff --git a/R/dbscan.R b/R/dbscan.R deleted file mode 100644 index 338ce84..0000000 --- a/R/dbscan.R +++ /dev/null @@ -1,193 +0,0 @@ -#' Density-Based Spatial Clustering of Applications with Noise -#' -#' @description -#' -#' `dbscan` defines a model that fits clusters based on areas with observations -#' that are densly packed together -#' -#' There are different ways to fit this model, and the method of estimation is -#' chosen by setting the model engine. The engine-specific pages for this model -#' are listed below. -#' -#' - \link[=details_hier_clust_stats]{stats} -#' -#' @param mode A single character string for the type of model. The only -#' possible value for this model is "partition". -#' @param engine A single character string specifying what computational engine -#' to use for fitting. Possible engines are listed below. The default for this -#' model is `"stats"`. -#' @param num_clusters Positive integer, number of clusters in model (optional). -#' @param cut_height Positive double, height at which to cut dendrogram to -#' obtain cluster assignments (only used if `num_clusters` is `NULL`) -#' @param linkage_method the agglomeration method to be used. This should be (an -#' unambiguous abbreviation of) one of `"ward.D"`, `"ward.D2"`, `"single"`, -#' `"complete"`, `"average"` (= UPGMA), `"mcquitty"` (= WPGMA), `"median"` (= -#' WPGMC) or `"centroid"` (= UPGMC). -#' -#' @details -#' -#' ## What does it mean to predict? -#' -#' To predict the cluster assignment for a new observation, we find the closest -#' cluster. How we measure “closeness” is dependent on the specified type of -#' linkage in the model: -#' -#' - *single linkage*: The new observation is assigned to the same cluster as -#' its nearest observation from the training data. -#' - *complete linkage*: The new observation is assigned to the cluster with the -#' smallest maximum distances between training observations and the new -#' observation. -#' - *average linkage*: The new observation is assigned to the cluster with the -#' smallest average distances between training observations and the new -#' observation. -#' - *centroid method*: The new observation is assigned to the cluster with the -#' closest centroid, as in prediction for k_means. -#' - *Ward’s method*: The new observation is assigned to the cluster with the -#' smallest increase in **error sum of squares (ESS)** due to the new -#' addition. The ESS is computed as the sum of squared distances between -#' observations in a cluster, and the centroid of the cluster. -#' -#' @return A `dbscan` cluster specification. -#' -#' @examples -#' # Show all engines -#' modelenv::get_from_env("dbscan") -#' -#' dbscan() -#' @export -dbscan <- - function(mode = "partition", - engine = "dbscan", - radius = NULL, - minpts = NULL) { - args <- list( - radius = enquo(radius), - minpts = enquo(minpts) - ) - - new_cluster_spec( - "dbscan", - args = args, - eng_args = NULL, - mode = mode, - method = NULL, - engine = engine - ) - } - -#' @export -print.dbscan <- function(x, ...) { - cat("DBSCAN Clustering Specification (", x$mode, ")\n\n", sep = "") - model_printer(x, ...) - - if (!is.null(x$method$fit$args)) { - cat("Model fit template:\n") - print(show_call(x)) - } - - invisible(x) -} - -# ------------------------------------------------------------------------------ - -#' @method update dbscan -#' @rdname tidyclust_update -#' @export -update.dbscan <- function(object, - parameters = NULL, - radius = NULL, - minpts = NULL, - fresh = FALSE, ...) { - eng_args <- parsnip::update_engine_parameters( - object$eng_args, - fresh = fresh, ... - ) - - if (!is.null(parameters)) { - parameters <- parsnip::check_final_param(parameters) - } - args <- list( - num_clusters = enquo(num_clusters), - cut_height = enquo(cut_height), - linkage_method = enquo(linkage_method) - ) - - args <- parsnip::update_main_parameters(args, parameters) - - if (fresh) { - object$args <- args - object$eng_args <- eng_args - } else { - null_args <- map_lgl(args, null_value) - if (any(null_args)) { - args <- args[!null_args] - } - if (length(args) > 0) { - object$args[names(args)] <- args - } - if (length(eng_args) > 0) { - object$eng_args[names(eng_args)] <- eng_args - } - } - - new_cluster_spec( - "dbscan", - args = object$args, - eng_args = object$eng_args, - mode = object$mode, - method = NULL, - engine = object$engine - ) -} - -# # ---------------------------------------------------------------------------- - -#' @export -check_args.dbscan <- function(object) { - args <- lapply(object$args, rlang::eval_tidy) - - if (all(is.numeric(args$num_clusters)) && any(args$num_clusters < 0)) { - rlang::abort("The number of centers should be >= 0.") - } - - invisible(object) -} - -#' @export -translate_tidyclust.hier_clust <- function(x, engine = x$engine, ...) { - x <- translate_tidyclust.default(x, engine, ...) - x -} - -# ------------------------------------------------------------------------------ - -#' Simple Wrapper around hclust function -#' -#' This wrapper prepares the data into a distance matrix to send to -#' `stats::hclust` and retains the parameters `num_clusters` or `h` as an -#' attribute. -#' -#' @param x matrix or data frame -#' @param num_clusters the number of clusters -#' @param cut_height the height to cut the dendrogram -#' @param linkage_method the agglomeration method to be used. This should be (an -#' unambiguous abbreviation of) one of `"ward.D"`, `"ward.D2"`, `"single"`, -#' `"complete"`, `"average"` (= UPGMA), `"mcquitty"` (= WPGMA), `"median"` (= -#' WPGMC) or `"centroid"` (= UPGMC). -#' @param dist_fun A distance function to use -#' -#' @return A dendrogram -#' @keywords internal -#' @export -.hier_clust_fit_stats <- function(x, - num_clusters = NULL, - cut_height = NULL, - linkage_method = NULL, - dist_fun = Rfast::Dist) { - dmat <- dist_fun(x) - res <- stats::hclust(stats::as.dist(dmat), method = linkage_method) - attr(res, "num_clusters") <- num_clusters - attr(res, "cut_height") <- cut_height - attr(res, "training_data") <- x - return(res) -} From 27084036d1159b4fafc3292735343f6c2fda086f Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 16 Nov 2024 15:04:39 -0800 Subject: [PATCH 03/44] cluster assignment and predict helpers --- R/extract_cluster_assignment.R | 49 ++++++++++++++++++++++++++++++++++ R/predict_helpers.R | 9 +++++++ 2 files changed, 58 insertions(+) diff --git a/R/extract_cluster_assignment.R b/R/extract_cluster_assignment.R index af18ce3..0fceb06 100644 --- a/R/extract_cluster_assignment.R +++ b/R/extract_cluster_assignment.R @@ -157,6 +157,55 @@ extract_cluster_assignment.hclust <- function(object, cluster_assignment_tibble(clusters, length(unique(clusters)), ...) } +#' @export +#' +#' STILL GOTTA DO STUFF HERE +extract_cluster_assignment.db_clust <- function(object, + ..., + call = rlang::caller_env(0)) { + + args <- list(...) + + # if (!is.null(args[["h"]])) { + # rlang::abort( + # paste( + # "Using `h` argument is not supported.", + # "Please use `cut_height` instead." + # ), + # call = call + # ) + # } + # + # if (!is.null(args[["k"]])) { + # rlang::abort( + # paste( + # "Using `k` argument is not supported.", + # "Please use `num_clusters` instead." + # ), + # call = call + # ) + # } + + # if (!("num_clusters" %in% names(args) || "cut_height" %in% names(args))) { + # num_clusters <- attr(object, "num_clusters") + # cut_height <- attr(object, "cut_height") + # } else { + # num_clusters <- args[["num_clusters"]] + # cut_height <- args[["cut_height"]] + # } + # + # if (is.null(num_clusters) && is.null(cut_height)) { + # rlang::abort( + # "Please specify either `num_clusters` or `cut_height`.", + # call = call + # ) + # } + + clusters <- object %$% cluster + cluster_assignment_tibble(clusters, length(unique(clusters)), ...) +} + + # ------------------------------------------------------------------------------ cluster_assignment_tibble <- function(clusters, diff --git a/R/predict_helpers.R b/R/predict_helpers.R index f4780ae..bbf9c54 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -152,3 +152,12 @@ make_predictions <- function(x, prefix, n_clusters) { pred_clusts } + +.db_clust_predict_dbscan <- function(object, new_data, prefix = "Cluster_") { + + clusters <- predict(object, newdata = new_data, data = object$training_data) + n_clusters <- length(db$cluster %>% unique()) + + make_predictions(clusters, prefix, n_clusters) +} + From 4ff1ad4bad9d77340f116a87611d69fde2f270b9 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 16 Nov 2024 15:12:44 -0800 Subject: [PATCH 04/44] minPts -> minpts --- R/db_clust.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/db_clust.R b/R/db_clust.R index 28ce960..59d1a04 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -161,7 +161,7 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { .db_clust_fit_dbscan <- function(x, radius = NULL, minpts = NULL) { - res <- dbscan::dbscan(x, eps = raidus, minPts = minPts) + res <- dbscan::dbscan(x, eps = raidus, minPts = minpts) attr(res, "radius") <- radius attr(res, "minpts") <- minpts attr(res, "training_data") <- x From 8106e43b4e1973b5928a1ebe22933d9821b22893 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 16 Nov 2024 15:21:12 -0800 Subject: [PATCH 05/44] fix function name references --- R/db_clust.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index 59d1a04..d77ed65 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -1,4 +1,4 @@ -#' Density-Based Spatial Clustering of Applications with Noise +#' Density-Based Spatial Clustering of Applications with Noise (DBSCAN) #' #' @description #' @@ -9,7 +9,7 @@ #' chosen by setting the model engine. The engine-specific pages for this model #' are listed below. #' -#' - \link[=details_hier_clust_stats]{stats} +#' - \link[=details_db_clust_dbscan]{dbscan} #' #' @param mode A single character string for the type of model. The only #' possible value for this model is "partition". @@ -34,7 +34,7 @@ #' # Show all engines #' modelenv::get_from_env("db_clust") #' -#' dbscan() +#' db_clust() #' @export db_clust <- function(mode = "partition", From c2cc44e7060de4e6f7ccb7194fb9877706a2853b Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 4 Feb 2025 19:12:28 -0800 Subject: [PATCH 06/44] db_clust and gm_clust fit, extract clusters, and predict --- NAMESPACE | 14 + R/db_clust.R | 31 +- R/db_clust_data.R | 85 +++++ R/db_clust_dbscan.R | 11 + R/extract_cluster_assignment.R | 74 ++-- R/gm_clust.R | 164 +++++++++ R/gm_clust_data.R | 77 ++++ R/gm_clust_mclust.R | 11 + R/predict_helpers.R | 25 +- R/zzz.R | 2 + man/db_clust.Rd | 47 +++ man/details_db_clust_dbscan.Rd | 9 + man/details_gm_clust_mclust.Rd | 9 + man/dot-db_clust_fit_dbscan.Rd | 24 ++ man/dot-gm_clust_fit_mclust.Rd | 22 ++ man/gm_clust.Rd | 44 +++ man/tidyclust_update.Rd | 28 +- tests/testthat/_snaps/k_means.new.md | 85 +++++ .../_snaps/reconcile_clusterings.new.md | 17 + vignettes/articles/db_clust.Rmd | 338 ++++++++++++++++++ vignettes/articles/gm_clust.Rmd | 130 +++++++ 21 files changed, 1187 insertions(+), 60 deletions(-) create mode 100644 R/db_clust_data.R create mode 100644 R/db_clust_dbscan.R create mode 100644 R/gm_clust.R create mode 100644 R/gm_clust_data.R create mode 100644 R/gm_clust_mclust.R create mode 100644 man/db_clust.Rd create mode 100644 man/details_db_clust_dbscan.Rd create mode 100644 man/details_gm_clust_mclust.Rd create mode 100644 man/dot-db_clust_fit_dbscan.Rd create mode 100644 man/dot-gm_clust_fit_mclust.Rd create mode 100644 man/gm_clust.Rd create mode 100644 tests/testthat/_snaps/k_means.new.md create mode 100644 tests/testthat/_snaps/reconcile_clusterings.new.md create mode 100644 vignettes/articles/db_clust.Rmd create mode 100644 vignettes/articles/gm_clust.Rmd diff --git a/NAMESPACE b/NAMESPACE index 9960b43..759e97a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,12 +2,16 @@ S3method(as_tibble,cluster_metric_set) S3method(augment,cluster_fit) +S3method(check_args,db_clust) S3method(check_args,default) +S3method(check_args,gm_clust) S3method(check_args,hier_clust) S3method(check_args,k_means) S3method(extract_cluster_assignment,KMeansCluster) +S3method(extract_cluster_assignment,Mclust) S3method(extract_cluster_assignment,cluster_fit) S3method(extract_cluster_assignment,cluster_spec) +S3method(extract_cluster_assignment,dbscan) S3method(extract_cluster_assignment,hclust) S3method(extract_cluster_assignment,kmeans) S3method(extract_cluster_assignment,kmodes) @@ -37,6 +41,8 @@ S3method(print,cluster_fit) S3method(print,cluster_metric_set) S3method(print,cluster_spec) S3method(print,control_cluster) +S3method(print,db_clust) +S3method(print,gm_clust) S3method(print,hier_clust) S3method(print,k_means) S3method(required_pkgs,cluster_fit) @@ -57,7 +63,9 @@ S3method(sse_within_total,cluster_fit) S3method(sse_within_total,cluster_spec) S3method(sse_within_total,workflow) S3method(tidy,cluster_fit) +S3method(translate_tidyclust,db_clust) S3method(translate_tidyclust,default) +S3method(translate_tidyclust,gm_clust) S3method(translate_tidyclust,hier_clust) S3method(translate_tidyclust,k_means) S3method(tunable,cluster_spec) @@ -66,9 +74,13 @@ S3method(tune_args,cluster_spec) S3method(tune_cluster,cluster_spec) S3method(tune_cluster,default) S3method(tune_cluster,workflow) +S3method(update,db_clust) +S3method(update,gm_clust) S3method(update,hier_clust) S3method(update,k_means) export("%>%") +export(.db_clust_fit_dbscan) +export(.gm_clust_fit_mclust) export(.hier_clust_fit_stats) export(.k_means_fit_ClusterR) export(.k_means_fit_clustMixType) @@ -78,6 +90,7 @@ export(augment) export(cluster_metric_set) export(control_cluster) export(cut_height) +export(db_clust) export(extract_centroids) export(extract_cluster_assignment) export(extract_fit_engine) @@ -94,6 +107,7 @@ export(fit_xy) export(fit_xy.cluster_spec) export(get_tidyclust_colors) export(glance) +export(gm_clust) export(hier_clust) export(k_means) export(knit_engine_docs) diff --git a/R/db_clust.R b/R/db_clust.R index d77ed65..d2c8e94 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -159,11 +159,30 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { #' @keywords internal #' @export .db_clust_fit_dbscan <- function(x, - radius = NULL, - minpts = NULL) { - res <- dbscan::dbscan(x, eps = raidus, minPts = minpts) - attr(res, "radius") <- radius - attr(res, "minpts") <- minpts + eps = NULL, + minPts = NULL, + ...) { + if (is.null(eps)) { + rlang::abort( + "Please specify `radius` to be able to fit specification.", + call = call("fit") + ) + } + + if (is.null(minPts)) { + rlang::abort( + "Please specify `minpts` to be able to fit specification.", + call = call("fit") + ) + } + + res <- dbscan::dbscan(x, eps = eps, minPts = minPts) + attr(res, "radius") <- eps + attr(res, "minpts") <- minPts attr(res, "training_data") <- x - return(res) + is_core <- is.corepoint(x, eps = eps, minPts = minPts) + attr(res, "core_points") <- x[is_core, ] + attr(res, "cp_clusters") <- res$cluster[is_core] + + res } diff --git a/R/db_clust_data.R b/R/db_clust_data.R new file mode 100644 index 0000000..1330f5b --- /dev/null +++ b/R/db_clust_data.R @@ -0,0 +1,85 @@ +# nocov start + +make_db_clust <- function() { + modelenv::set_new_model("db_clust") + + modelenv::set_model_mode("db_clust", "partition") + + # ---------------------------------------------------------------------------- + + modelenv::set_model_engine("db_clust", "partition", "dbscan") + modelenv::set_dependency( + model = "db_clust", + mode = "partition", + eng = "dbscan", + pkg = "dbscan" + ) + modelenv::set_dependency( + model = "db_clust", + mode = "partition", + eng = "dbscan", + pkg = "tidyclust" + ) + + modelenv::set_fit( + model = "db_clust", + eng = "dbscan", + mode = "partition", + value = list( + interface = "matrix", + protect = c("data"), + func = c(pkg = "tidyclust", fun = ".db_clust_fit_dbscan"), + defaults = list() + ) + ) + + modelenv::set_encoding( + model = "db_clust", + eng = "dbscan", + mode = "partition", + options = list( + predictor_indicators = "traditional", + compute_intercept = TRUE, + remove_intercept = TRUE, + allow_sparse_x = FALSE + ) + ) + + modelenv::set_model_arg( + model = "db_clust", + eng = "dbscan", + exposed = "radius", + original = "eps", + func = list(pkg = "dials", fun = "raidus"), + has_submodel = TRUE + ) + + modelenv::set_model_arg( + model = "db_clust", + eng = "dbscan", + exposed = "minpts", + original = "minPts", + func = list(pkg = "dials", fun = "minpts"), + has_submodel = TRUE + ) + + modelenv::set_pred( + model = "db_clust", + eng = "dbscan", + mode = "partition", + type = "cluster", + value = list( + pre = NULL, + post = NULL, + func = c(fun = ".db_clust_predict_dbscan"), + args = + list( + object = rlang::expr(object$fit), + new_data = rlang::expr(new_data) + ) + ) + ) + +} + +# nocov end diff --git a/R/db_clust_dbscan.R b/R/db_clust_dbscan.R new file mode 100644 index 0000000..56f4846 --- /dev/null +++ b/R/db_clust_dbscan.R @@ -0,0 +1,11 @@ +#' Density-Based Spatial Clustering of Applications with Noise (DBSCAN) via dbscan +#' +#' [db_clust()] creates DBSCAN model. +#' +#' @includeRmd man/rmd/db_clust_dbscan.md details +#' +#' @name details_db_clust_dbscan +#' @keywords internal +NULL + +# See inst/README-DOCS.md for a description of how these files are processed diff --git a/R/extract_cluster_assignment.R b/R/extract_cluster_assignment.R index 0fceb06..3c02a8d 100644 --- a/R/extract_cluster_assignment.R +++ b/R/extract_cluster_assignment.R @@ -158,51 +158,17 @@ extract_cluster_assignment.hclust <- function(object, } #' @export -#' -#' STILL GOTTA DO STUFF HERE -extract_cluster_assignment.db_clust <- function(object, - ..., - call = rlang::caller_env(0)) { - - args <- list(...) +extract_cluster_assignment.dbscan <- function(object, ...) { + clusters <- object$cluster + n_clusters <- length(unique(clusters)) + cluster_assignment_tibble_w_outliers(clusters, n_clusters, ...) +} - # if (!is.null(args[["h"]])) { - # rlang::abort( - # paste( - # "Using `h` argument is not supported.", - # "Please use `cut_height` instead." - # ), - # call = call - # ) - # } - # - # if (!is.null(args[["k"]])) { - # rlang::abort( - # paste( - # "Using `k` argument is not supported.", - # "Please use `num_clusters` instead." - # ), - # call = call - # ) - # } - - # if (!("num_clusters" %in% names(args) || "cut_height" %in% names(args))) { - # num_clusters <- attr(object, "num_clusters") - # cut_height <- attr(object, "cut_height") - # } else { - # num_clusters <- args[["num_clusters"]] - # cut_height <- args[["cut_height"]] - # } - # - # if (is.null(num_clusters) && is.null(cut_height)) { - # rlang::abort( - # "Please specify either `num_clusters` or `cut_height`.", - # call = call - # ) - # } - - clusters <- object %$% cluster - cluster_assignment_tibble(clusters, length(unique(clusters)), ...) +#' @export +extract_cluster_assignment.Mclust <- function(object, ...) { + clusters <- object$classification + n_clusters <- length(unique(clusters)) + cluster_assignment_tibble(clusters, n_clusters, ...) } @@ -218,3 +184,23 @@ cluster_assignment_tibble <- function(clusters, tibble::tibble(.cluster = factor(res)) } + +cluster_assignment_tibble_w_outliers <- function(clusters, + n_clusters, + ..., + prefix = "Cluster_") { + reorder_clusts <- order(union(unique(clusters), 0:(n_clusters-1))) + names <- paste0(prefix, 0:(n_clusters-1)) + res <- names[reorder_clusts][clusters+1] + res[res == paste0(prefix, "0")] <- "Outlier" + # zero_count <- 0 + # res <- sapply(res, function(x) { + # if (x == "Cluster_0") { + # zero_count <<- zero_count + 1 + # paste0("Cluster_0_", zero_count) + # } else { + # x + # } + # }) + tibble::tibble(.cluster = factor(res)) +} diff --git a/R/gm_clust.R b/R/gm_clust.R new file mode 100644 index 0000000..9c65910 --- /dev/null +++ b/R/gm_clust.R @@ -0,0 +1,164 @@ +#' Gaussian Mixture Models (GMM) +#' +#' @description +#' +#' `gm_clust` defines a model that fits clusters based on fitting a specified number of +#' multivariate normal distributions to the data. +#' +#' There are different ways to fit this model, and the method of estimation is +#' chosen by setting the model engine. The engine-specific pages for this model +#' are listed below. +#' +#' - \link[=details_gm_clust_mclust]{mclust} +#' +#' @param mode A single character string for the type of model. The only +#' possible value for this model is "partition". +#' @param engine A single character string specifying what computational engine +#' to use for fitting. The engine for this model is `"mclust"`. +#' @param num_clusters Positive integer, number of clusters in model (required). +#' +#' +#' @details +#' +#' ## What does it mean to predict? +#' +#' To predict the cluster assignment for a new observation, we determine which cluster +#' a point has the highest probability of belonging to. +#' +#' +#' @return A `gm_clust` cluster specification. +#' +#' @examples +#' # Show all engines +#' modelenv::get_from_env("gm_clust") +#' +#' gm_clust() +#' @export +gm_clust <- + function(mode = "partition", + engine = "mclust", + num_clusters = NULL) { + args <- list( + num_clusters = enquo(num_clusters) + ) + + new_cluster_spec( + "gm_clust", + args = args, + eng_args = NULL, + mode = mode, + method = NULL, + engine = engine + ) + } + +#' @export +print.gm_clust <- function(x, ...) { + cat("GMM Clustering Specification (", x$mode, ")\n\n", sep = "") + model_printer(x, ...) + + if (!is.null(x$method$fit$args)) { + cat("Model fit template:\n") + print(show_call(x)) + } + + invisible(x) +} + +# ------------------------------------------------------------------------------ + +#' @method update gm_clust +#' @rdname tidyclust_update +#' @export +update.gm_clust <- function(object, + parameters = NULL, + num_clusters = NULL, + fresh = FALSE, ...) { + eng_args <- parsnip::update_engine_parameters( + object$eng_args, + fresh = fresh, ... + ) + + if (!is.null(parameters)) { + parameters <- parsnip::check_final_param(parameters) + } + args <- list( + num_clusters = enquo(num_clusters) + ) + + args <- parsnip::update_main_parameters(args, parameters) + + if (fresh) { + object$args <- args + object$eng_args <- eng_args + } else { + null_args <- map_lgl(args, null_value) + if (any(null_args)) { + args <- args[!null_args] + } + if (length(args) > 0) { + object$args[names(args)] <- args + } + if (length(eng_args) > 0) { + object$eng_args[names(eng_args)] <- eng_args + } + } + + new_cluster_spec( + "gm_clust", + args = object$args, + eng_args = object$eng_args, + mode = object$mode, + method = NULL, + engine = object$engine + ) +} + +# # ---------------------------------------------------------------------------- + +#' @export +check_args.gm_clust <- function(object) { + args <- lapply(object$args, rlang::eval_tidy) + + if (all(is.numeric(args$num_clusters)) && any(args$num_clusters <= 0)) { + rlang::abort("The number of clusters should be > 0.") + } + + invisible(object) +} + +#' @export +translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { + x <- translate_tidyclust.default(x, engine, ...) + x +} + +# ------------------------------------------------------------------------------ + +#' Simple Wrapper around Mclust function +#' +#' This wrapper prepares the data into a distance matrix to send to +#' `mclust::Mclust` and retains the parameters `num_clusters` as an +#' attribute. +#' +#' @param x matrix or data frame +#' @param num_clusters Number of clusters +#' +#' @return mclust object +#' @keywords internal +#' @export +.gm_clust_fit_mclust <- function(x, + G = NULL, + ...) { + if (is.null(G)) { + rlang::abort( + "Please specify `num_clusters` to be able to fit specification.", + call = call("fit") + ) + } + + res <- mclust::Mclust(x, G = G) + attr(res, "num_clusters") <- G + attr(res, "training_data") <- x + res +} diff --git a/R/gm_clust_data.R b/R/gm_clust_data.R new file mode 100644 index 0000000..08efe84 --- /dev/null +++ b/R/gm_clust_data.R @@ -0,0 +1,77 @@ +# nocov start + +make_gm_clust <- function() { + modelenv::set_new_model("gm_clust") + + modelenv::set_model_mode("gm_clust", "partition") + + # ---------------------------------------------------------------------------- + + modelenv::set_model_engine("gm_clust", "partition", "mclust") + modelenv::set_dependency( + model = "gm_clust", + mode = "partition", + eng = "mclust", + pkg = "mclust" + ) + modelenv::set_dependency( + model = "gm_clust", + mode = "partition", + eng = "mclust", + pkg = "tidyclust" + ) + + modelenv::set_fit( + model = "gm_clust", + eng = "mclust", + mode = "partition", + value = list( + interface = "matrix", + protect = c("data"), + func = c(pkg = "tidyclust", fun = ".gm_clust_fit_mclust"), + defaults = list() + ) + ) + + modelenv::set_encoding( + model = "gm_clust", + eng = "mclust", + mode = "partition", + options = list( + predictor_indicators = "traditional", + compute_intercept = TRUE, + remove_intercept = TRUE, + allow_sparse_x = FALSE + ) + ) + + modelenv::set_model_arg( + model = "gm_clust", + eng = "mclust", + exposed = "num_clusters", + original = "G", + func = list(pkg = "dials", fun = "num_clusters"), + has_submodel = TRUE + ) + + + modelenv::set_pred( + model = "gm_clust", + eng = "mclust", + mode = "partition", + type = "cluster", + value = list( + pre = NULL, + post = NULL, + func = c(fun = ".gm_clust_predict_mclust"), + args = + list( + object = rlang::expr(object$fit), + new_data = rlang::expr(new_data) + ) + ) + ) + +} + +# nocov end diff --git a/R/gm_clust_mclust.R b/R/gm_clust_mclust.R new file mode 100644 index 0000000..769298e --- /dev/null +++ b/R/gm_clust_mclust.R @@ -0,0 +1,11 @@ +#' Gaussian Mixture Model (GMM) via mclust +#' +#' [gm_clust()] creates GMM model. +#' +#' @includeRmd man/rmd/gm_clust_mclust.md details +#' +#' @name details_gm_clust_mclust +#' @keywords internal +NULL + +# See inst/README-DOCS.md for a description of how these files are processed diff --git a/R/predict_helpers.R b/R/predict_helpers.R index bbf9c54..29b520f 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -3,6 +3,13 @@ make_predictions <- function(x, prefix, n_clusters) { factor(x, levels = levels, labels = paste0(prefix, levels)) } +make_predictions_w_outliers <- function(x, prefix, n_clusters) { + levels <- seq_len(n_clusters)-1 + labels <- paste0(prefix, levels) + labels[labels == paste0(prefix, "0")] <- "Outlier" + factor(x, levels = levels, labels = labels) +} + .k_means_predict_stats <- function(object, new_data, prefix = "Cluster_") { res <- object$centers res <- flexclust::dist2(res, new_data) @@ -150,13 +157,25 @@ make_predictions <- function(x, prefix, n_clusters) { } pred_clusts <- unique(clusters$.cluster)[pred_clusts_num] - pred_clusts + pred_clust } .db_clust_predict_dbscan <- function(object, new_data, prefix = "Cluster_") { - clusters <- predict(object, newdata = new_data, data = object$training_data) - n_clusters <- length(db$cluster %>% unique()) + cp <- attr(object, "core_points") + cp_clusters <- attr(object, "cp_clusters") + eps <- attr(object, "radius") + + clusters <- dbscan:::.predict_frNN(newdata = new_data, data = cp, cp_clusters, eps = eps) + n_clusters <- length(unique(object$cluster)) + + make_predictions_w_outliers(clusters, prefix, n_clusters) +} + +.gm_clust_predict_mclust <- function(object, new_data, prefix = "Cluster_") { + + clusters <- predict(object, newdata = new_data)$classification + n_clusters <- length(clusters %>% unique()) make_predictions(clusters, prefix, n_clusters) } diff --git a/R/zzz.R b/R/zzz.R index 44938d0..2754a6d 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -3,6 +3,8 @@ .onLoad <- function(libname, pkgname) { make_hier_clust() make_k_means() + make_db_clust() + make_gm_clust() s3_register("generics::required_pkgs", "cluster_fit") s3_register("generics::required_pkgs", "cluster_spec") diff --git a/man/db_clust.Rd b/man/db_clust.Rd new file mode 100644 index 0000000..c352b9c --- /dev/null +++ b/man/db_clust.Rd @@ -0,0 +1,47 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/db_clust.R +\name{db_clust} +\alias{db_clust} +\title{Density-Based Spatial Clustering of Applications with Noise (DBSCAN)} +\usage{ +db_clust(mode = "partition", engine = "dbscan", radius = NULL, minpts = NULL) +} +\arguments{ +\item{mode}{A single character string for the type of model. The only +possible value for this model is "partition".} + +\item{engine}{A single character string specifying what computational engine +to use for fitting. The engine for this model is \code{"dbscan"}.} + +\item{radius}{Positive integer, Radius used to determine core-points and cluster points together (required).} + +\item{minpts}{Positive double, Minimum number of points needed to form a cluster (required)} +} +\value{ +A \code{db_clust} cluster specification. +} +\description{ +\code{db_clust} defines a model that fits clusters based on areas with observations +that are densely packed together + +There are different ways to fit this model, and the method of estimation is +chosen by setting the model engine. The engine-specific pages for this model +are listed below. +\itemize{ +\item \link[=details_db_clust_dbscan]{dbscan} +} +} +\details{ +\subsection{What does it mean to predict?}{ + +To predict the cluster assignment for a new observation, we determine if a point +is within the radius of a core point. If so, we predict the same cluster as the core point. +If not, we predict the observation to be an outlier. +} +} +\examples{ +# Show all engines +modelenv::get_from_env("db_clust") + +db_clust() +} diff --git a/man/details_db_clust_dbscan.Rd b/man/details_db_clust_dbscan.Rd new file mode 100644 index 0000000..3ac9204 --- /dev/null +++ b/man/details_db_clust_dbscan.Rd @@ -0,0 +1,9 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/db_clust_dbscan.R +\name{details_db_clust_dbscan} +\alias{details_db_clust_dbscan} +\title{Density-Based Spatial Clustering of Applications with Noise (DBSCAN) via dbscan} +\description{ +\code{\link[=db_clust]{db_clust()}} creates DBSCAN model. +} +\keyword{internal} diff --git a/man/details_gm_clust_mclust.Rd b/man/details_gm_clust_mclust.Rd new file mode 100644 index 0000000..385a563 --- /dev/null +++ b/man/details_gm_clust_mclust.Rd @@ -0,0 +1,9 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gm_clust_mclust.R +\name{details_gm_clust_mclust} +\alias{details_gm_clust_mclust} +\title{Gaussian Mixture Model (GMM) via mclust} +\description{ +\code{\link[=gm_clust]{gm_clust()}} creates GMM model. +} +\keyword{internal} diff --git a/man/dot-db_clust_fit_dbscan.Rd b/man/dot-db_clust_fit_dbscan.Rd new file mode 100644 index 0000000..4c2f6d9 --- /dev/null +++ b/man/dot-db_clust_fit_dbscan.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/db_clust.R +\name{.db_clust_fit_dbscan} +\alias{.db_clust_fit_dbscan} +\title{Simple Wrapper around dbscan function} +\usage{ +.db_clust_fit_dbscan(x, eps = NULL, minPts = NULL, ...) +} +\arguments{ +\item{x}{matrix or data frame} + +\item{radius}{Radius used to determine core-points and cluster points together} + +\item{minpts}{Minimum number of points needed to form a cluster} +} +\value{ +dbscan object +} +\description{ +This wrapper prepares the data into a distance matrix to send to +\code{dbscan::dbscan} and retains the parameters \code{radius} or \code{minpts} as an +attribute. +} +\keyword{internal} diff --git a/man/dot-gm_clust_fit_mclust.Rd b/man/dot-gm_clust_fit_mclust.Rd new file mode 100644 index 0000000..6a4ea76 --- /dev/null +++ b/man/dot-gm_clust_fit_mclust.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gm_clust.R +\name{.gm_clust_fit_mclust} +\alias{.gm_clust_fit_mclust} +\title{Simple Wrapper around dbscan function} +\usage{ +.gm_clust_fit_mclust(x, G = NULL, ...) +} +\arguments{ +\item{x}{matrix or data frame} + +\item{num_clusters}{Number of clusters} +} +\value{ +mclust object +} +\description{ +This wrapper prepares the data into a distance matrix to send to +\code{mclust::Mclust} and retains the parameters \code{num_clusters} as an +attribute. +} +\keyword{internal} diff --git a/man/gm_clust.Rd b/man/gm_clust.Rd new file mode 100644 index 0000000..9daf6ac --- /dev/null +++ b/man/gm_clust.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gm_clust.R +\name{gm_clust} +\alias{gm_clust} +\title{Gaussian Mixture Models (GMM)} +\usage{ +gm_clust(mode = "partition", engine = "mclust", num_clusters = NULL) +} +\arguments{ +\item{mode}{A single character string for the type of model. The only +possible value for this model is "partition".} + +\item{engine}{A single character string specifying what computational engine +to use for fitting. The engine for this model is \code{"mclust"}.} + +\item{num_clusters}{Positive integer, number of clusters in model (required).} +} +\value{ +A \code{gm_clust} cluster specification. +} +\description{ +\code{gm_clust} defines a model that fits clusters based on fitting a specified number of +multivariate normal distributions to the data. + +There are different ways to fit this model, and the method of estimation is +chosen by setting the model engine. The engine-specific pages for this model +are listed below. +\itemize{ +\item \link[=details_gm_clust_mclust]{mclust} +} +} +\details{ +\subsection{What does it mean to predict?}{ + +To predict the cluster assignment for a new observation, we determine which cluster +a point has the highest probability of belonging to. +} +} +\examples{ +# Show all engines +modelenv::get_from_env("gm_clust") + +gm_clust() +} diff --git a/man/tidyclust_update.Rd b/man/tidyclust_update.Rd index d11819f..2b6c906 100644 --- a/man/tidyclust_update.Rd +++ b/man/tidyclust_update.Rd @@ -1,11 +1,25 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/hier_clust.R, R/k_means.R, R/update.R -\name{update.hier_clust} +% Please edit documentation in R/db_clust.R, R/gm_clust.R, R/hier_clust.R, +% R/k_means.R, R/update.R +\name{update.db_clust} +\alias{update.db_clust} +\alias{update.gm_clust} \alias{update.hier_clust} \alias{update.k_means} \alias{tidyclust_update} \title{Update a cluster specification} \usage{ +\method{update}{db_clust}( + object, + parameters = NULL, + radius = NULL, + minpts = NULL, + fresh = FALSE, + ... +) + +\method{update}{gm_clust}(object, parameters = NULL, num_clusters = NULL, fresh = FALSE, ...) + \method{update}{hier_clust}( object, parameters = NULL, @@ -27,6 +41,11 @@ updating. If the main arguments are used, these will supersede the values in \code{parameters}. Also, using engine arguments in this object will result in an error.} +\item{fresh}{A logical for whether the arguments should be modified in-place +or replaced wholesale.} + +\item{...}{Not used for \code{update()}.} + \item{num_clusters}{Positive integer, number of clusters in model.} \item{cut_height}{Positive double, height at which to cut dendrogram to @@ -36,11 +55,6 @@ obtain cluster assignments (only used if \code{num_clusters} is \code{NULL})} unambiguous abbreviation of) one of \code{"ward.D"}, \code{"ward.D2"}, \code{"single"}, \code{"complete"}, \code{"average"} (= UPGMA), \code{"mcquitty"} (= WPGMA), \code{"median"} (= WPGMC) or \code{"centroid"} (= UPGMC).} - -\item{fresh}{A logical for whether the arguments should be modified in-place -or replaced wholesale.} - -\item{...}{Not used for \code{update()}.} } \value{ An updated cluster specification. diff --git a/tests/testthat/_snaps/k_means.new.md b/tests/testthat/_snaps/k_means.new.md new file mode 100644 index 0000000..51be933 --- /dev/null +++ b/tests/testthat/_snaps/k_means.new.md @@ -0,0 +1,85 @@ +# bad input + + Code + k_means(mode = "bogus") + Condition + Error in `modelenv::check_spec_mode_engine_val()`: + ! 'bogus' is not a known mode for model `k_means()`. + +--- + + Code + bt <- k_means(num_clusters = -1) %>% set_engine("stats") + fit(bt, mpg ~ ., mtcars) + Condition + Error in `check_args()`: + ! The number of centers should be >= 0. + +--- + + Code + translate_tidyclust(k_means(), engine = NULL) + Condition + Error in `translate_tidyclust.default()`: + ! Please set an engine. + +--- + + Code + translate_tidyclust(k_means(formula = ~x)) + Condition + Error in `k_means()`: + ! unused argument (formula = ~x) + +# printing + + Code + k_means() + Output + K Means Cluster Specification (partition) + + Computational engine: stats + + +--- + + Code + k_means(num_clusters = 10) + Output + K Means Cluster Specification (partition) + + Main Arguments: + num_clusters = 10 + + Computational engine: stats + + +# updating + + Code + k_means(num_clusters = 5) %>% update(num_clusters = tune()) + Output + K Means Cluster Specification (partition) + + Main Arguments: + num_clusters = tune() + + Computational engine: stats + + +# errors if `num_clust` isn't specified + + Code + k_means() %>% set_engine("stats") %>% fit(~., data = mtcars) + Condition + Error in `fit()`: + ! Please specify `num_clust` to be able to fit specification. + +--- + + Code + k_means() %>% set_engine("ClusterR") %>% fit(~., data = mtcars) + Condition + Error in `fit()`: + ! This engine requires some package installs: 'ClusterR' + diff --git a/tests/testthat/_snaps/reconcile_clusterings.new.md b/tests/testthat/_snaps/reconcile_clusterings.new.md new file mode 100644 index 0000000..8bb2168 --- /dev/null +++ b/tests/testthat/_snaps/reconcile_clusterings.new.md @@ -0,0 +1,17 @@ +# reconciliation works with uneven numbers + + Code + reconcile_clusterings_mapping(primary_cluster_assignment, + alt_cluster_assignment, one_to_one = TRUE) + Condition + Error in `reconcile_clusterings_mapping()`: + ! The package "RcppHungarian" is required. + +# reconciliation errors for uneven lengths + + Code + reconcile_clusterings_mapping(letters, letters[1:10]) + Condition + Error in `reconcile_clusterings_mapping()`: + ! The package "RcppHungarian" is required. + diff --git a/vignettes/articles/db_clust.Rmd b/vignettes/articles/db_clust.Rmd new file mode 100644 index 0000000..6839510 --- /dev/null +++ b/vignettes/articles/db_clust.Rmd @@ -0,0 +1,338 @@ +--- +title: "Density-Based Clustering" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Density-Based Clustering} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + + +## Setup +```{r} +library(workflows) +library(parsnip) +``` + +```{r} +library(tidyclust) +library(tidyverse) +library(tidymodels) +set.seed(838383) +``` + + +Load and clean a dataset: + +```{r} +data("penguins", package = "modeldata") + +penguins <- penguins %>% + select(bill_length_mm, bill_depth_mm) %>% + drop_na() + + +# shuffle rows +penguins <- penguins %>% + sample_n(nrow(penguins)) +``` + +At the end of this vignette, you will find a brief overview of the DBSCAN algorithm. + +## A brief introduction to density-based clustering + +Density-Based Spatial Clustering of Applications with Noise (DBSCAN) is a method of unsupervised learning that groups observations into clusters based on their density in multidimensional space. Unlike methods such as k-means, DBSCAN does not require specifying the number of clusters beforehand and can identify clusters of arbitrary shapes. Additionally, it can classify points that do not belong to any cluster as noise, allowing for greater flexibility in handling real-world data. + +In DBSCAN, observations are considered as locations in multidimensional space. The algorithm works by defining a cluster as a dense region of connected points. During the fitting process, points are classified as core points, border points, or noise based on their proximity to other points (**radius**) and a density threshold (**minpts**). + +```{r, include = FALSE} +penguins_std <- penguins %>% + mutate(bill_length_std = scale(bill_length_mm)[,1], + bill_depth_std = scale(bill_depth_mm)[,1]) %>% + select(bill_length_std, bill_depth_std) +``` + + +```{r, echo = FALSE} + +# penguins_std %>% + # ggplot() + + # geom_point(aes(x = bill_length_std, y = bill_depth_std)) + + # theme_minimal() + + # coord_fixed() + +``` + +1. For each observation in the data, determine whether each point is a core point. A core points is defined as an observation which has more than the specified **minpts** points (including the point itself) within the specified **radius** around the point. + + +```{r, include = FALSE} +library(dbscan) +eps <- 0.35 +minpts <- 10 +dbscan_fit <- dbscan(penguins_std, eps = eps, minPts = minpts) + +``` + +```{r, echo = FALSE} +library(ggforce) +penguins_std %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std)) + + theme_minimal() + + geom_circle(tibble(x = c(-0.79162259), y = c(1.79706436), radius = rep(eps,1)), + mapping = aes(x0 = x, y0 = y, r = eps), + color = "gray", linewidth = 0.8) + + geom_point(tibble(x = c(-0.79162259), y = c(1.79706436)), mapping = aes(x = x, y = y, color = c("1"))) + + coord_fixed() + + theme(legend.position = "none") + + scale_color_manual(values = c("red")) +``` + + + +```{r, echo = FALSE} +penguins_new <- penguins_std +penguins_new$cluster <- factor(dbscan_fit$cluster) +penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = minpts)) == 1, "Yes", "No"), levels = c("Yes", "No")) + +penguins_new %>% + ggplot(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + + geom_point() + + theme_minimal() + + coord_fixed() + + labs(color = "Is a core point?") + + scale_color_manual(values = c("red", "black")) + + theme(legend.position = "none") +``` + +2. For each Core point, assign it and all the points within the specified radius around the point ta + +```{r, echo = FALSE} +penguins_new %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + + theme_minimal() + + geom_circle(tibble(x = c(-1.10300165), y = c(0.73366185), radius = rep(eps, 1)), + mapping = aes(x0 = x, y0 = y, r = eps), + color = "gray", linewidth = 0.8) + + geom_point(tibble(x = c(-1.10300165), y = c(0.73366185)), mapping = aes(x = x, y = y, color = c("1"))) + + coord_fixed() + + theme(legend.position = "none") + + scale_color_manual(values = c("red", "black", "#619CFF")) +``` + + + +```{r, echo = FALSE} +penguins_new %>% + mutate(cp = if_else(sqrt((bill_length_std - -1.10300165)^2 + (bill_depth_std - 0.73366185)^2) <= eps, "1", cp)) %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + + theme_minimal() + + geom_circle(tibble(x = c(-1.10300165), y = c(0.73366185), radius = rep(eps, 1)), + mapping = aes(x0 = x, y0 = y, r = eps), + color = "gray", linewidth = 0.8) + + geom_point(tibble(x = c(-1.10300165), y = c(0.73366185)), mapping = aes(x = x, y = y, color = c("1"))) + + coord_fixed() + + theme(legend.position = "none") + + scale_color_manual(values = c("#619CFF", "black", "red")) +``` + + +```{r, echo = FALSE} +penguins_new %>% + mutate(cluster_temp = if_else(cluster == 1, "temp", cp)) %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster_temp)) + + theme_minimal() + + geom_circle(tibble(x = c(-1.25), y = c(-0.32), radius = rep(eps, 1)), + mapping = aes(x0 = x, y0 = y, r = eps), + color = "gray", linewidth = 0.8) + + geom_point(tibble(x = c(-1.25), y = c(-0.32)), mapping = aes(x = x, y = y, color = c("1"))) + + coord_fixed() + + theme(legend.position = "none") + + scale_color_manual(values = c("#619CFF", "black", "#619CFF", "red")) +``` + + +```{r, echo = FALSE} +penguins_new %>% + mutate(cluster_temp = case_when(cluster == 1 ~ "temp", + sqrt((bill_length_std - 1.2)^2 + (bill_depth_std - 1.05)^2) <= eps ~ "1", + TRUE ~ cp)) %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster_temp)) + + theme_minimal() + + geom_circle(tibble(x = c(1.2), y = c(1.05), radius = rep(eps, 1)), + mapping = aes(x0 = x, y0 = y, r = eps), + color = "gray", linewidth = 0.8) + + geom_point(tibble(x = c(1.2), y = c(1.05)), mapping = aes(x = x, y = y, color = c("1")), size = 1.8) + + coord_fixed() + + theme(legend.position = "none") + + scale_color_manual(values = c("#00BA38", "black", "#619CFF", "red")) +``` + + +```{r, echo = FALSE} +penguins_new %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster)) + + theme_minimal() + + coord_fixed() + + scale_color_manual(values = c("black", "#619CFF", "#F8766D", "#00BA38", "#C77CFF")) + + theme(legend.position = "none") + +``` + + +## db clust specification in {`tidyclust`} + +```{r} +db_clust_spec <- db_clust(radius = 0.35, minpts = 10) + +db_clust_spec +``` + +There is currently one engine: `dbscan::dbscan` (default) + +## Fitting db_clust models + +We fit the model to data in the usual way: + +```{r} +db_clust_fit <- db_clust_spec %>% + fit( ~ bill_length_std + bill_depth_std, + data = penguins_std + ) + +db_clust_fit %>% + summary() +``` + +We can also extract the standard `tidyclust` summary list: + + +```{r} +# no extract fit summary method for db_clust object yet + +# db_clust_summary <- db_clust_fit %>% extract_fit_summary() + +# db_clust_summary %>% str() +``` + +```{r} +db_clust_fit %>% extract_cluster_assignment() +``` + + +```{r} +penguins_new %>% + mutate(cluster2 = (db_clust_fit %>% extract_cluster_assignment())$.cluster) %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster2)) + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = "green", size = 2), data = penguins_new %>% .[144,]) + + theme_minimal() + + coord_fixed() + + scale_color_manual(values = c("#619CFF", "#F8766D", "#00BA38", "black", "green")) + + theme(legend.position = "none") +``` + + +If you have not yet read the `k_means` vignette, we recommend reading that first; +functions that are used in this vignette are explained in more detail there. + + +## Prediction + + + + +Since $DBSCAN$ algorithm ultimately assigns training observations to the +clusters based on proximity to core points, it is natural to "predict" that test +observations belong to a cluster if they are within $radius$ distance to a core point. + +The `predict()` function behaves as expected, producing cluster assignment +predictions on new data based on distance to the core points from the fitted model. + + +```{r} +new_penguin <- tibble( + bill_length_std = -1.2454235, + bill_depth_std = 0.5012132 +) + +db_clust_fit %>% + predict(new_penguin) +``` + +```{r} +set.seed(80) + +dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) +is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) +pred_data <- penguins_std[is_core,] + +pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) +``` + + +```{r} +test <- db_clust_fit %>% + predict(penguins_std) %>% + mutate(.fit_cluster = (db_clust_fit %>% extract_cluster_assignment())$.cluster, + .bc = pred, + .bc = case_when(.bc == 0 ~ "Outlier", + TRUE ~ paste0("Cluster_", .bc))) +# %>% +# filter(.pred_cluster != .fit_cluster) + +# want to assign to closer corepoint + + +which(test$.pred_cluster != test$.bc) +``` + + +```{r, include = FALSE} + +dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) +is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) +pred_data <- penguins_std[is_core,] + +pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) + +preds <- cbind( + db_clust_fit %>% extract_cluster_assignment(), + db_clust_fit %>% predict(penguins_std), + .pred_clust_adj = paste0("Cluster_", dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps)) + +``` +```{r} +preds %>% filter(.cluster != .pred_cluster) +``` + + +```{r} +cbind( + attr(db_clust_fit$fit, "training_data"), + attr(db_clust_fit$fit, "core_points") +) + +dist(db_clust_fit) + + + + +new_penguin + + +``` + diff --git a/vignettes/articles/gm_clust.Rmd b/vignettes/articles/gm_clust.Rmd new file mode 100644 index 0000000..bdae1f4 --- /dev/null +++ b/vignettes/articles/gm_clust.Rmd @@ -0,0 +1,130 @@ +--- +title: "Gaussian Model Clustering" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Gaussian Model Clustering} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + + +## Setup +```{r} +library(workflows) +library(parsnip) +library(mclust) +``` + +```{r} +library(tidyclust) +library(tidyverse) +library(tidymodels) +set.seed(838383) +``` + + +Load and clean a dataset: + +```{r} +data("penguins", package = "modeldata") + +penguins <- penguins %>% + select(bill_length_mm, bill_depth_mm) %>% + drop_na() + + +# shuffle rows +penguins <- penguins %>% + sample_n(nrow(penguins)) +``` + + + +At the end of this vignette, you will find a brief overview of the GMM algorithm. + + + +## gm clust specification in {`tidyclust`} + +```{r} +gm_clust_spec <- gm_clust(num_clusters = 3) + +gm_clust_spec +``` + +There is currently one engine: `mclust::Mclust` (default) + +## Fitting gm_clust models + +We fit the model to data in the usual way: + +```{r} +gm_clust_fit <- gm_clust_spec %>% + fit( ~ bill_length_mm + bill_depth_mm, + data = penguins + ) + +gm_clust_fit %>% + summary() +``` +We can also extract the standard `tidyclust` summary list: + + +```{r} +# gm_clust_summary <- gm_clust_fit %>% extract_fit_summary() + +# gm_clust_summary %>% str() +``` + + +```{r} +gm_clust_fit %>% extract_cluster_assignment() + + + +``` + +If you have not yet read the `k_means` vignette, we recommend reading that first; +functions that are used in this vignette are explained in more detail there. + + +## Prediction + + + + +write stuff here + +```{r} +new_penguin <- tibble( + bill_length_mm = 40, + bill_depth_mm = 20 +) + +gm_clust_fit %>% + predict(new_penguin) +``` + + +## A brief introduction to guassian mixture models + + +write and explain here + + + + + + + + + + + From e43433b8a5ed0418d70ea246634e3907a731e35d Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 22 Feb 2025 10:01:07 -0800 Subject: [PATCH 07/44] add helper to make db_clust fit deterministic --- R/db_clust.R | 47 ++++++++++- R/extract_cluster_assignment.R | 2 +- R/predict_helpers.R | 6 +- man/dbscan_helper.Rd | 18 ++++ man/dot-gm_clust_fit_mclust.Rd | 2 +- vignettes/articles/db_clust.Rmd | 144 ++++++++++++++++++++++++++------ vignettes/articles/gm_clust.Rmd | 45 +++++++++- 7 files changed, 230 insertions(+), 34 deletions(-) create mode 100644 man/dbscan_helper.Rd diff --git a/R/db_clust.R b/R/db_clust.R index d2c8e94..7b87c7d 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -181,8 +181,51 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { attr(res, "minpts") <- minPts attr(res, "training_data") <- x is_core <- is.corepoint(x, eps = eps, minPts = minPts) - attr(res, "core_points") <- x[is_core, ] - attr(res, "cp_clusters") <- res$cluster[is_core] + attr(res, "is_core") <- is_core res } + +#' dbscan fit helper function +#' +#' This function... +#' +#' @param x matrix or data frame +#' +#' @return dbscan object +#' @keywords internal +dbscan_helper <- function(object, + ...) { + + is_core <- attr(object, "is_core") + print(length(is_core)) + training_data <- data.frame(attr(object, "training_data")) + cp <- training_data[is_core,] + non_cp <- training_data[!is_core,] + cp_clusters <- object$cluster[is_core] + eps <- attr(object, "radius") + + # get fit values according to closest core point + non_cp_clusters <- dbscan:::.predict_frNN(newdata = non_cp, data = cp, cp_clusters, eps = eps) + + # join back separated fits into proper order in training data + non_cp_clusters <- data.frame(non_cp_clusters) + cp_clusters <- data.frame(cp_clusters) + + # create vars to join back results in proper order + training_data$overall_order <- 1:nrow(training_data) + training_data$is_core <- ifelse(is_core, "cp", "non cp") + non_cp_clusters$is_core <- "non cp" + cp_clusters$is_core <- "cp" + + training_data$id <- ave(training_data$is_core, training_data$is_core, FUN = seq_along) + non_cp_clusters$id <- 1:nrow(non_cp_clusters) + cp_clusters$id <- 1:nrow(cp_clusters) + + training_data <- merge(x = training_data, y = non_cp_clusters, by = c("id", "is_core"), all.x = TRUE) + training_data <- merge(x = training_data, y = cp_clusters, by = c("id", "is_core"), all.x = TRUE) + + training_data$cluster <- ifelse(!is.na(training_data$non_cp_clusters), training_data$non_cp_clusters, training_data$cp_clusters) + training_data$cluster[order(training_data$overall_order)] + +} diff --git a/R/extract_cluster_assignment.R b/R/extract_cluster_assignment.R index 3c02a8d..1ff9984 100644 --- a/R/extract_cluster_assignment.R +++ b/R/extract_cluster_assignment.R @@ -159,7 +159,7 @@ extract_cluster_assignment.hclust <- function(object, #' @export extract_cluster_assignment.dbscan <- function(object, ...) { - clusters <- object$cluster + clusters <- dbscan_helper(object) n_clusters <- length(unique(clusters)) cluster_assignment_tibble_w_outliers(clusters, n_clusters, ...) } diff --git a/R/predict_helpers.R b/R/predict_helpers.R index 29b520f..a991112 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -162,8 +162,10 @@ make_predictions_w_outliers <- function(x, prefix, n_clusters) { .db_clust_predict_dbscan <- function(object, new_data, prefix = "Cluster_") { - cp <- attr(object, "core_points") - cp_clusters <- attr(object, "cp_clusters") + is_core <- attr(object, "is_core") + training_data <- attr(object, "training_data") + cp <- training_data[is_core,] + cp_clusters <- object$cluster[is_core] eps <- attr(object, "radius") clusters <- dbscan:::.predict_frNN(newdata = new_data, data = cp, cp_clusters, eps = eps) diff --git a/man/dbscan_helper.Rd b/man/dbscan_helper.Rd new file mode 100644 index 0000000..9bdeef1 --- /dev/null +++ b/man/dbscan_helper.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/db_clust.R +\name{dbscan_helper} +\alias{dbscan_helper} +\title{dbscan fit helper function} +\usage{ +dbscan_helper(x, ...) +} +\arguments{ +\item{x}{matrix or data frame} +} +\value{ +dbscan object +} +\description{ +This function... +} +\keyword{internal} diff --git a/man/dot-gm_clust_fit_mclust.Rd b/man/dot-gm_clust_fit_mclust.Rd index 6a4ea76..aad9416 100644 --- a/man/dot-gm_clust_fit_mclust.Rd +++ b/man/dot-gm_clust_fit_mclust.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/gm_clust.R \name{.gm_clust_fit_mclust} \alias{.gm_clust_fit_mclust} -\title{Simple Wrapper around dbscan function} +\title{Simple Wrapper around Mclust function} \usage{ .gm_clust_fit_mclust(x, G = NULL, ...) } diff --git a/vignettes/articles/db_clust.Rmd b/vignettes/articles/db_clust.Rmd index 6839510..256a43d 100644 --- a/vignettes/articles/db_clust.Rmd +++ b/vignettes/articles/db_clust.Rmd @@ -97,7 +97,6 @@ penguins_std %>% ``` - ```{r, echo = FALSE} penguins_new <- penguins_std penguins_new$cluster <- factor(dbscan_fit$cluster) @@ -113,9 +112,9 @@ penguins_new %>% theme(legend.position = "none") ``` -2. For each Core point, assign it and all the points within the specified radius around the point ta +2. For each core point, assign it to a cluster as well as all the points within the specified **radius** of the point. -```{r, echo = FALSE} +```{r, echo = FALSE, include = FALSE} penguins_new %>% ggplot() + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + @@ -146,6 +145,7 @@ penguins_new %>% scale_color_manual(values = c("#619CFF", "black", "red")) ``` +3. For all the points added to the cluster, check if a point added is a core point. If a point is a core point recursively add all other points wihtin that core point's **radius** to the current cluster. ```{r, echo = FALSE} penguins_new %>% @@ -162,6 +162,7 @@ penguins_new %>% scale_color_manual(values = c("#619CFF", "black", "#619CFF", "red")) ``` +4. Repeat until all core points have been assigned clusters ```{r, echo = FALSE} penguins_new %>% @@ -180,6 +181,7 @@ penguins_new %>% scale_color_manual(values = c("#00BA38", "black", "#619CFF", "red")) ``` +5. Points not assigned to a cluster are considered outliers by the algorithm. ```{r, echo = FALSE} penguins_new %>% @@ -232,8 +234,17 @@ We can also extract the standard `tidyclust` summary list: db_clust_fit %>% extract_cluster_assignment() ``` +```{r} +penguins_new %>% + mutate(cluster2 = (db_clust_fit %>% extract_cluster_assignment())$.cluster) %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster2)) +``` + + ```{r} +#| include: false penguins_new %>% mutate(cluster2 = (db_clust_fit %>% extract_cluster_assignment())$.cluster) %>% ggplot() + @@ -263,6 +274,9 @@ The `predict()` function behaves as expected, producing cluster assignment predictions on new data based on distance to the core points from the fitted model. +*Need to make sure it predicts cluster of CLOSEST core point* + + ```{r} new_penguin <- tibble( bill_length_std = -1.2454235, @@ -273,8 +287,8 @@ db_clust_fit %>% predict(new_penguin) ``` -```{r} -set.seed(80) +```{r, include=FALSE} +# set.seed(80) dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) @@ -285,54 +299,132 @@ pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_ ```{r} +dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) +is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) +pred_data <- penguins_std[is_core,] + +pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) + +pred[144] +``` + + + + +```{r, include = FALSE} + + +dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) +is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) +pred_data <- penguins_std[is_core,] + +pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) + test <- db_clust_fit %>% predict(penguins_std) %>% mutate(.fit_cluster = (db_clust_fit %>% extract_cluster_assignment())$.cluster, .bc = pred, .bc = case_when(.bc == 0 ~ "Outlier", TRUE ~ paste0("Cluster_", .bc))) -# %>% -# filter(.pred_cluster != .fit_cluster) -# want to assign to closer corepoint - -which(test$.pred_cluster != test$.bc) +which(test$.fit_cluster != test$.bc) ``` -```{r, include = FALSE} +```{r} dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) -pred_data <- penguins_std[is_core,] +core_points <- penguins_std[is_core,] +non_core_points <- penguins_std[!is_core,] -pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) - -preds <- cbind( - db_clust_fit %>% extract_cluster_assignment(), - db_clust_fit %>% predict(penguins_std), - .pred_clust_adj = paste0("Cluster_", dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps)) - +non_core_point_fits <- dbscan:::.predict_frNN(newdata = non_core_points, data = core_points, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) +core_point_fits <- dbscan_adj$cluster[is_core] ``` + + ```{r} -preds %>% filter(.cluster != .pred_cluster) +penguins_temp <- penguins_std +ncps <- data.frame(non_core_point_fits) +cps <- data.frame(core_point_fits) + +core_point_fits <- dbscan_adj$cluster[is_core] + +penguins_std$is_core <- as.character(as.numeric(is_core)) + +penguins_std$id <- ave(penguins_std$is_core, penguins_std$is_core, FUN = seq_along) +ncps$id <- 1:nrow(ncps) +ncps$is_core <- "0" +cps$id <- 1:nrow(cps) +cps$is_core <- "1" + +penguins_temp <- merge(x = penguins_temp, y = ncps, by = c("id", "is_core"), all.x = TRUE) +penguins_temp <- merge(x = penguins_temp, y = cps, by = c("id", "is_core"), all.x = TRUE) + +penguins_temp$cluster <- ifelse(!is.na(penguins_temp$non_core_point_fits), penguins_temp$non_core_point_fits, penguins_temp$core_point_fits) + + ``` + ```{r} -cbind( - attr(db_clust_fit$fit, "training_data"), - attr(db_clust_fit$fit, "core_points") -) -dist(db_clust_fit) +dbscan_helper <- function(object, + ...) { + + is_core <- attr(object, "is_core") + print(length(is_core)) + training_data <- data.frame(attr(object, "training_data")) + cp <- training_data[is_core,] + non_cp <- training_data[!is_core,] + cp_clusters <- object$cluster[is_core] + eps <- attr(object, "radius") + # get fit values according to closest core point + non_cp_clusters <- dbscan:::.predict_frNN(newdata = non_cp, data = cp, cp_clusters, eps = eps) + # join back separated fits into proper order in training data + non_cp_clusters <- data.frame(non_cp_clusters) + cp_clusters <- data.frame(cp_clusters) -new_penguin + # create vars to join back results in proper order + training_data$is_core <- ifelse(is_core, "cp", "non cp") + non_cp_clusters$is_core <- "non cp" + cp_clusters$is_core <- "cp" + training_data$overall_order <- 1:nrow(training_data) + training_data$id <- ave(training_data$is_core, training_data$is_core, FUN = seq_along) + non_cp_clusters$id <- 1:nrow(non_cp_clusters) + cp_clusters$id <- 1:nrow(cp_clusters) + + training_data <- merge(x = training_data, y = non_cp_clusters, by = c("id", "is_core"), all.x = TRUE) + training_data <- merge(x = training_data, y = cp_clusters, by = c("id", "is_core"), all.x = TRUE) + + training_data$cluster <- ifelse(!is.na(training_data$non_cp_clusters), training_data$non_cp_clusters, training_data$cp_clusters) + + training_data$cluster[order(training_data$overall_order)] + +} ``` + +```{r} +dbscan_helper(db_clust_fit$fit) +``` + + +```{r} +penguins_new %>% + mutate(cluster2 = factor(dbscan_helper(db_clust_fit$fit))) %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster2)) + + +dbscan_helper(db_clust_fit$fit) +``` + + diff --git a/vignettes/articles/gm_clust.Rmd b/vignettes/articles/gm_clust.Rmd index bdae1f4..bece292 100644 --- a/vignettes/articles/gm_clust.Rmd +++ b/vignettes/articles/gm_clust.Rmd @@ -113,18 +113,59 @@ gm_clust_fit %>% ``` -## A brief introduction to guassian mixture models +## A brief introduction to density-based clustering -write and explain here +Gaussian Mixture Models (GMM) is a probabilistic unsupervised learning method that models data as a mixture of multiple Gaussian distributions. Unlike clustering methods such as k-means, GMM provides a soft clustering approach, where each observation has a probability of belonging to multiple clusters. This allows for more flexibility in capturing complex data distributions. +In GMM, observations are assumed to be generated from a combination of Gaussian distributions, each with its own mean and covariance. The algorithm works by iteratively estimating the parameters of these distributions using the Expectation-Maximization (EM) algorithm. During the fitting process, observations are assigned to clusters based on their probability of belonging to each Gaussian component (**num_clusters**), making GMM effective for identifying overlapping or elliptical clusters in data. +```{r} +penguins %>% + mutate(cluster = paste0("Cluster_", sample(c(1,2,3), size = nrow(penguins), replace = TRUE))) %>% + ggplot(aes(x = bill_length_mm, y = bill_depth_mm, color = cluster)) + + geom_point() + + stat_ellipse(level = .50, type = "norm", linetype = 1) + + stat_ellipse(level = .75, type = "norm", linetype = 1) + + stat_ellipse(level = .95, type = "norm", linetype = 1) + + theme_minimal() + + theme(legend.position = "none") + # scale_color_manual(values = c("red")) +``` + +```{r} +penguins %>% + mutate(cluster = (gm_clust_fit %>% extract_cluster_assignment())$.cluster) %>% + ggplot(aes(x = bill_length_mm, y = bill_depth_mm, color = cluster)) + + geom_point() + + stat_ellipse(level = .50, type = "norm", linetype = 1) + + stat_ellipse(level = .75, type = "norm", linetype = 1) + + stat_ellipse(level = .95, type = "norm", linetype = 1) + + theme_minimal() + + scale_color_manual(values = c("#F8766D", "#00BA38", "#619CFF")) + + theme(legend.position = "none") +``` + + + +```{r} +gm_clust_engine <- gm_clust_fit %>% extract_fit_engine() +``` + + +```{r} +gm_clust_engine$parameters +``` + +```{r} +plot(gm_clust_engine) +``` From 2112bd36cbb558b87ece67b58c89b73a5ccdb150 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Thu, 6 Mar 2025 12:18:00 -0800 Subject: [PATCH 08/44] fix gm clust bug + finalize vignettes --- NAMESPACE | 3 + R/db_clust.R | 3 +- R/extract_cluster_assignment.R | 10 +- R/extract_fit_summary.R | 64 ++++++ R/gm_clust.R | 1 + R/predict_helpers.R | 2 +- man/dbscan_helper.Rd | 2 +- vignettes/articles/db_clust.Rmd | 395 ++++++++------------------------ vignettes/articles/gm_clust.Rmd | 164 ++++++++++--- 9 files changed, 294 insertions(+), 350 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 759e97a..46eacc1 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,8 +19,10 @@ S3method(extract_cluster_assignment,kproto) S3method(extract_cluster_assignment,workflow) S3method(extract_fit_engine,cluster_fit) S3method(extract_fit_summary,KMeansCluster) +S3method(extract_fit_summary,Mclust) S3method(extract_fit_summary,cluster_fit) S3method(extract_fit_summary,cluster_spec) +S3method(extract_fit_summary,dbscan) S3method(extract_fit_summary,hclust) S3method(extract_fit_summary,kmeans) S3method(extract_fit_summary,kmodes) @@ -161,6 +163,7 @@ importFrom(hardhat,extract_parameter_set_dials) importFrom(hardhat,extract_preprocessor) importFrom(hardhat,extract_spec_parsnip) importFrom(hardhat,tune) +importFrom(mclust,mclustBIC) importFrom(parsnip,make_call) importFrom(parsnip,maybe_data_frame) importFrom(parsnip,maybe_matrix) diff --git a/R/db_clust.R b/R/db_clust.R index 7b87c7d..0728d1e 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -180,7 +180,7 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { attr(res, "radius") <- eps attr(res, "minpts") <- minPts attr(res, "training_data") <- x - is_core <- is.corepoint(x, eps = eps, minPts = minPts) + is_core <- dbscan::is.corepoint(x, eps = eps, minPts = minPts) attr(res, "is_core") <- is_core res @@ -198,7 +198,6 @@ dbscan_helper <- function(object, ...) { is_core <- attr(object, "is_core") - print(length(is_core)) training_data <- data.frame(attr(object, "training_data")) cp <- training_data[is_core,] non_cp <- training_data[!is_core,] diff --git a/R/extract_cluster_assignment.R b/R/extract_cluster_assignment.R index 1ff9984..e989190 100644 --- a/R/extract_cluster_assignment.R +++ b/R/extract_cluster_assignment.R @@ -193,14 +193,6 @@ cluster_assignment_tibble_w_outliers <- function(clusters, names <- paste0(prefix, 0:(n_clusters-1)) res <- names[reorder_clusts][clusters+1] res[res == paste0(prefix, "0")] <- "Outlier" - # zero_count <- 0 - # res <- sapply(res, function(x) { - # if (x == "Cluster_0") { - # zero_count <<- zero_count + 1 - # paste0("Cluster_0_", zero_count) - # } else { - # x - # } - # }) + tibble::tibble(.cluster = factor(res)) } diff --git a/R/extract_fit_summary.R b/R/extract_fit_summary.R index ce6526a..71f11d4 100644 --- a/R/extract_fit_summary.R +++ b/R/extract_fit_summary.R @@ -179,3 +179,67 @@ extract_fit_summary.hclust <- function(object, ...) { cluster_assignments = clusts ) } + +#' @export +extract_fit_summary.dbscan <- function(object, ...) { + clusts <- extract_cluster_assignment(object, ...)$.cluster + n_clust <- dplyr::n_distinct(clusts)-1 + n_outliers <- length(clusts == "Outlier") + training_data <- attr(object, "training_data") + + overall_centroid <- colMeans(training_data) + + by_clust <- training_data %>% + tibble::as_tibble() %>% + dplyr::mutate( + .cluster = clusts + ) %>% + dplyr::filter(.cluster != "Outlier") %>% + dplyr::group_by(.cluster) %>% + tidyr::nest() + + centroids <- by_clust$data %>% + map(dplyr::summarize_all, mean) %>% + dplyr::bind_rows() + + + list( + cluster_names = unique(clusts), + centroids = centroids, + n_members = unname(as.integer(table(clusts))), + n_outliers = n_outliers, + orig_labels = NULL, + cluster_assignments = clusts + ) +} + +#' @export +extract_fit_summary.Mclust <- function(object, ...) { + clusts <- extract_cluster_assignment(object, ...)$.cluster + n_clust <- dplyr::n_distinct(clusts) + training_data <- attr(object, "training_data") + + overall_centroid <- colMeans(training_data) + + by_clust <- training_data %>% + tibble::as_tibble() %>% + dplyr::mutate( + .cluster = clusts + ) %>% + dplyr::filter(.cluster != "Outlier") %>% + dplyr::group_by(.cluster) %>% + tidyr::nest() + + centroids <- by_clust$data %>% + map(dplyr::summarize_all, mean) %>% + dplyr::bind_rows() + + + list( + cluster_names = unique(clusts), + centroids = centroids, + n_members = unname(as.integer(table(clusts))), + orig_labels = NULL, + cluster_assignments = clusts + ) +} diff --git a/R/gm_clust.R b/R/gm_clust.R index 9c65910..3b645e0 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -17,6 +17,7 @@ #' to use for fitting. The engine for this model is `"mclust"`. #' @param num_clusters Positive integer, number of clusters in model (required). #' +#' @importFrom mclust mclustBIC #' #' @details #' diff --git a/R/predict_helpers.R b/R/predict_helpers.R index a991112..23dd272 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -177,7 +177,7 @@ make_predictions_w_outliers <- function(x, prefix, n_clusters) { .gm_clust_predict_mclust <- function(object, new_data, prefix = "Cluster_") { clusters <- predict(object, newdata = new_data)$classification - n_clusters <- length(clusters %>% unique()) + n_clusters <- attr(object, "num_clusters") make_predictions(clusters, prefix, n_clusters) } diff --git a/man/dbscan_helper.Rd b/man/dbscan_helper.Rd index 9bdeef1..7a557ac 100644 --- a/man/dbscan_helper.Rd +++ b/man/dbscan_helper.Rd @@ -4,7 +4,7 @@ \alias{dbscan_helper} \title{dbscan fit helper function} \usage{ -dbscan_helper(x, ...) +dbscan_helper(object, ...) } \arguments{ \item{x}{matrix or data frame} diff --git a/vignettes/articles/db_clust.Rmd b/vignettes/articles/db_clust.Rmd index 256a43d..405d198 100644 --- a/vignettes/articles/db_clust.Rmd +++ b/vignettes/articles/db_clust.Rmd @@ -10,27 +10,37 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + message = FALSE, + warning = FALSE ) ``` ## Setup + ```{r} library(workflows) library(parsnip) ``` -```{r} +Load libraries: + +```{r setup} library(tidyclust) library(tidyverse) library(tidymodels) -set.seed(838383) ``` +```{r setup_secret, echo = FALSE} +library(ggforce) +set.seed(822) +``` + Load and clean a dataset: + ```{r} data("penguins", package = "modeldata") @@ -38,7 +48,6 @@ penguins <- penguins %>% select(bill_length_mm, bill_depth_mm) %>% drop_na() - # shuffle rows penguins <- penguins %>% sample_n(nrow(penguins)) @@ -46,156 +55,11 @@ penguins <- penguins %>% At the end of this vignette, you will find a brief overview of the DBSCAN algorithm. -## A brief introduction to density-based clustering - -Density-Based Spatial Clustering of Applications with Noise (DBSCAN) is a method of unsupervised learning that groups observations into clusters based on their density in multidimensional space. Unlike methods such as k-means, DBSCAN does not require specifying the number of clusters beforehand and can identify clusters of arbitrary shapes. Additionally, it can classify points that do not belong to any cluster as noise, allowing for greater flexibility in handling real-world data. - -In DBSCAN, observations are considered as locations in multidimensional space. The algorithm works by defining a cluster as a dense region of connected points. During the fitting process, points are classified as core points, border points, or noise based on their proximity to other points (**radius**) and a density threshold (**minpts**). - -```{r, include = FALSE} -penguins_std <- penguins %>% - mutate(bill_length_std = scale(bill_length_mm)[,1], - bill_depth_std = scale(bill_depth_mm)[,1]) %>% - select(bill_length_std, bill_depth_std) -``` - - -```{r, echo = FALSE} - -# penguins_std %>% - # ggplot() + - # geom_point(aes(x = bill_length_std, y = bill_depth_std)) + - # theme_minimal() + - # coord_fixed() - -``` - -1. For each observation in the data, determine whether each point is a core point. A core points is defined as an observation which has more than the specified **minpts** points (including the point itself) within the specified **radius** around the point. - - -```{r, include = FALSE} -library(dbscan) -eps <- 0.35 -minpts <- 10 -dbscan_fit <- dbscan(penguins_std, eps = eps, minPts = minpts) - -``` - -```{r, echo = FALSE} -library(ggforce) -penguins_std %>% - ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std)) + - theme_minimal() + - geom_circle(tibble(x = c(-0.79162259), y = c(1.79706436), radius = rep(eps,1)), - mapping = aes(x0 = x, y0 = y, r = eps), - color = "gray", linewidth = 0.8) + - geom_point(tibble(x = c(-0.79162259), y = c(1.79706436)), mapping = aes(x = x, y = y, color = c("1"))) + - coord_fixed() + - theme(legend.position = "none") + - scale_color_manual(values = c("red")) -``` - - -```{r, echo = FALSE} -penguins_new <- penguins_std -penguins_new$cluster <- factor(dbscan_fit$cluster) -penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = minpts)) == 1, "Yes", "No"), levels = c("Yes", "No")) - -penguins_new %>% - ggplot(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + - geom_point() + - theme_minimal() + - coord_fixed() + - labs(color = "Is a core point?") + - scale_color_manual(values = c("red", "black")) + - theme(legend.position = "none") -``` - -2. For each core point, assign it to a cluster as well as all the points within the specified **radius** of the point. - -```{r, echo = FALSE, include = FALSE} -penguins_new %>% - ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + - theme_minimal() + - geom_circle(tibble(x = c(-1.10300165), y = c(0.73366185), radius = rep(eps, 1)), - mapping = aes(x0 = x, y0 = y, r = eps), - color = "gray", linewidth = 0.8) + - geom_point(tibble(x = c(-1.10300165), y = c(0.73366185)), mapping = aes(x = x, y = y, color = c("1"))) + - coord_fixed() + - theme(legend.position = "none") + - scale_color_manual(values = c("red", "black", "#619CFF")) -``` - - - -```{r, echo = FALSE} -penguins_new %>% - mutate(cp = if_else(sqrt((bill_length_std - -1.10300165)^2 + (bill_depth_std - 0.73366185)^2) <= eps, "1", cp)) %>% - ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + - theme_minimal() + - geom_circle(tibble(x = c(-1.10300165), y = c(0.73366185), radius = rep(eps, 1)), - mapping = aes(x0 = x, y0 = y, r = eps), - color = "gray", linewidth = 0.8) + - geom_point(tibble(x = c(-1.10300165), y = c(0.73366185)), mapping = aes(x = x, y = y, color = c("1"))) + - coord_fixed() + - theme(legend.position = "none") + - scale_color_manual(values = c("#619CFF", "black", "red")) -``` - -3. For all the points added to the cluster, check if a point added is a core point. If a point is a core point recursively add all other points wihtin that core point's **radius** to the current cluster. - -```{r, echo = FALSE} -penguins_new %>% - mutate(cluster_temp = if_else(cluster == 1, "temp", cp)) %>% - ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster_temp)) + - theme_minimal() + - geom_circle(tibble(x = c(-1.25), y = c(-0.32), radius = rep(eps, 1)), - mapping = aes(x0 = x, y0 = y, r = eps), - color = "gray", linewidth = 0.8) + - geom_point(tibble(x = c(-1.25), y = c(-0.32)), mapping = aes(x = x, y = y, color = c("1"))) + - coord_fixed() + - theme(legend.position = "none") + - scale_color_manual(values = c("#619CFF", "black", "#619CFF", "red")) -``` - -4. Repeat until all core points have been assigned clusters - -```{r, echo = FALSE} -penguins_new %>% - mutate(cluster_temp = case_when(cluster == 1 ~ "temp", - sqrt((bill_length_std - 1.2)^2 + (bill_depth_std - 1.05)^2) <= eps ~ "1", - TRUE ~ cp)) %>% - ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster_temp)) + - theme_minimal() + - geom_circle(tibble(x = c(1.2), y = c(1.05), radius = rep(eps, 1)), - mapping = aes(x0 = x, y0 = y, r = eps), - color = "gray", linewidth = 0.8) + - geom_point(tibble(x = c(1.2), y = c(1.05)), mapping = aes(x = x, y = y, color = c("1")), size = 1.8) + - coord_fixed() + - theme(legend.position = "none") + - scale_color_manual(values = c("#00BA38", "black", "#619CFF", "red")) -``` - -5. Points not assigned to a cluster are considered outliers by the algorithm. - -```{r, echo = FALSE} -penguins_new %>% - ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster)) + - theme_minimal() + - coord_fixed() + - scale_color_manual(values = c("black", "#619CFF", "#F8766D", "#00BA38", "#C77CFF")) + - theme(legend.position = "none") -``` +## `db_clust` specification in {`tidyclust`} -## db clust specification in {`tidyclust`} +To specify a DBSCAN model in `tidyclust`, simply set the values for `radius` and `min_pts`: ```{r} db_clust_spec <- db_clust(radius = 0.35, minpts = 10) @@ -203,13 +67,21 @@ db_clust_spec <- db_clust(radius = 0.35, minpts = 10) db_clust_spec ``` -There is currently one engine: `dbscan::dbscan` (default) +There is currently one engine: `dbscan::dbscan` (default) ## Fitting db_clust models -We fit the model to data in the usual way: +After specifying the model specification, we fit the model to data in the usual way: + +Note that I have standardized bill length and bill depth since DBSCAN uses euclidean distance to fit clusters and these variables are on different scales. ```{r} + +penguins_std <- penguins %>% + mutate(bill_length_std = scale(bill_length_mm)[,1], + bill_depth_std = scale(bill_depth_mm)[,1]) %>% + select(bill_length_std, bill_depth_std) + db_clust_fit <- db_clust_spec %>% fit( ~ bill_length_std + bill_depth_std, data = penguins_std @@ -221,60 +93,36 @@ db_clust_fit %>% We can also extract the standard `tidyclust` summary list: - ```{r} -# no extract fit summary method for db_clust object yet +db_clust_summary <- db_clust_fit %>% extract_fit_summary() -# db_clust_summary <- db_clust_fit %>% extract_fit_summary() +db_clust_summary %>% str() -# db_clust_summary %>% str() ``` -```{r} -db_clust_fit %>% extract_cluster_assignment() -``` +## Cluster assignments and centers -```{r} -penguins_new %>% - mutate(cluster2 = (db_clust_fit %>% extract_cluster_assignment())$.cluster) %>% - ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster2)) -``` +The cluster assignments for the training data can be accessed using the `extract_cluster_assignment()` function. +Note that the DBSCAN algorithm allows for some points to not be assigned clusters. These points are labeled as outliers. ```{r} -#| include: false -penguins_new %>% - mutate(cluster2 = (db_clust_fit %>% extract_cluster_assignment())$.cluster) %>% - ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster2)) + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = "green", size = 2), data = penguins_new %>% .[144,]) + - theme_minimal() + - coord_fixed() + - scale_color_manual(values = c("#619CFF", "#F8766D", "#00BA38", "black", "green")) + - theme(legend.position = "none") +db_clust_fit %>% extract_cluster_assignment() ``` +### Centroids -If you have not yet read the `k_means` vignette, we recommend reading that first; -functions that are used in this vignette are explained in more detail there. +While the centroids produced by a db_clust fit may not be of primary interest, they can still be accessed via the `extract_fit_summary()` object. +```{r} +db_clust_summary$centroids +``` ## Prediction - - -Since $DBSCAN$ algorithm ultimately assigns training observations to the -clusters based on proximity to core points, it is natural to "predict" that test -observations belong to a cluster if they are within $radius$ distance to a core point. - -The `predict()` function behaves as expected, producing cluster assignment -predictions on new data based on distance to the core points from the fitted model. - - -*Need to make sure it predicts cluster of CLOSEST core point* +Since $DBSCAN$ algorithm ultimately assigns training observations to the clusters based on proximity to core points, it is natural to "predict" that test observations belong to a cluster if they are within `radius` distance to a core point. To reconcile points being within the radius of two core points that belong to different clusters, the `predict()` function assigns new observations to the cluster of the closest core point. If a point is not within the `radius` of any core points, it is predicted to be an outlier. ```{r} @@ -287,144 +135,87 @@ db_clust_fit %>% predict(new_penguin) ``` -```{r, include=FALSE} -# set.seed(80) - -dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) -is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) -pred_data <- penguins_std[is_core,] - -pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) -``` - - -```{r} -dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) -is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) -pred_data <- penguins_std[is_core,] - -pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) - -pred[144] -``` - - +## A brief introduction to density-based clustering -```{r, include = FALSE} - +Density-Based Spatial Clustering of Applications with Noise (DBSCAN) is a method of unsupervised learning that groups observations into clusters based on their density in multidimensional space. Unlike methods such as k-means, DBSCAN does not require specifying the number of clusters beforehand and can identify clusters of arbitrary shapes. Additionally, it can classify points that do not belong to any cluster as outliers, allowing for greater flexibility in handling real-world data. -dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) -is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) -pred_data <- penguins_std[is_core,] +In DBSCAN, observations are considered as locations in multidimensional space. The algorithm works by defining a cluster as a dense region of connected points. During the fitting process, points are classified as core points, border points, or noise based on their proximity to other points (**radius**) and a density threshold (**min_pts**). -pred <- dbscan:::.predict_frNN(newdata = penguins_std, data = pred_data, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) +The fitting process can be described as follows: -test <- db_clust_fit %>% - predict(penguins_std) %>% - mutate(.fit_cluster = (db_clust_fit %>% extract_cluster_assignment())$.cluster, - .bc = pred, - .bc = case_when(.bc == 0 ~ "Outlier", - TRUE ~ paste0("Cluster_", .bc))) +```{r, echo = FALSE, include = FALSE} +penguins_std %>% +ggplot() + +geom_point(aes(x = bill_length_std, y = bill_depth_std)) + +theme_minimal() + +coord_fixed() -which(test$.fit_cluster != test$.bc) ``` +1. For each observation in the data, determine whether each point is a core point. A core point is defined as an observation which has more than the specified **minpts** points (including the point itself) within the specified **radius** around the point. -```{r} -dbscan_adj <- dbscan(penguins_std, eps = eps, minPts = minpts) -is_core <- is.corepoint(penguins_std, eps = eps, minPts = minpts) -core_points <- penguins_std[is_core,] -non_core_points <- penguins_std[!is_core,] +```{r, include = FALSE} +library(dbscan) +eps <- 0.35 +minpts <- 10 +dbscan_fit <- dbscan(penguins_std, eps = eps, minPts = minpts) -non_core_point_fits <- dbscan:::.predict_frNN(newdata = non_core_points, data = core_points, dbscan_adj$cluster[is_core], eps = dbscan_adj$eps) -core_point_fits <- dbscan_adj$cluster[is_core] ``` +```{r, echo = FALSE} +par(mfrow=c(1,2)) -```{r} -penguins_temp <- penguins_std -ncps <- data.frame(non_core_point_fits) -cps <- data.frame(core_point_fits) - -core_point_fits <- dbscan_adj$cluster[is_core] - -penguins_std$is_core <- as.character(as.numeric(is_core)) - -penguins_std$id <- ave(penguins_std$is_core, penguins_std$is_core, FUN = seq_along) -ncps$id <- 1:nrow(ncps) -ncps$is_core <- "0" -cps$id <- 1:nrow(cps) -cps$is_core <- "1" - -penguins_temp <- merge(x = penguins_temp, y = ncps, by = c("id", "is_core"), all.x = TRUE) -penguins_temp <- merge(x = penguins_temp, y = cps, by = c("id", "is_core"), all.x = TRUE) - -penguins_temp$cluster <- ifelse(!is.na(penguins_temp$non_core_point_fits), penguins_temp$non_core_point_fits, penguins_temp$core_point_fits) +penguins_std %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std)) + + theme_minimal() + + geom_circle(tibble(x = c(-0.79162259), y = c(0.2), radius = rep(eps,1)), + mapping = aes(x0 = x, y0 = y, r = eps), + color = "gray", linewidth = 0.8) + + geom_point(tibble(x = c(-0.79162259), y = c(0.2)), mapping = aes(x = x, y = y, color = c("1"))) + + coord_fixed() + + theme(legend.position = "none") + + scale_color_manual(values = c("red")) +penguins_new <- penguins_std +penguins_new$cluster <- factor(dbscan_fit$cluster) +penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = minpts)) == 1, "Yes", "No"), levels = c("Yes", "No")) +penguins_new %>% + ggplot(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + + geom_point() + + theme_minimal() + + coord_fixed() + + scale_color_manual(values = c("red", "black")) + + theme(legend.position = "none") ``` +2. For each core point, assign it to a cluster as well as all other core points within the specified **radius** of the point. Do until all core points have been assigned to a cluster. -```{r} - - -dbscan_helper <- function(object, - ...) { - - is_core <- attr(object, "is_core") - print(length(is_core)) - training_data <- data.frame(attr(object, "training_data")) - cp <- training_data[is_core,] - non_cp <- training_data[!is_core,] - cp_clusters <- object$cluster[is_core] - eps <- attr(object, "radius") - - # get fit values according to closest core point - non_cp_clusters <- dbscan:::.predict_frNN(newdata = non_cp, data = cp, cp_clusters, eps = eps) - - # join back separated fits into proper order in training data - non_cp_clusters <- data.frame(non_cp_clusters) - cp_clusters <- data.frame(cp_clusters) - - # create vars to join back results in proper order - training_data$is_core <- ifelse(is_core, "cp", "non cp") - non_cp_clusters$is_core <- "non cp" - cp_clusters$is_core <- "cp" - - training_data$overall_order <- 1:nrow(training_data) - training_data$id <- ave(training_data$is_core, training_data$is_core, FUN = seq_along) - non_cp_clusters$id <- 1:nrow(non_cp_clusters) - cp_clusters$id <- 1:nrow(cp_clusters) - - training_data <- merge(x = training_data, y = non_cp_clusters, by = c("id", "is_core"), all.x = TRUE) - training_data <- merge(x = training_data, y = cp_clusters, by = c("id", "is_core"), all.x = TRUE) - - training_data$cluster <- ifelse(!is.na(training_data$non_cp_clusters), training_data$non_cp_clusters, training_data$cp_clusters) - - training_data$cluster[order(training_data$overall_order)] - -} - +```{r, echo = FALSE} +penguins_new %>% + mutate(cp_color = if_else(cp == "Yes", cluster, "0")) %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cp_color)) + + theme_minimal() + + coord_fixed() + + scale_color_manual(values = c("black", "#619CFF", "#F8766D", "#00BA38")) + + theme(legend.position = "none") ``` +3. For the remaining points not assigned to a cluster, check whether the point is within the radius of a core point. For points not in the radius of any core points, assign the point as an outlier. Otherwise, assign the point to the cluster of the closest core point. -```{r} -dbscan_helper(db_clust_fit$fit) -``` - -```{r} +```{r, echo = FALSE} penguins_new %>% - mutate(cluster2 = factor(dbscan_helper(db_clust_fit$fit))) %>% ggplot() + - geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster2)) - - -dbscan_helper(db_clust_fit$fit) + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster)) + + theme_minimal() + + coord_fixed() + + scale_color_manual(values = c("black", "#619CFF", "#F8766D", "#00BA38")) + + theme(legend.position = "none") ``` - - diff --git a/vignettes/articles/gm_clust.Rmd b/vignettes/articles/gm_clust.Rmd index bece292..5315dee 100644 --- a/vignettes/articles/gm_clust.Rmd +++ b/vignettes/articles/gm_clust.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + message = FALSE, + warning = FALSE ) ``` @@ -19,17 +21,21 @@ knitr::opts_chunk$set( ```{r} library(workflows) library(parsnip) -library(mclust) ``` +Load Libraries: + ```{r} library(tidyclust) library(tidyverse) library(tidymodels) -set.seed(838383) ``` +```{r setup_secret, echo = FALSE} +set.seed(822) +``` + Load and clean a dataset: ```{r} @@ -51,7 +57,9 @@ At the end of this vignette, you will find a brief overview of the GMM algorithm -## gm clust specification in {`tidyclust`} +## `gm_clust` specification in {`tidyclust`} + +To specify a GMM model in `tidyclust`, simply set the value for `num_clusters`: ```{r} gm_clust_spec <- gm_clust(num_clusters = 3) @@ -63,7 +71,7 @@ There is currently one engine: `mclust::Mclust` (default) ## Fitting gm_clust models -We fit the model to data in the usual way: +After specifying the model specification, we fit the model to data in the usual way: ```{r} gm_clust_fit <- gm_clust_spec %>% @@ -74,33 +82,46 @@ gm_clust_fit <- gm_clust_spec %>% gm_clust_fit %>% summary() ``` -We can also extract the standard `tidyclust` summary list: +We can also extract the standard `tidyclust` summary list: ```{r} -# gm_clust_summary <- gm_clust_fit %>% extract_fit_summary() +gm_clust_summary <- gm_clust_fit %>% extract_fit_summary() -# gm_clust_summary %>% str() +gm_clust_summary %>% str() ``` +## Cluster assignments and centers +The cluster assignments for the training data can be accessed using the `extract_cluster_assignment()` function. ```{r} gm_clust_fit %>% extract_cluster_assignment() +``` +**Should probably make some way to extract probabilities of belonging to each group** - +```{r} +gm_clust_fit$fit$z %>% head() ``` + + If you have not yet read the `k_means` vignette, we recommend reading that first; functions that are used in this vignette are explained in more detail there. +### Centroids + +The centroids for the fitted clusters can be accessed via `extract_centroids()`: + +```{r} +gm_clust_fit %>% extract_centroids() +``` + ## Prediction - - -write stuff here +For GMMs each cluster is modeled as a multivariate normal distribution. This makes prediction easy since we can calculate the probability that each point belongs to each of the fitted clusters. Therefore, it is natural for the `predict()` function to assign new observations to the cluster in which they have the highest probability of belonging to. ```{r} new_penguin <- tibble( @@ -116,7 +137,6 @@ gm_clust_fit %>% ## A brief introduction to density-based clustering - Gaussian Mixture Models (GMM) is a probabilistic unsupervised learning method that models data as a mixture of multiple Gaussian distributions. Unlike clustering methods such as k-means, GMM provides a soft clustering approach, where each observation has a probability of belonging to multiple clusters. This allows for more flexibility in capturing complex data distributions. In GMM, observations are assumed to be generated from a combination of Gaussian distributions, each with its own mean and covariance. The algorithm works by iteratively estimating the parameters of these distributions using the Expectation-Maximization (EM) algorithm. During the fitting process, observations are assigned to clusters based on their probability of belonging to each Gaussian component (**num_clusters**), making GMM effective for identifying overlapping or elliptical clusters in data. @@ -126,22 +146,108 @@ In GMM, observations are assumed to be generated from a combination of Gaussian ```{r} -penguins %>% - mutate(cluster = paste0("Cluster_", sample(c(1,2,3), size = nrow(penguins), replace = TRUE))) %>% - ggplot(aes(x = bill_length_mm, y = bill_depth_mm, color = cluster)) + - geom_point() + - stat_ellipse(level = .50, type = "norm", linetype = 1) + - stat_ellipse(level = .75, type = "norm", linetype = 1) + - stat_ellipse(level = .95, type = "norm", linetype = 1) + - theme_minimal() + - theme(legend.position = "none") - # scale_color_manual(values = c("red")) +#| include: false +plot_state <- function(obj) { + + data.grid <- expand.grid(bill_length_mm = seq(20, 80, length.out=200), bill_depth_mm = seq(10, 25, length.out=200)) + + mean1 <- obj$mean1 + mean2 <- obj$mean2 + mean3 <- obj$mean3 + + sigma1 <- obj$sigma1 + sigma2 <- obj$sigma2 + sigma3 <- obj$sigma3 + + q.samp1 <- cbind(data.grid, prob = mvtnorm::dmvnorm(data.grid, mean = mean1, sigma = sigma1)) + q.samp2 <- cbind(data.grid, prob = mvtnorm::dmvnorm(data.grid, mean = mean2, sigma = sigma2)) + q.samp3 <- cbind(data.grid, prob = mvtnorm::dmvnorm(data.grid, mean = mean3, sigma = sigma3)) + + penguins_temp <- penguins %>% + mutate(p1 = mvtnorm::dmvnorm(cbind(bill_length_mm, bill_depth_mm), mean = mean1, sigma = sigma1), + p2 = mvtnorm::dmvnorm(cbind(bill_length_mm, bill_depth_mm), mean = mean2, sigma = sigma2), + p3 = mvtnorm::dmvnorm(cbind(bill_length_mm, bill_depth_mm), mean = mean3, sigma = sigma3), + class = case_when(p1 > p2 & p1 > p3 ~ "1", + p2 > p3 ~ "2", + TRUE ~ "3")) + + ggplot() + + geom_point(aes(x = bill_length_mm, y = bill_depth_mm, color = class), data = penguins_temp) + + geom_contour(aes(x=bill_length_mm, y=bill_depth_mm, z=prob), data = q.samp1, color = "#F8766D", bins = 5) + + geom_contour(aes(x=bill_length_mm, y=bill_depth_mm, z=prob), data = q.samp2, color = "#00BA38", bins = 5) + + geom_contour(aes(x=bill_length_mm, y=bill_depth_mm, z=prob), data = q.samp3, color = "#619CFF", bins = 5) + + theme_minimal() + + scale_fill_manual() + + theme(legend.position = "none") + +} +``` + + +```{r} +#| include: false +param_init <- list( + mean1 = c(45,20), + mean2 = c(45, 17.5), + mean3 = c(45, 15), + sigma1 = matrix(c(15,0,0,0.4), nrow = 2, byrow = TRUE), + sigma2 = matrix(c(15,0,0,0.4), nrow = 2, byrow = TRUE), + sigma3 = matrix(c(15,0,0,0.4), nrow = 2, byrow = TRUE) +) + +param_iter1 <- list( + mean1 = c(45.73339, 19.27432), + mean2 = c(40.12257, 17.81372), + mean3 = c(47.44993, 14.93927), + sigma1 = matrix(c(37.408656, -1.623795, -1.623795, 1.079872), nrow = 2), + sigma2 = matrix(c(16.9103292, 0.3527712, 0.3527712, 0.8637195), nrow = 2), + sigma3 = matrix(c(8.093719, 1.797110, 1.797110, 0.874565), nrow = 2) +) + +param_iter2 <- list( + mean1 = c(48.15322, 18.25719), + mean2 = c(38.52801, 18.28852), + mean3 = c(47.28095, 14.84609), + sigma1 = matrix(c(17.177953, 1.247011, 1.247011, 1.643133), nrow = 2), + sigma2 = matrix(c(5.9677874, 0.9537252, 0.9537252, 1.4710272), nrow = 2), + sigma3 = matrix(c(7.584198, 1.613411, 1.613411, 0.766815), nrow = 2) +) + +param_conv <- list( + mean1 = c(49.17829, 18.46058), + mean2 = c(39.0444, 18.3100), + mean3 = c(47.69776, 14.98856), + sigma1 = matrix(c(7.626905, 2.329064, 2.329064, 1.346795), nrow = 2), + sigma2 = matrix(c(7.837458, 1.077226, 1.077226, 1.477878), nrow = 2), + sigma3 = matrix(c(10.3399995, 2.3100534, 2.3100534, 0.9769847), nrow = 2) +) + +``` + + +```{r} +#| echo: false +plot_state(param_init) +``` +```{r} +#| echo: false +plot_state(param_iter1) ``` +```{r} +#| echo: false +plot_state(param_iter2) +``` +```{r} +#| echo: false +plot_state(param_conv) +``` + ```{r} +#| include: false penguins %>% mutate(cluster = (gm_clust_fit %>% extract_cluster_assignment())$.cluster) %>% ggplot(aes(x = bill_length_mm, y = bill_depth_mm, color = cluster)) + @@ -156,16 +262,4 @@ penguins %>% -```{r} -gm_clust_engine <- gm_clust_fit %>% extract_fit_engine() -``` - - -```{r} -gm_clust_engine$parameters -``` - -```{r} -plot(gm_clust_engine) -``` From 1b109fe0d5774b65b670a9330c313fbab4b611a7 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 15 Mar 2025 10:52:10 -0700 Subject: [PATCH 09/44] updated db_clust to have outlier as last level of .cluster factor. also adjusted extract_cluster_summary to return NA vals for selected metrics for outlier cluster --- R/extract_cluster_assignment.R | 11 +++++++---- R/extract_fit_summary.R | 15 +++++++++++---- R/predict_helpers.R | 5 +++-- vignettes/articles/db_clust.Rmd | 9 ++++++--- vignettes/articles/gm_clust.Rmd | 5 +++++ 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/R/extract_cluster_assignment.R b/R/extract_cluster_assignment.R index e989190..79cd94b 100644 --- a/R/extract_cluster_assignment.R +++ b/R/extract_cluster_assignment.R @@ -189,10 +189,13 @@ cluster_assignment_tibble_w_outliers <- function(clusters, n_clusters, ..., prefix = "Cluster_") { - reorder_clusts <- order(union(unique(clusters), 0:(n_clusters-1))) - names <- paste0(prefix, 0:(n_clusters-1)) - res <- names[reorder_clusts][clusters+1] - res[res == paste0(prefix, "0")] <- "Outlier" + # move outlier from cluster 0 to cluster n_clusters + clusters <- ifelse(clusters == 0, n_clusters, clusters) + + reorder_clusts <- order(union(unique(clusters), seq_len(n_clusters))) + names <- paste0(prefix, seq_len(n_clusters)) + names[n_clusters] <- "Outlier" + res <- names[reorder_clusts][clusters] tibble::tibble(.cluster = factor(res)) } diff --git a/R/extract_fit_summary.R b/R/extract_fit_summary.R index 71f11d4..01333d2 100644 --- a/R/extract_fit_summary.R +++ b/R/extract_fit_summary.R @@ -183,8 +183,7 @@ extract_fit_summary.hclust <- function(object, ...) { #' @export extract_fit_summary.dbscan <- function(object, ...) { clusts <- extract_cluster_assignment(object, ...)$.cluster - n_clust <- dplyr::n_distinct(clusts)-1 - n_outliers <- length(clusts == "Outlier") + n_clust <- dplyr::n_distinct(clusts) training_data <- attr(object, "training_data") overall_centroid <- colMeans(training_data) @@ -194,7 +193,6 @@ extract_fit_summary.dbscan <- function(object, ...) { dplyr::mutate( .cluster = clusts ) %>% - dplyr::filter(.cluster != "Outlier") %>% dplyr::group_by(.cluster) %>% tidyr::nest() @@ -202,12 +200,21 @@ extract_fit_summary.dbscan <- function(object, ...) { map(dplyr::summarize_all, mean) %>% dplyr::bind_rows() + centroids[n_clust, ] <- NA + + sse_within_total_total <- map2_dbl( + by_clust$data, + seq_len(n_clust), + ~ sum(Rfast::dista(centroids[.y, ], .x)) + ) + list( cluster_names = unique(clusts), centroids = centroids, n_members = unname(as.integer(table(clusts))), - n_outliers = n_outliers, + sse_within_total_total = sse_within_total_total, + sse_total = sum(Rfast::dista(t(overall_centroid), training_data)), orig_labels = NULL, cluster_assignments = clusts ) diff --git a/R/predict_helpers.R b/R/predict_helpers.R index 23dd272..9494ea9 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -4,9 +4,10 @@ make_predictions <- function(x, prefix, n_clusters) { } make_predictions_w_outliers <- function(x, prefix, n_clusters) { - levels <- seq_len(n_clusters)-1 + x <- ifelse(x == 0, n_clusters, x) + levels <- seq_len(n_clusters) labels <- paste0(prefix, levels) - labels[labels == paste0(prefix, "0")] <- "Outlier" + labels[n_clusters] <- "Outlier" factor(x, levels = levels, labels = labels) } diff --git a/vignettes/articles/db_clust.Rmd b/vignettes/articles/db_clust.Rmd index 405d198..97894b0 100644 --- a/vignettes/articles/db_clust.Rmd +++ b/vignettes/articles/db_clust.Rmd @@ -89,6 +89,7 @@ db_clust_fit <- db_clust_spec %>% db_clust_fit %>% summary() + ``` We can also extract the standard `tidyclust` summary list: @@ -181,7 +182,8 @@ penguins_std %>% scale_color_manual(values = c("red")) penguins_new <- penguins_std -penguins_new$cluster <- factor(dbscan_fit$cluster) +penguins_new$cluster <- (db_clust_fit %>% extract_cluster_assignment())$.cluster +# factor(dbscan_fit$cluster) penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = minpts)) == 1, "Yes", "No"), levels = c("Yes", "No")) penguins_new %>% @@ -203,7 +205,7 @@ penguins_new %>% geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cp_color)) + theme_minimal() + coord_fixed() + - scale_color_manual(values = c("black", "#619CFF", "#F8766D", "#00BA38")) + + scale_color_manual(values = c("black", "#F8766D", "#00BA38", "#619CFF")) + theme(legend.position = "none") ``` @@ -216,6 +218,7 @@ penguins_new %>% geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster)) + theme_minimal() + coord_fixed() + - scale_color_manual(values = c("black", "#619CFF", "#F8766D", "#00BA38")) + + scale_color_manual(values = c("#F8766D", "#00BA38", "#619CFF", "black")) + theme(legend.position = "none") ``` + diff --git a/vignettes/articles/gm_clust.Rmd b/vignettes/articles/gm_clust.Rmd index 5315dee..d0dc4a2 100644 --- a/vignettes/articles/gm_clust.Rmd +++ b/vignettes/articles/gm_clust.Rmd @@ -262,4 +262,9 @@ penguins %>% +```{r} +gmm_engine <- gm_clust_fit %>% extract_fit_engine() + +mclust::plot.Mclust(gmm_engine) +``` From 47b8e69ba99050a765610abd3f5bf3cbd14783f0 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 22 Mar 2025 09:30:45 -0700 Subject: [PATCH 10/44] minpts -> min_points --- R/db_clust.R | 28 ++++++++++++++-------------- R/db_clust_data.R | 6 +++--- vignettes/articles/db_clust.Rmd | 10 +++++----- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index 0728d1e..3894dd1 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -16,7 +16,7 @@ #' @param engine A single character string specifying what computational engine #' to use for fitting. The engine for this model is `"dbscan"`. #' @param radius Positive integer, Radius used to determine core-points and cluster points together (required). -#' @param minpts Positive double, Minimum number of points needed to form a cluster (required) +#' @param min_points Positive double, Minimum number of points needed to form a cluster (required) #' #' #' @details @@ -40,10 +40,10 @@ db_clust <- function(mode = "partition", engine = "dbscan", radius = NULL, - minpts = NULL) { + min_points = NULL) { args <- list( radius = enquo(radius), - minpts = enquo(minpts) + min_points = enquo(min_points) ) new_cluster_spec( @@ -77,7 +77,7 @@ print.db_clust <- function(x, ...) { update.db_clust <- function(object, parameters = NULL, radius = NULL, - minpts = NULL, + min_points = NULL, fresh = FALSE, ...) { eng_args <- parsnip::update_engine_parameters( object$eng_args, @@ -89,7 +89,7 @@ update.db_clust <- function(object, } args <- list( radius = enquo(radius), - minpts = enquo(minpts), + min_points = enquo(min_points), ) args <- parsnip::update_main_parameters(args, parameters) @@ -126,7 +126,7 @@ update.db_clust <- function(object, check_args.db_clust <- function(object) { args <- lapply(object$args, rlang::eval_tidy) - if (all(is.numeric(args$minpts)) && any(args$minpts < 0)) { + if (all(is.numeric(args$min_points)) && any(args$min_points < 0)) { rlang::abort("The number of points in a cluster should be > 0.") } @@ -148,19 +148,19 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { #' Simple Wrapper around dbscan function #' #' This wrapper prepares the data into a distance matrix to send to -#' `dbscan::dbscan` and retains the parameters `radius` or `minpts` as an +#' `dbscan::dbscan` and retains the parameters `radius` or `min_points` as an #' attribute. #' #' @param x matrix or data frame #' @param radius Radius used to determine core-points and cluster points together -#' @param minpts Minimum number of points needed to form a cluster +#' @param min_points Minimum number of points needed to form a cluster #' #' @return dbscan object #' @keywords internal #' @export .db_clust_fit_dbscan <- function(x, eps = NULL, - minPts = NULL, + min_points = NULL, ...) { if (is.null(eps)) { rlang::abort( @@ -169,18 +169,18 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { ) } - if (is.null(minPts)) { + if (is.null(min_points)) { rlang::abort( - "Please specify `minpts` to be able to fit specification.", + "Please specify `min_points` to be able to fit specification.", call = call("fit") ) } - res <- dbscan::dbscan(x, eps = eps, minPts = minPts) + res <- dbscan::dbscan(x, eps = eps, min_points = min_points) attr(res, "radius") <- eps - attr(res, "minpts") <- minPts + attr(res, "min_points") <- min_points attr(res, "training_data") <- x - is_core <- dbscan::is.corepoint(x, eps = eps, minPts = minPts) + is_core <- dbscan::is.corepoint(x, eps = eps, min_points = min_points) attr(res, "is_core") <- is_core res diff --git a/R/db_clust_data.R b/R/db_clust_data.R index 1330f5b..eede5aa 100644 --- a/R/db_clust_data.R +++ b/R/db_clust_data.R @@ -50,16 +50,16 @@ make_db_clust <- function() { eng = "dbscan", exposed = "radius", original = "eps", - func = list(pkg = "dials", fun = "raidus"), + func = list(pkg = "dials", fun = "radius"), has_submodel = TRUE ) modelenv::set_model_arg( model = "db_clust", eng = "dbscan", - exposed = "minpts", + exposed = "min_points", original = "minPts", - func = list(pkg = "dials", fun = "minpts"), + func = list(pkg = "dials", fun = "min_points"), has_submodel = TRUE ) diff --git a/vignettes/articles/db_clust.Rmd b/vignettes/articles/db_clust.Rmd index 97894b0..aceee24 100644 --- a/vignettes/articles/db_clust.Rmd +++ b/vignettes/articles/db_clust.Rmd @@ -62,7 +62,7 @@ At the end of this vignette, you will find a brief overview of the DBSCAN algori To specify a DBSCAN model in `tidyclust`, simply set the values for `radius` and `min_pts`: ```{r} -db_clust_spec <- db_clust(radius = 0.35, minpts = 10) +db_clust_spec <- db_clust(radius = 0.35, min_points = 10) db_clust_spec ``` @@ -155,14 +155,14 @@ coord_fixed() ``` -1. For each observation in the data, determine whether each point is a core point. A core point is defined as an observation which has more than the specified **minpts** points (including the point itself) within the specified **radius** around the point. +1. For each observation in the data, determine whether each point is a core point. A core point is defined as an observation which has more than the specified **min_points** points (including the point itself) within the specified **radius** around the point. ```{r, include = FALSE} library(dbscan) eps <- 0.35 -minpts <- 10 -dbscan_fit <- dbscan(penguins_std, eps = eps, minPts = minpts) +min_points <- 10 +dbscan_fit <- dbscan(penguins_std, eps = eps, min_points = min_points) ``` @@ -184,7 +184,7 @@ penguins_std %>% penguins_new <- penguins_std penguins_new$cluster <- (db_clust_fit %>% extract_cluster_assignment())$.cluster # factor(dbscan_fit$cluster) -penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = minpts)) == 1, "Yes", "No"), levels = c("Yes", "No")) +penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, min_points = min_points)) == 1, "Yes", "No"), levels = c("Yes", "No")) penguins_new %>% ggplot(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + From 54130bf08022075db9db2fc05d3bf391a5d43738 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 22 Mar 2025 09:39:32 -0700 Subject: [PATCH 11/44] fixed bugs in transition from minpts to min_points --- R/db_clust.R | 10 +++++----- vignettes/articles/db_clust.Rmd | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index 3894dd1..07666d6 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -160,7 +160,7 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { #' @export .db_clust_fit_dbscan <- function(x, eps = NULL, - min_points = NULL, + minPts = NULL, ...) { if (is.null(eps)) { rlang::abort( @@ -169,18 +169,18 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { ) } - if (is.null(min_points)) { + if (is.null(minPts)) { rlang::abort( "Please specify `min_points` to be able to fit specification.", call = call("fit") ) } - res <- dbscan::dbscan(x, eps = eps, min_points = min_points) + res <- dbscan::dbscan(x, eps = eps, minPts = minPts) attr(res, "radius") <- eps - attr(res, "min_points") <- min_points + attr(res, "min_points") <- minPts attr(res, "training_data") <- x - is_core <- dbscan::is.corepoint(x, eps = eps, min_points = min_points) + is_core <- dbscan::is.corepoint(x, eps = eps, minPts = minPts) attr(res, "is_core") <- is_core res diff --git a/vignettes/articles/db_clust.Rmd b/vignettes/articles/db_clust.Rmd index aceee24..14a0cc2 100644 --- a/vignettes/articles/db_clust.Rmd +++ b/vignettes/articles/db_clust.Rmd @@ -141,7 +141,7 @@ db_clust_fit %>% Density-Based Spatial Clustering of Applications with Noise (DBSCAN) is a method of unsupervised learning that groups observations into clusters based on their density in multidimensional space. Unlike methods such as k-means, DBSCAN does not require specifying the number of clusters beforehand and can identify clusters of arbitrary shapes. Additionally, it can classify points that do not belong to any cluster as outliers, allowing for greater flexibility in handling real-world data. -In DBSCAN, observations are considered as locations in multidimensional space. The algorithm works by defining a cluster as a dense region of connected points. During the fitting process, points are classified as core points, border points, or noise based on their proximity to other points (**radius**) and a density threshold (**min_pts**). +In DBSCAN, observations are considered as locations in multidimensional space. The algorithm works by defining a cluster as a dense region of connected points. During the fitting process, points are classified as core points, border points, or noise based on their proximity to other points (**radius**) and a density threshold (**min_points**). The fitting process can be described as follows: @@ -162,7 +162,7 @@ coord_fixed() library(dbscan) eps <- 0.35 min_points <- 10 -dbscan_fit <- dbscan(penguins_std, eps = eps, min_points = min_points) +dbscan_fit <- dbscan(penguins_std, eps = eps, minPts = min_points) ``` @@ -184,7 +184,7 @@ penguins_std %>% penguins_new <- penguins_std penguins_new$cluster <- (db_clust_fit %>% extract_cluster_assignment())$.cluster # factor(dbscan_fit$cluster) -penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, min_points = min_points)) == 1, "Yes", "No"), levels = c("Yes", "No")) +penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = min_points)) == 1, "Yes", "No"), levels = c("Yes", "No")) penguins_new %>% ggplot(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + From 5b7e9d18e5a71050ad79491da746fbb76fdb4ebb Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 22 Mar 2025 09:40:58 -0700 Subject: [PATCH 12/44] min_ponits documentation update --- man/db_clust.Rd | 9 +++++++-- man/dot-db_clust_fit_dbscan.Rd | 4 ++-- man/tidyclust_update.Rd | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/man/db_clust.Rd b/man/db_clust.Rd index c352b9c..9c2a764 100644 --- a/man/db_clust.Rd +++ b/man/db_clust.Rd @@ -4,7 +4,12 @@ \alias{db_clust} \title{Density-Based Spatial Clustering of Applications with Noise (DBSCAN)} \usage{ -db_clust(mode = "partition", engine = "dbscan", radius = NULL, minpts = NULL) +db_clust( + mode = "partition", + engine = "dbscan", + radius = NULL, + min_points = NULL +) } \arguments{ \item{mode}{A single character string for the type of model. The only @@ -15,7 +20,7 @@ to use for fitting. The engine for this model is \code{"dbscan"}.} \item{radius}{Positive integer, Radius used to determine core-points and cluster points together (required).} -\item{minpts}{Positive double, Minimum number of points needed to form a cluster (required)} +\item{min_points}{Positive double, Minimum number of points needed to form a cluster (required)} } \value{ A \code{db_clust} cluster specification. diff --git a/man/dot-db_clust_fit_dbscan.Rd b/man/dot-db_clust_fit_dbscan.Rd index 4c2f6d9..d6012ca 100644 --- a/man/dot-db_clust_fit_dbscan.Rd +++ b/man/dot-db_clust_fit_dbscan.Rd @@ -11,14 +11,14 @@ \item{radius}{Radius used to determine core-points and cluster points together} -\item{minpts}{Minimum number of points needed to form a cluster} +\item{min_points}{Minimum number of points needed to form a cluster} } \value{ dbscan object } \description{ This wrapper prepares the data into a distance matrix to send to -\code{dbscan::dbscan} and retains the parameters \code{radius} or \code{minpts} as an +\code{dbscan::dbscan} and retains the parameters \code{radius} or \code{min_points} as an attribute. } \keyword{internal} diff --git a/man/tidyclust_update.Rd b/man/tidyclust_update.Rd index 2b6c906..673bdd6 100644 --- a/man/tidyclust_update.Rd +++ b/man/tidyclust_update.Rd @@ -13,7 +13,7 @@ object, parameters = NULL, radius = NULL, - minpts = NULL, + min_points = NULL, fresh = FALSE, ... ) From 034b9955516c1c7a1da3c07c9ed7723eb46cdc6c Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 29 Mar 2025 11:10:24 -0700 Subject: [PATCH 13/44] add tunable for db_clust --- R/tunable.R | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/R/tunable.R b/R/tunable.R index da49bd9..cdd7790 100644 --- a/R/tunable.R +++ b/R/tunable.R @@ -67,6 +67,8 @@ tunable.k_means <- function(x, ...) { res } + + stats_k_means_engine_args <- tibble::tibble( name = c( @@ -79,3 +81,29 @@ stats_k_means_engine_args <- component = "k_means", component_id = "engine" ) + + +# #' @export +# tunable.dbscan <- function(x, ...) { +# res <- NextMethod() +# if (x$engine == "dbscan") { +# res <- add_engine_parameters(res, stats_k_means_engine_args) +# } +# res +# } +# +# dbscan_db_clust_engine_args <- +# tibble::tibble( +# name = c( +# "", +# "core_points" +# ), +# call_info = list( +# list(pkg = "dials", fun = "radius"), +# list(pkg = "dials", fun = "core_points"), +# ), +# source = "cluster_spec", +# component = "db_scan", +# component_id = "engine" +# ) + From 0797be979d0c479e61606e6933d2df78380ed417 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Sat, 29 Mar 2025 11:10:39 -0700 Subject: [PATCH 14/44] add tunable for dbscan --- R/tunable.R | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/R/tunable.R b/R/tunable.R index cdd7790..d3ba7d0 100644 --- a/R/tunable.R +++ b/R/tunable.R @@ -83,27 +83,27 @@ stats_k_means_engine_args <- ) -# #' @export -# tunable.dbscan <- function(x, ...) { -# res <- NextMethod() -# if (x$engine == "dbscan") { -# res <- add_engine_parameters(res, stats_k_means_engine_args) -# } -# res -# } -# -# dbscan_db_clust_engine_args <- -# tibble::tibble( -# name = c( -# "", -# "core_points" -# ), -# call_info = list( -# list(pkg = "dials", fun = "radius"), -# list(pkg = "dials", fun = "core_points"), -# ), -# source = "cluster_spec", -# component = "db_scan", -# component_id = "engine" -# ) +#' @export +tunable.db_clust <- function(x, ...) { + res <- NextMethod() + if (x$engine == "dbscan") { + res <- add_engine_parameters(res, dbscan_db_clust_engine_args) + } + res +} + +dbscan_db_clust_engine_args <- + tibble::tibble( + name = c( + "eps", + "minPts" + ), + call_info = list( + list(pkg = "dials", fun = "radius"), + list(pkg = "dials", fun = "min_points"), + ), + source = "cluster_spec", + component = "dbscan", + component_id = "engine" + ) From 9238147d40a1345f963cacf4d21e75e4f5322891 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Thu, 3 Apr 2025 12:23:28 -0700 Subject: [PATCH 15/44] finalize cluster assignment tibble helper --- R/db_clust.R | 6 +++--- R/db_clust_data.R | 2 +- R/extract_cluster_assignment.R | 12 ++++++------ R/tunable.R | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index 07666d6..37ada77 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -15,8 +15,8 @@ #' possible value for this model is "partition". #' @param engine A single character string specifying what computational engine #' to use for fitting. The engine for this model is `"dbscan"`. -#' @param radius Positive integer, Radius used to determine core-points and cluster points together (required). -#' @param min_points Positive double, Minimum number of points needed to form a cluster (required) +#' @param radius Positive double, Radius drawn around points to determine core-points and cluster assignments (required) +#' @param min_points Positive integer, Minimum number of points required to form a core-point (required) #' #' #' @details @@ -89,7 +89,7 @@ update.db_clust <- function(object, } args <- list( radius = enquo(radius), - min_points = enquo(min_points), + min_points = enquo(min_points) ) args <- parsnip::update_main_parameters(args, parameters) diff --git a/R/db_clust_data.R b/R/db_clust_data.R index eede5aa..9b6e0be 100644 --- a/R/db_clust_data.R +++ b/R/db_clust_data.R @@ -27,7 +27,7 @@ make_db_clust <- function() { mode = "partition", value = list( interface = "matrix", - protect = c("data"), + protect = c("x", "eps", "minPts"), func = c(pkg = "tidyclust", fun = ".db_clust_fit_dbscan"), defaults = list() ) diff --git a/R/extract_cluster_assignment.R b/R/extract_cluster_assignment.R index 79cd94b..94480d4 100644 --- a/R/extract_cluster_assignment.R +++ b/R/extract_cluster_assignment.R @@ -189,13 +189,13 @@ cluster_assignment_tibble_w_outliers <- function(clusters, n_clusters, ..., prefix = "Cluster_") { - # move outlier from cluster 0 to cluster n_clusters - clusters <- ifelse(clusters == 0, n_clusters, clusters) - reorder_clusts <- order(union(unique(clusters), seq_len(n_clusters))) - names <- paste0(prefix, seq_len(n_clusters)) - names[n_clusters] <- "Outlier" - res <- names[reorder_clusts][clusters] + no_outliers <- clusters[clusters != 0] + new_mappings <- c(0,order(union(unique(no_outliers), seq_len(n_clusters-1)))) + + names <- paste0(prefix, 0:(n_clusters)) + names[1] <- "Outlier" + res <- names[new_mappings[(clusters+1)]+1] tibble::tibble(.cluster = factor(res)) } diff --git a/R/tunable.R b/R/tunable.R index d3ba7d0..cc64103 100644 --- a/R/tunable.R +++ b/R/tunable.R @@ -100,7 +100,7 @@ dbscan_db_clust_engine_args <- ), call_info = list( list(pkg = "dials", fun = "radius"), - list(pkg = "dials", fun = "min_points"), + list(pkg = "dials", fun = "min_points") ), source = "cluster_spec", component = "dbscan", From d1b3d5537928b73daabb3b6f3acef9bae54b2300 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 8 Apr 2025 19:48:17 -0700 Subject: [PATCH 16/44] test-db_clust done --- R/extract_fit_summary.R | 3 +- R/predict_helpers.R | 15 ++- tests/testthat/_snaps/db_clust.md | 104 +++++++++++++++ tests/testthat/test-db_clust.R | 184 ++++++++++++++++++++++++++ tests/testthat/test-gm_clust.R | 207 ++++++++++++++++++++++++++++++ 5 files changed, 508 insertions(+), 5 deletions(-) create mode 100644 tests/testthat/_snaps/db_clust.md create mode 100644 tests/testthat/test-db_clust.R create mode 100644 tests/testthat/test-gm_clust.R diff --git a/R/extract_fit_summary.R b/R/extract_fit_summary.R index 01333d2..555eaf9 100644 --- a/R/extract_fit_summary.R +++ b/R/extract_fit_summary.R @@ -200,7 +200,8 @@ extract_fit_summary.dbscan <- function(object, ...) { map(dplyr::summarize_all, mean) %>% dplyr::bind_rows() - centroids[n_clust, ] <- NA + outlier_idx <- which(unique(clusts) == "Outlier") + centroids[outlier_idx, ] <- rep(NA, ncol(centroids)) sse_within_total_total <- map2_dbl( by_clust$data, diff --git a/R/predict_helpers.R b/R/predict_helpers.R index 9494ea9..8162a2d 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -4,13 +4,20 @@ make_predictions <- function(x, prefix, n_clusters) { } make_predictions_w_outliers <- function(x, prefix, n_clusters) { - x <- ifelse(x == 0, n_clusters, x) - levels <- seq_len(n_clusters) - labels <- paste0(prefix, levels) - labels[n_clusters] <- "Outlier" + + if (sum(x == 0) > 0) { + levels <- 0:(n_clusters-1) + labels <- paste0(prefix, levels) + labels[1] <- "Outlier" + + } else { + levels <- 1:(n_clusters) + labels <- paste0(prefix, levels) + } factor(x, levels = levels, labels = labels) } + .k_means_predict_stats <- function(object, new_data, prefix = "Cluster_") { res <- object$centers res <- flexclust::dist2(res, new_data) diff --git a/tests/testthat/_snaps/db_clust.md b/tests/testthat/_snaps/db_clust.md new file mode 100644 index 0000000..40d8e03 --- /dev/null +++ b/tests/testthat/_snaps/db_clust.md @@ -0,0 +1,104 @@ +# bad input + + Code + db_clust(mode = "bogus") + Condition + Error in `modelenv::check_spec_mode_engine_val()`: + ! 'bogus' is not a known mode for model `db_clust()`. + +--- + + Code + bt <- db_clust(radius = -1) %>% set_engine("dbscan") + fit(bt, mpg ~ ., mtcars) + Condition + Error in `check_args()`: + ! The radius used to create a cluster should be > 0. + +--- + + Code + bt <- db_clust(min_points = -1) %>% set_engine("dbscan") + fit(bt, mpg ~ ., mtcars) + Condition + Error in `check_args()`: + ! The number of points in a cluster should be > 0. + +--- + + Code + translate_tidyclust(db_clust(), engine = NULL) + Condition + Error in `translate_tidyclust.default()`: + ! Please set an engine. + +--- + + Code + translate_tidyclust(db_clust(formula = ~x)) + Condition + Error in `db_clust()`: + ! unused argument (formula = ~x) + +# printing + + Code + db_clust() + Output + DBSCAN Clustering Specification (partition) + + Computational engine: dbscan + + +--- + + Code + db_clust(radius = 20, min_points = 3) + Output + DBSCAN Clustering Specification (partition) + + Main Arguments: + radius = 20 + min_points = 3 + + Computational engine: dbscan + + +# updating + + Code + db_clust(radius = 20, min_points = 5) %>% update(radius = tune()) + Output + DBSCAN Clustering Specification (partition) + + Main Arguments: + radius = tune() + min_points = 5 + + Computational engine: dbscan + + +# errors if `radius` and `min_points` aren't specified + + Code + db_clust() %>% set_engine("dbscan") %>% fit(~., data = mtcars) + Condition + Error in `fit()`: + ! Please specify `radius` to be able to fit specification. + +# errors if `radius` isn't specified + + Code + db_clust(min_points = 10) %>% set_engine("dbscan") %>% fit(~., data = mtcars) + Condition + Error in `fit()`: + ! Please specify `radius` to be able to fit specification. + +# errors if `min_points` isn't specified + + Code + db_clust(radius = 20) %>% set_engine("dbscan") %>% fit(~., data = mtcars) + Condition + Error in `fit()`: + ! Please specify `min_points` to be able to fit specification. + diff --git a/tests/testthat/test-db_clust.R b/tests/testthat/test-db_clust.R new file mode 100644 index 0000000..f4a3b50 --- /dev/null +++ b/tests/testthat/test-db_clust.R @@ -0,0 +1,184 @@ +test_that("primary arguments", { + basic <- db_clust(mode = "partition") + basic_dbscan <- translate_tidyclust(basic %>% set_engine("dbscan")) + expect_equal( + basic_dbscan$method$fit$args, + list( + x = rlang::expr(missing_arg()), + eps = rlang::expr(missing_arg()), + minPts = rlang::expr(missing_arg()) + ) + ) + + db <- db_clust(radius = 2, min_points = 4, mode = "partition") + db_dbscan <- translate_tidyclust(db %>% set_engine("dbscan")) + expect_equal( + db_dbscan$method$fit$args, + list( + x = rlang::expr(missing_arg()), + eps = rlang::expr(missing_arg()), + minPts = rlang::expr(missing_arg()), + eps = new_empty_quosure(2), + minPts = new_empty_quosure(4) + ) + ) +}) + + +test_that("bad input", { + expect_snapshot(error = TRUE, db_clust(mode = "bogus")) + expect_snapshot(error = TRUE, { + bt <- db_clust(radius = -1) %>% set_engine("dbscan") + fit(bt, mpg ~ ., mtcars) + }) + expect_snapshot(error = TRUE, { + bt <- db_clust(min_points = -1) %>% set_engine("dbscan") + fit(bt, mpg ~ ., mtcars) + }) + expect_snapshot(error = TRUE, translate_tidyclust(db_clust(), engine = NULL)) + expect_snapshot(error = TRUE, translate_tidyclust(db_clust(formula = ~x))) +}) + +test_that("predictions", { + set.seed(1234) + db_clust_fit <- db_clust(radius = 60, min_points = 5) %>% + set_engine("dbscan") %>% + fit(~., mtcars) + + set.seed(1234) + ref_res <- dbscan::dbscan(mtcars, eps = 60, minPts = 5)$cluster + + ref_clusts <- ref_res[ref_res != 0] + ref_outliers <- which(ref_res == 0) + + relevel_preds <- function(x) { + factor(unname(x), unique(unname(x))) %>% as.numeric() + } + + expect_equal( + ref_clusts, + predict(db_clust_fit, mtcars)$.pred_cluster %>% .[. != "Outlier"] %>% as.numeric() - 1 + ) + + expect_equal( + relevel_preds(ref_clusts), + extract_cluster_assignment(db_clust_fit)$.cluster %>% .[. != "Outlier"] %>% as.numeric() + ) + + expect_equal( + ref_outliers, + which(predict(db_clust_fit, mtcars)$.pred_cluster == "Outlier") + ) +}) + + +test_that("extract_centroids work", { + set.seed(1234) + dbscan_fit <- db_clust(radius = 20, min_points = 3) %>% + set_engine("dbscan") %>% + fit(~., mtcars) + + set.seed(1234) + ref_res <- dbscan::dbscan(mtcars, eps = 20, minPts = 3) + + centers <- bind_cols(mtcars, .cluster = ref_res$cluster) %>% + dplyr::group_by(.cluster) %>% + dplyr::summarize_all(mean) %>% + dplyr::filter(.cluster != 0) %>% + dplyr::select(-.cluster) + + ref_centroids <- dplyr::bind_cols( + .cluster = c(1L, 2L, 4L, 5L, 3L), + centers + ) %>% + dplyr::arrange(.cluster) %>% + dplyr::select(-.cluster) + + expect_identical( + extract_centroids(dbscan_fit) %>% + dplyr::filter(.cluster != "Outlier") %>% + dplyr::select(-.cluster), + ref_centroids + ) +}) + +test_that("Right classes", { + expect_equal( + class(db_clust()), + c("db_clust", "cluster_spec", "unsupervised_spec") + ) +}) + +test_that("printing", { + expect_snapshot( + db_clust() + ) + expect_snapshot( + db_clust(radius = 20, min_points = 3) + ) +}) + +test_that("updating", { + expect_snapshot( + db_clust(radius = 20, min_points = 5) %>% + update(radius = tune()) + ) +}) + + +test_that("reordering is done correctly for stats k_means", { + set.seed(42) + + kmeans_fit <- k_means(num_clusters = 6) %>% + set_engine("stats") %>% + fit(~., data = mtcars) + + summ <- extract_fit_summary(kmeans_fit) + + expect_identical( + summ$n_members, + unname(as.integer(table(summ$cluster_assignments))) + ) +}) +# +# test_that("reordering is done correctly for ClusterR k_means", { +# set.seed(42) +# +# kmeans_fit <- k_means(num_clusters = 6) %>% +# set_engine("ClusterR") %>% +# fit(~., data = mtcars) +# +# summ <- extract_fit_summary(kmeans_fit) +# +# expect_identical( +# summ$n_members, +# unname(as.integer(table(summ$cluster_assignments))) +# ) +# }) + +test_that("errors if `radius` and `min_points` aren't specified", { + expect_snapshot( + error = TRUE, + db_clust() %>% + set_engine("dbscan") %>% + fit(~ ., data = mtcars) + ) +}) + +test_that("errors if `radius` isn't specified", { + expect_snapshot( + error = TRUE, + db_clust(min_points = 10) %>% + set_engine("dbscan") %>% + fit(~ ., data = mtcars) + ) +}) + +test_that("errors if `min_points` isn't specified", { + expect_snapshot( + error = TRUE, + db_clust(radius = 20) %>% + set_engine("dbscan") %>% + fit(~ ., data = mtcars) + ) +}) diff --git a/tests/testthat/test-gm_clust.R b/tests/testthat/test-gm_clust.R new file mode 100644 index 0000000..f855e8c --- /dev/null +++ b/tests/testthat/test-gm_clust.R @@ -0,0 +1,207 @@ +test_that("primary arguments", { + basic <- hier_clust(mode = "partition") + basic_stats <- translate_tidyclust(basic %>% set_engine("stats")) + expect_equal( + basic_stats$method$fit$args, + list( + data = rlang::expr(missing_arg()), + linkage_method = new_empty_quosure("complete") + ) + ) +}) + +test_that("engine arguments", { + stats_print <- hier_clust(mode = "partition") + expect_equal( + translate_tidyclust( + stats_print %>% + set_engine("stats", members = NULL) + )$method$fit$args, + list( + data = rlang::expr(missing_arg()), + linkage_method = new_empty_quosure("complete"), + members = new_empty_quosure(NULL) + ) + ) +}) + +test_that("bad input", { + expect_snapshot( + error = TRUE, + hier_clust(mode = "bogus") + ) + expect_snapshot( + error = TRUE, + { + bt <- hier_clust(linkage_method = "bogus") %>% set_engine("stats") + fit(bt, mpg ~ ., mtcars) + } + ) + expect_snapshot( + error = TRUE, + translate_tidyclust(hier_clust(), engine = NULL) + ) + expect_snapshot( + error = TRUE, + translate_tidyclust(hier_clust(formula = ~x)) + ) +}) + +test_that("predictions", { + set.seed(1234) + hclust_fit <- hier_clust(num_clusters = 4) %>% + set_engine("stats") %>% + fit(~., mtcars) + + set.seed(1234) + ref_res <- cutree(hclust(dist(mtcars)), k = 4) + + ref_predictions <- ref_res %>% unname() + + relevel_preds <- function(x) { + factor(unname(x), unique(unname(x))) %>% as.numeric() + } + + expect_equal( + relevel_preds(predict(hclust_fit, mtcars)$.pred_cluster), + predict(hclust_fit, mtcars)$.pred_cluster %>% as.numeric() + ) + + expect_equal( + relevel_preds(ref_predictions), + extract_cluster_assignment(hclust_fit)$.cluster %>% as.numeric() + ) +}) + +test_that("extract_cluster_assignment works if you don't set num_clusters", { + set.seed(1234) + hclust_fit <- hier_clust(num_clusters = 4) %>% + set_engine("stats") %>% + fit(~., mtcars) + + set.seed(1234) + hclust_fit_no_args <- hier_clust() %>% + set_engine("stats") %>% + fit(~., mtcars) + + expect_identical( + extract_cluster_assignment(hclust_fit, mtcars), + extract_cluster_assignment(hclust_fit_no_args, mtcars, num_clusters = 4) + ) +}) + +test_that("predict works if you don't set num_clusters", { + set.seed(1234) + hclust_fit <- hier_clust(num_clusters = 4) %>% + set_engine("stats") %>% + fit(~., mtcars) + + set.seed(1234) + hclust_fit_no_args <- hier_clust() %>% + set_engine("stats") %>% + fit(~., mtcars) + + expect_identical( + predict(hclust_fit, mtcars), + predict(hclust_fit_no_args, mtcars, num_clusters = 4) + ) +}) + +test_that("extract_centroids work", { + set.seed(1234) + hclust_fit <- hier_clust(num_clusters = 4) %>% + set_engine("stats") %>% + fit(~., mtcars) + + set.seed(1234) + ref_res <- cutree(hclust(dist(mtcars)), k = 4) + + ref_predictions <- ref_res %>% unname() + + expect_identical( + extract_centroids(hclust_fit) %>% + dplyr::mutate(.cluster = as.integer(.cluster)), + mtcars %>% + dplyr::group_by(.cluster = ref_predictions) %>% + dplyr::summarize(dplyr::across(dplyr::everything(), mean)) + ) +}) + +test_that("extract_centroids work if you don't set num_clusters", { + set.seed(1234) + hclust_fit <- hier_clust() %>% + set_engine("stats") %>% + fit(~., mtcars) + + set.seed(1234) + ref_res <- cutree(hclust(dist(mtcars)), k = 4) + + ref_predictions <- ref_res %>% unname() + + expect_identical( + extract_centroids(hclust_fit, num_clusters = 4) %>% + dplyr::mutate(.cluster = as.integer(.cluster)), + mtcars %>% + dplyr::group_by(.cluster = ref_predictions) %>% + dplyr::summarize(dplyr::across(dplyr::everything(), mean)) + ) +}) + +test_that("predictions with new data", { + set.seed(1234) + hclust_fit <- hier_clust(num_clusters = 4) %>% + set_engine("stats") %>% + fit(~., mtcars) + + set.seed(1234) + ref_res <- cutree(hclust(dist(mtcars)), k = 4) + + ref_predictions <- ref_res %>% unname() + + relevel_preds <- function(x) { + factor(unname(x), unique(unname(x))) %>% as.numeric() + } + + expect_equal( + relevel_preds(predict(hclust_fit, mtcars[1:10, ])$.pred_cluster), + predict(hclust_fit, mtcars[1:10, ])$.pred_cluster %>% as.numeric() + ) +}) + +test_that("Right classes", { + expect_equal( + class(hier_clust()), + c("hier_clust", "cluster_spec", "unsupervised_spec") + ) +}) + +test_that("printing", { + expect_snapshot( + hier_clust() + ) + expect_snapshot( + hier_clust(num_clusters = 10) + ) +}) + +test_that("updating", { + expect_snapshot( + hier_clust(num_clusters = 5) %>% + update(num_clusters = tune()) + ) +}) + +test_that("reordering is done correctly for stats hier_clust", { + set.seed(42) + + kmeans_fit <- hier_clust(num_clusters = 6) %>% + set_engine("stats") %>% + fit(~., data = mtcars) + + summ <- extract_fit_summary(kmeans_fit) + + expect_identical( + summ$n_members, + unname(as.integer(table(summ$cluster_assignments))) + ) +}) From 3d7f2d4da1ce4771ae9687d718382bdcf267d15d Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Wed, 9 Apr 2025 17:12:13 -0700 Subject: [PATCH 17/44] db_clust dbscan engine testing complete --- R/db_clust.R | 10 +++ R/extract_cluster_assignment.R | 18 ++++-- R/predict_helpers.R | 23 ++++--- tests/testthat/test-db_clust-dbscan.R | 93 +++++++++++++++++++++++++++ tests/testthat/test-db_clust.R | 2 +- 5 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 tests/testthat/test-db_clust-dbscan.R diff --git a/R/db_clust.R b/R/db_clust.R index 37ada77..a82edd2 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -204,6 +204,16 @@ dbscan_helper <- function(object, cp_clusters <- object$cluster[is_core] eps <- attr(object, "radius") + # if all points are core points then no border points / outliers to fit + if (sum(is_core) == nrow(training_data)) { + return(cp_clusters) + } + + # if there are no core points, all points are considered outliers + if (sum(is_core) == 0) { + return(rep(0, nrow(training_data))) + } + # get fit values according to closest core point non_cp_clusters <- dbscan:::.predict_frNN(newdata = non_cp, data = cp, cp_clusters, eps = eps) diff --git a/R/extract_cluster_assignment.R b/R/extract_cluster_assignment.R index 94480d4..74332a6 100644 --- a/R/extract_cluster_assignment.R +++ b/R/extract_cluster_assignment.R @@ -160,7 +160,8 @@ extract_cluster_assignment.hclust <- function(object, #' @export extract_cluster_assignment.dbscan <- function(object, ...) { clusters <- dbscan_helper(object) - n_clusters <- length(unique(clusters)) + + n_clusters <- length(unique(clusters[clusters != 0])) + 1 cluster_assignment_tibble_w_outliers(clusters, n_clusters, ...) } @@ -191,11 +192,14 @@ cluster_assignment_tibble_w_outliers <- function(clusters, prefix = "Cluster_") { no_outliers <- clusters[clusters != 0] - new_mappings <- c(0,order(union(unique(no_outliers), seq_len(n_clusters-1)))) - - names <- paste0(prefix, 0:(n_clusters)) - names[1] <- "Outlier" + if (n_clusters == 1) { + res <- rep("Outlier", length(clusters)) + } else { + new_mappings <- c(0,order(union(unique(no_outliers), seq_len(n_clusters-1)))) + names <- paste0(prefix, 0:(n_clusters-1)) + names[1] <- "Outlier" + res <- names[new_mappings[(clusters+1)]+1] + } - res <- names[new_mappings[(clusters+1)]+1] - tibble::tibble(.cluster = factor(res)) + tibble::tibble(.cluster = factor(res, levels = names)) } diff --git a/R/predict_helpers.R b/R/predict_helpers.R index 8162a2d..566cbaa 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -4,16 +4,9 @@ make_predictions <- function(x, prefix, n_clusters) { } make_predictions_w_outliers <- function(x, prefix, n_clusters) { - - if (sum(x == 0) > 0) { - levels <- 0:(n_clusters-1) - labels <- paste0(prefix, levels) - labels[1] <- "Outlier" - - } else { - levels <- 1:(n_clusters) - labels <- paste0(prefix, levels) - } + levels <- 0:(n_clusters-1) + labels <- paste0(prefix, levels) + labels[1] <- "Outlier" factor(x, levels = levels, labels = labels) } @@ -176,10 +169,16 @@ make_predictions_w_outliers <- function(x, prefix, n_clusters) { cp_clusters <- object$cluster[is_core] eps <- attr(object, "radius") - clusters <- dbscan:::.predict_frNN(newdata = new_data, data = cp, cp_clusters, eps = eps) - n_clusters <- length(unique(object$cluster)) + if (sum(is_core) == 0) { + clusters <- (rep(0, nrow(new_data))) + n_clusters <- 1 + } else { + clusters <- dbscan:::.predict_frNN(newdata = new_data, data = cp, cp_clusters, eps = eps) + n_clusters <- length(unique(object$cluster[object$cluster != 0])) + 1 + } make_predictions_w_outliers(clusters, prefix, n_clusters) + } .gm_clust_predict_mclust <- function(object, new_data, prefix = "Cluster_") { diff --git a/tests/testthat/test-db_clust-dbscan.R b/tests/testthat/test-db_clust-dbscan.R new file mode 100644 index 0000000..8ec0966 --- /dev/null +++ b/tests/testthat/test-db_clust-dbscan.R @@ -0,0 +1,93 @@ +test_that("fitting", { + set.seed(1234) + spec <- db_clust(radius = 10, min_points = 5) %>% + set_engine("dbscan") + + expect_no_error( + res <- fit(spec, ~., mtcars) + ) + + expect_no_error( + res <- fit_xy(spec, mtcars) + ) +}) + +test_that("predicting", { + set.seed(1234) + spec <- db_clust(radius = .42, min_points = 5) %>% + set_engine("dbscan") + + iris_temp <- iris %>% dplyr::select(-Species) + res <- fit(spec, ~., iris_temp) + + + preds <- predict(res, iris_temp[c(58 ,25, 75, 125), ]) + exp <- factor(c("Outlier", paste0("Cluster_", 1:3)), levels = c("Outlier", paste0("Cluster_", 1:3))) + + expect_identical( + preds, + tibble::tibble(.pred_cluster = exp) + ) +}) + + + +test_that("all levels are preserved with 1 row predictions", { + set.seed(1234) + spec <- db_clust(radius = 50, min_points = 5) %>% + set_engine("dbscan") + + res <- fit(spec, ~., mtcars) + + preds <- predict(res, mtcars[1, ]) + + expect_identical( + levels(preds$.pred_cluster), + c("Outlier", paste0("Cluster_", 1:2)) + ) +}) + +# test_that("extract_centroids() works", { +# set.seed(1234) +# spec <- db_clust(radius = .42, min_points = 5) %>% +# set_engine("dbscan") +# +# iris_temp <- iris %>% select(-Species) +# res <- fit(spec, ~., iris) +# +# centroids <- extract_centroids(res) +# +# expected <- vctrs::vec_cbind( +# tibble::tibble(.cluster = factor(paste0("Cluster_", 1:4))), +# tibble::as_tibble(res$fit$centers) +# ) +# +# expect_identical( +# centroids, +# expected +# ) +# }) + +test_that("extract_cluster_assignment() works", { + set.seed(1234) + spec <- db_clust(radius = .42, min_points = 5) %>% + set_engine("dbscan") + + iris_temp <- iris %>% dplyr::select(-Species) + res <- fit(spec, ~., iris_temp) + + clusters <- extract_cluster_assignment(res) + + expected <- vctrs::vec_cbind( + tibble::tibble(.cluster = factor(paste0("Cluster_", res$fit$cluster)) %>% + forcats::fct_recode("Outlier" = "Cluster_0") %>% + relevel(ref = "Outlier")) + + ) + + + expect_identical( + clusters, + expected + ) +}) diff --git a/tests/testthat/test-db_clust.R b/tests/testthat/test-db_clust.R index f4a3b50..a62c0a9 100644 --- a/tests/testthat/test-db_clust.R +++ b/tests/testthat/test-db_clust.R @@ -62,7 +62,7 @@ test_that("predictions", { expect_equal( relevel_preds(ref_clusts), - extract_cluster_assignment(db_clust_fit)$.cluster %>% .[. != "Outlier"] %>% as.numeric() + extract_cluster_assignment(db_clust_fit)$.cluster %>% .[. != "Outlier"] %>% as.numeric() - 1 ) expect_equal( From a4a3ea80bbe716334e1ca1e6d4f48aa292499bfa Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Wed, 9 Apr 2025 21:35:58 -0700 Subject: [PATCH 18/44] gm_clust true/false args for specifying different models --- R/db_clust.R | 7 ++- R/gm_clust.R | 142 ++++++++++++++++++++++++++++++++++++++++++++-- R/gm_clust_data.R | 47 ++++++++++++++- 3 files changed, 188 insertions(+), 8 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index a82edd2..098e2a4 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -188,11 +188,12 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { #' dbscan fit helper function #' -#' This function... +#' This function returns the cluster assignments for the training data +#' based on their distance to the CLOSEST core point in the data #' -#' @param x matrix or data frame +#' @param object db_clust object #' -#' @return dbscan object +#' @return numeric vector #' @keywords internal dbscan_helper <- function(object, ...) { diff --git a/R/gm_clust.R b/R/gm_clust.R index 3b645e0..ddb8eab 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -38,9 +38,20 @@ gm_clust <- function(mode = "partition", engine = "mclust", - num_clusters = NULL) { + num_clusters = NULL, + circular = FALSE, + zero_covariance = FALSE, + shared_orientation = FALSE, + shared_shape = FALSE, + shared_size = FALSE + ) { args <- list( - num_clusters = enquo(num_clusters) + num_clusters = enquo(num_clusters), + circular = enquo(circular), + zero_covariance = enquo(zero_covariance), + shared_orientation = enquo(shared_orientation), + shared_shape = enquo(shared_shape), + shared_size = enquo(shared_size) ) new_cluster_spec( @@ -74,6 +85,11 @@ print.gm_clust <- function(x, ...) { update.gm_clust <- function(object, parameters = NULL, num_clusters = NULL, + circular = NULL, + zero_covariance = NULL, + shared_orientation = NULL, + shared_shape = NULL, + shared_size = NULL, fresh = FALSE, ...) { eng_args <- parsnip::update_engine_parameters( object$eng_args, @@ -84,7 +100,12 @@ update.gm_clust <- function(object, parameters <- parsnip::check_final_param(parameters) } args <- list( - num_clusters = enquo(num_clusters) + num_clusters = enquo(num_clusters), + circular = enquo(circular), + zero_covariance = enquo(zero_covariance), + shared_orientation = enquo(shared_orientation), + shared_shape = enquo(shared_shape), + shared_size = enquo(shared_size) ) args <- parsnip::update_main_parameters(args, parameters) @@ -125,6 +146,26 @@ check_args.gm_clust <- function(object) { rlang::abort("The number of clusters should be > 0.") } + if (all(!is.logical(args$circular))) { + rlang::abort("The circular cluster shape argument should be TRUE or FALSE.") + } + + if (all(!is.logical(args$zero_covariance))) { + rlang::abort("The zero covariance argument should be TRUE or FALSE.") + } + + if (all(!is.logical(args$shared_orientation))) { + rlang::abort("The shared cluster orientation argument should be TRUE or FALSE.") + } + + if (all(!is.logical(args$shared_shape))) { + rlang::abort("The shared cluster shape argument should be TRUE or FALSE.") + } + + if (all(!is.logical(args$shared_size))) { + rlang::abort("The shared cluster size argument should be TRUE or FALSE.") + } + invisible(object) } @@ -150,6 +191,11 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { #' @export .gm_clust_fit_mclust <- function(x, G = NULL, + circular = NULL, + zero_covariance = NULL, + shared_orientation = NULL, + shared_shape = NULL, + shared_size = NULL, ...) { if (is.null(G)) { rlang::abort( @@ -157,9 +203,97 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { call = call("fit") ) } + if (is.null(circular)) { + rlang::abort( + "Please specify `circular` to be able to fit specification.", + call = call("fit") + ) + } + if (is.null(shared_size)) { + rlang::abort( + "Please specify `shared_size` to be able to fit specification.", + call = call("fit") + ) + } + if (!circular) { - res <- mclust::Mclust(x, G = G) + if (is.null(zero_covariance)) { + rlang::abort( + "Please specify `zero_covariance` to be able to fit specification.", + call = call("fit") + ) + } + + if (is.null(shared_shape)) { + rlang::abort( + "Please specify `shared_shape` to be able to fit specification.", + call = call("fit") + ) + } + + if (!zero_covariance) { + + if (is.null(shared_orientation)) { + rlang::abort( + "Please specify `shared_orientation` to be able to fit specification.", + call = call("fit") + ) + } + } + } + + model_name <- mclust_helper(circular, + zero_covariance, + shared_orientation, + shared_shape, + shared_size) + + + + res <- mclust::Mclust(x, G = G, modelNames = model_name) attr(res, "num_clusters") <- G + attr(res, "circular") <- circular + attr(res, "zero_covariance") <- zero_covariance + attr(res, "shared_orientation") <- shared_orientation + attr(res, "shared_shape") <- shared_shape + attr(res, "shared_size") <- shared_size attr(res, "training_data") <- x res } + + +#' mclust fit helper function +#' +#' This function returns the mclust model name based on the specified +#' TRUE/FALSE model arguments +#' +#' @param object gm_clust object +#' +#' @return string containing mclust model name +#' @keywords internal +mclust_helper <- function(circular, + zero_covariance, + shared_orientation, + shared_shape, + shared_size) { + model_name <- case_when( + circular & shared_size ~ "EII", + circular & !shared_size ~ "VII", + !circular & zero_covariance & shared_shape & shared_size ~ "EEI", + !circular & zero_covariance & !shared_shape & shared_size ~ "EVI", + !circular & zero_covariance & shared_shape & !shared_size ~ "VEI", + !circular & zero_covariance & !shared_shape & !shared_size ~ "VVI", + !circular & !zero_covariance & shared_orientation & shared_shape & shared_size ~ "EEE", + !circular & !zero_covariance & shared_orientation & !shared_shape & shared_size ~ "EVE", + !circular & !zero_covariance & shared_orientation & shared_shape & !shared_size ~ "VEE", + !circular & !zero_covariance & shared_orientation & !shared_shape & !shared_size ~ "VVE", + !circular & !zero_covariance & !shared_orientation & shared_shape & shared_size ~ "EEV", + !circular & !zero_covariance & !shared_orientation & shared_shape & !shared_size ~ "EVV", + !circular & !zero_covariance & !shared_orientation & !shared_shape & shared_size ~ "VEV", + !circular & !zero_covariance & !shared_orientation & !shared_shape & !shared_size ~ "VVV" + + + ) + +} + diff --git a/R/gm_clust_data.R b/R/gm_clust_data.R index 08efe84..b61ce6b 100644 --- a/R/gm_clust_data.R +++ b/R/gm_clust_data.R @@ -27,12 +27,13 @@ make_gm_clust <- function() { mode = "partition", value = list( interface = "matrix", - protect = c("data"), + protect = c("x", "G", "circular", "shared_orientation", "shared_shape", "shared_size"), func = c(pkg = "tidyclust", fun = ".gm_clust_fit_mclust"), defaults = list() ) ) + modelenv::set_encoding( model = "gm_clust", eng = "mclust", @@ -54,6 +55,50 @@ make_gm_clust <- function() { has_submodel = TRUE ) + modelenv::set_model_arg( + model = "gm_clust", + eng = "mclust", + exposed = "circular", + original = "circular", + func = list(pkg = "dials", fun = "circular"), + has_submodel = TRUE + ) + + modelenv::set_model_arg( + model = "gm_clust", + eng = "mclust", + exposed = "zero_covariance", + original = "zero_covariance", + func = list(pkg = "dials", fun = "zero_covariance"), + has_submodel = TRUE + ) + + modelenv::set_model_arg( + model = "gm_clust", + eng = "mclust", + exposed = "shared_orientation", + original = "shared_orientation", + func = list(pkg = "dials", fun = "shared_orientation"), + has_submodel = TRUE + ) + + modelenv::set_model_arg( + model = "gm_clust", + eng = "mclust", + exposed = "shared_shape", + original = "shared_shape", + func = list(pkg = "dials", fun = "shared_shape"), + has_submodel = TRUE + ) + + modelenv::set_model_arg( + model = "gm_clust", + eng = "mclust", + exposed = "shared_size", + original = "shared_size", + func = list(pkg = "dials", fun = "shared_size"), + has_submodel = TRUE + ) modelenv::set_pred( model = "gm_clust", From cfca66fe175ed90c422c2f6e6b8e4c364e30700b Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Thu, 17 Apr 2025 09:13:15 -0700 Subject: [PATCH 19/44] testing done --- NAMESPACE | 1 + R/gm_clust.R | 29 +-- R/gm_clust_data.R | 2 +- R/tunable.R | 33 ++++ man/db_clust.Rd | 4 +- man/dbscan_helper.Rd | 7 +- man/dot-gm_clust_fit_mclust.Rd | 11 +- man/gm_clust.Rd | 11 +- man/mclust_helper.Rd | 25 +++ man/tidyclust_update.Rd | 13 +- tests/testthat/_snaps/gm_clust.md | 133 +++++++++++++ tests/testthat/test-db_clust.R | 24 +-- tests/testthat/test-gm_clust-mclust.R | 85 +++++++++ tests/testthat/test-gm_clust.R | 265 +++++++++++++++++--------- 14 files changed, 512 insertions(+), 131 deletions(-) create mode 100644 man/mclust_helper.Rd create mode 100644 tests/testthat/_snaps/gm_clust.md create mode 100644 tests/testthat/test-gm_clust-mclust.R diff --git a/NAMESPACE b/NAMESPACE index 46eacc1..091b875 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -71,6 +71,7 @@ S3method(translate_tidyclust,gm_clust) S3method(translate_tidyclust,hier_clust) S3method(translate_tidyclust,k_means) S3method(tunable,cluster_spec) +S3method(tunable,db_clust) S3method(tunable,k_means) S3method(tune_args,cluster_spec) S3method(tune_cluster,cluster_spec) diff --git a/R/gm_clust.R b/R/gm_clust.R index ddb8eab..2089c0d 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -39,11 +39,11 @@ gm_clust <- function(mode = "partition", engine = "mclust", num_clusters = NULL, - circular = FALSE, - zero_covariance = FALSE, - shared_orientation = FALSE, - shared_shape = FALSE, - shared_size = FALSE + circular = TRUE, + shared_size = TRUE, + zero_covariance = TRUE, + shared_orientation = TRUE, + shared_shape = TRUE ) { args <- list( num_clusters = enquo(num_clusters), @@ -251,12 +251,21 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { res <- mclust::Mclust(x, G = G, modelNames = model_name) + + if (is.null(res)) { + rlang::abort( + "Model cannot be estimated. Please specify a model specification with less parameters by setting some model arguments to TRUE", + call = call("fit") + ) + } + attr(res, "num_clusters") <- G attr(res, "circular") <- circular attr(res, "zero_covariance") <- zero_covariance attr(res, "shared_orientation") <- shared_orientation attr(res, "shared_shape") <- shared_shape attr(res, "shared_size") <- shared_size + attr(res, "model_name") <- model_name attr(res, "training_data") <- x res } @@ -276,7 +285,7 @@ mclust_helper <- function(circular, shared_orientation, shared_shape, shared_size) { - model_name <- case_when( + model_name <- dplyr::case_when( circular & shared_size ~ "EII", circular & !shared_size ~ "VII", !circular & zero_covariance & shared_shape & shared_size ~ "EEI", @@ -288,12 +297,10 @@ mclust_helper <- function(circular, !circular & !zero_covariance & shared_orientation & shared_shape & !shared_size ~ "VEE", !circular & !zero_covariance & shared_orientation & !shared_shape & !shared_size ~ "VVE", !circular & !zero_covariance & !shared_orientation & shared_shape & shared_size ~ "EEV", - !circular & !zero_covariance & !shared_orientation & shared_shape & !shared_size ~ "EVV", - !circular & !zero_covariance & !shared_orientation & !shared_shape & shared_size ~ "VEV", + !circular & !zero_covariance & !shared_orientation & !shared_shape & shared_size ~ "EVV", + !circular & !zero_covariance & !shared_orientation & shared_shape & !shared_size ~ "VEV", !circular & !zero_covariance & !shared_orientation & !shared_shape & !shared_size ~ "VVV" - - ) - + model_name } diff --git a/R/gm_clust_data.R b/R/gm_clust_data.R index b61ce6b..d58e820 100644 --- a/R/gm_clust_data.R +++ b/R/gm_clust_data.R @@ -27,7 +27,7 @@ make_gm_clust <- function() { mode = "partition", value = list( interface = "matrix", - protect = c("x", "G", "circular", "shared_orientation", "shared_shape", "shared_size"), + protect = c("x", "G", "circular", "zero_covariance", "shared_orientation", "shared_shape", "shared_size"), func = c(pkg = "tidyclust", fun = ".gm_clust_fit_mclust"), defaults = list() ) diff --git a/R/tunable.R b/R/tunable.R index cc64103..9d86ca5 100644 --- a/R/tunable.R +++ b/R/tunable.R @@ -107,3 +107,36 @@ dbscan_db_clust_engine_args <- component_id = "engine" ) + +#' @export +tunable.gm_clust <- function(x, ...) { + res <- NextMethod() + if (x$engine == "mclust") { + res <- add_engine_parameters(res, mclust_gm_clust_engine_args) + } + res +} + +mclust_gm_clust_engine_args <- + tibble::tibble( + name = c( + "G", + "circular", + "zero_covariance", + "shared_orientation", + "shared_shape", + "shared_size" + ), + call_info = list( + list(pkg = "dials", fun = "num_clusters"), + list(pkg = "dials", fun = "circular"), + list(pkg = "dials", fun = "zero_covariance"), + list(pkg = "dials", fun = "shared_orientation"), + list(pkg = "dials", fun = "shared_shape"), + list(pkg = "dials", fun = "shared_size") + ), + source = "cluster_spec", + component = "mclust", + component_id = "engine" + ) + diff --git a/man/db_clust.Rd b/man/db_clust.Rd index 9c2a764..d085cfb 100644 --- a/man/db_clust.Rd +++ b/man/db_clust.Rd @@ -18,9 +18,9 @@ possible value for this model is "partition".} \item{engine}{A single character string specifying what computational engine to use for fitting. The engine for this model is \code{"dbscan"}.} -\item{radius}{Positive integer, Radius used to determine core-points and cluster points together (required).} +\item{radius}{Positive double, Radius drawn around points to determine core-points and cluster assignments (required)} -\item{min_points}{Positive double, Minimum number of points needed to form a cluster (required)} +\item{min_points}{Positive integer, Minimum number of points required to form a core-point (required)} } \value{ A \code{db_clust} cluster specification. diff --git a/man/dbscan_helper.Rd b/man/dbscan_helper.Rd index 7a557ac..d6dc43a 100644 --- a/man/dbscan_helper.Rd +++ b/man/dbscan_helper.Rd @@ -7,12 +7,13 @@ dbscan_helper(object, ...) } \arguments{ -\item{x}{matrix or data frame} +\item{object}{db_clust object} } \value{ -dbscan object +numeric vector } \description{ -This function... +This function returns the cluster assignments for the training data +based on their distance to the CLOSEST core point in the data } \keyword{internal} diff --git a/man/dot-gm_clust_fit_mclust.Rd b/man/dot-gm_clust_fit_mclust.Rd index aad9416..c8f252b 100644 --- a/man/dot-gm_clust_fit_mclust.Rd +++ b/man/dot-gm_clust_fit_mclust.Rd @@ -4,7 +4,16 @@ \alias{.gm_clust_fit_mclust} \title{Simple Wrapper around Mclust function} \usage{ -.gm_clust_fit_mclust(x, G = NULL, ...) +.gm_clust_fit_mclust( + x, + G = NULL, + circular = NULL, + zero_covariance = NULL, + shared_orientation = NULL, + shared_shape = NULL, + shared_size = NULL, + ... +) } \arguments{ \item{x}{matrix or data frame} diff --git a/man/gm_clust.Rd b/man/gm_clust.Rd index 9daf6ac..cc5d972 100644 --- a/man/gm_clust.Rd +++ b/man/gm_clust.Rd @@ -4,7 +4,16 @@ \alias{gm_clust} \title{Gaussian Mixture Models (GMM)} \usage{ -gm_clust(mode = "partition", engine = "mclust", num_clusters = NULL) +gm_clust( + mode = "partition", + engine = "mclust", + num_clusters = NULL, + circular = FALSE, + zero_covariance = FALSE, + shared_orientation = FALSE, + shared_shape = FALSE, + shared_size = FALSE +) } \arguments{ \item{mode}{A single character string for the type of model. The only diff --git a/man/mclust_helper.Rd b/man/mclust_helper.Rd new file mode 100644 index 0000000..d42adb1 --- /dev/null +++ b/man/mclust_helper.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gm_clust.R +\name{mclust_helper} +\alias{mclust_helper} +\title{mclust fit helper function} +\usage{ +mclust_helper( + circular, + zero_covariance, + shared_orientation, + shared_shape, + shared_size +) +} +\arguments{ +\item{object}{gm_clust object} +} +\value{ +string containing mclust model name +} +\description{ +This function returns the mclust model name based on the specified +TRUE/FALSE model arguments +} +\keyword{internal} diff --git a/man/tidyclust_update.Rd b/man/tidyclust_update.Rd index 673bdd6..e1cda51 100644 --- a/man/tidyclust_update.Rd +++ b/man/tidyclust_update.Rd @@ -18,7 +18,18 @@ ... ) -\method{update}{gm_clust}(object, parameters = NULL, num_clusters = NULL, fresh = FALSE, ...) +\method{update}{gm_clust}( + object, + parameters = NULL, + num_clusters = NULL, + circular = NULL, + zero_covariance = NULL, + shared_orientation = NULL, + shared_shape = NULL, + shared_size = NULL, + fresh = FALSE, + ... +) \method{update}{hier_clust}( object, diff --git a/tests/testthat/_snaps/gm_clust.md b/tests/testthat/_snaps/gm_clust.md new file mode 100644 index 0000000..5a89562 --- /dev/null +++ b/tests/testthat/_snaps/gm_clust.md @@ -0,0 +1,133 @@ +# bad input + + Code + gm_clust(mode = "bogus") + Condition + Error in `modelenv::check_spec_mode_engine_val()`: + ! 'bogus' is not a known mode for model `gm_clust()`. + +--- + + Code + bt <- gm_clust(circular = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + Condition + Error in `check_args()`: + ! The circular cluster shape argument should be TRUE or FALSE. + +--- + + Code + bt <- gm_clust(zero_covariance = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + Condition + Error in `check_args()`: + ! The zero covariance argument should be TRUE or FALSE. + +--- + + Code + bt <- gm_clust(shared_orientation = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + Condition + Error in `check_args()`: + ! The shared cluster orientation argument should be TRUE or FALSE. + +--- + + Code + bt <- gm_clust(shared_shape = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + Condition + Error in `check_args()`: + ! The shared cluster shape argument should be TRUE or FALSE. + +--- + + Code + bt <- gm_clust(shared_size = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + Condition + Error in `check_args()`: + ! The shared cluster size argument should be TRUE or FALSE. + +--- + + Code + bt <- gm_clust(num_clusters = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + Condition + Warning in `sort()`: + NAs introduced by coercion + Error in `if (G[1] == 1) ...`: + ! missing value where TRUE/FALSE needed + +--- + + Code + translate_tidyclust(gm_clust(), engine = NULL) + Condition + Error in `translate_tidyclust.default()`: + ! Please set an engine. + +--- + + Code + translate_tidyclust(gm_clust(formula = ~x)) + Condition + Error in `gm_clust()`: + ! unused argument (formula = ~x) + +# printing + + Code + gm_clust() + Output + GMM Clustering Specification (partition) + + Main Arguments: + circular = TRUE + zero_covariance = TRUE + shared_orientation = TRUE + shared_shape = TRUE + shared_size = TRUE + + Computational engine: mclust + + +--- + + Code + gm_clust(num_clusters = 3) + Output + GMM Clustering Specification (partition) + + Main Arguments: + num_clusters = 3 + circular = TRUE + zero_covariance = TRUE + shared_orientation = TRUE + shared_shape = TRUE + shared_size = TRUE + + Computational engine: mclust + + +# updating + + Code + gm_clust(num_clusters = 5) %>% update(num_clusters = tune()) + Output + GMM Clustering Specification (partition) + + Main Arguments: + num_clusters = tune() + circular = TRUE + zero_covariance = TRUE + shared_orientation = TRUE + shared_shape = TRUE + shared_size = TRUE + + Computational engine: mclust + + diff --git a/tests/testthat/test-db_clust.R b/tests/testthat/test-db_clust.R index a62c0a9..d7e0317 100644 --- a/tests/testthat/test-db_clust.R +++ b/tests/testthat/test-db_clust.R @@ -126,35 +126,21 @@ test_that("updating", { }) -test_that("reordering is done correctly for stats k_means", { +test_that("reordering is done correctly for dbscan db_clust", { set.seed(42) - kmeans_fit <- k_means(num_clusters = 6) %>% - set_engine("stats") %>% + dbscan_fit <- db_clust(radius = 20, min_points = 3) %>% + set_engine("dbscan") %>% fit(~., data = mtcars) - summ <- extract_fit_summary(kmeans_fit) + summ <- extract_fit_summary(dbscan_fit) expect_identical( summ$n_members, unname(as.integer(table(summ$cluster_assignments))) ) }) -# -# test_that("reordering is done correctly for ClusterR k_means", { -# set.seed(42) -# -# kmeans_fit <- k_means(num_clusters = 6) %>% -# set_engine("ClusterR") %>% -# fit(~., data = mtcars) -# -# summ <- extract_fit_summary(kmeans_fit) -# -# expect_identical( -# summ$n_members, -# unname(as.integer(table(summ$cluster_assignments))) -# ) -# }) + test_that("errors if `radius` and `min_points` aren't specified", { expect_snapshot( diff --git a/tests/testthat/test-gm_clust-mclust.R b/tests/testthat/test-gm_clust-mclust.R new file mode 100644 index 0000000..12e499d --- /dev/null +++ b/tests/testthat/test-gm_clust-mclust.R @@ -0,0 +1,85 @@ +test_that("fitting", { + set.seed(1234) + spec <- gm_clust(num_clusters = 3) %>% + set_engine("mclust") + + expect_no_error( + res <- fit(spec, ~., mtcars) + ) + + expect_no_error( + res <- fit_xy(spec, mtcars) + ) +}) + +test_that("predicting", { + set.seed(1234) + spec <- gm_clust(num_clusters = 3) %>% + set_engine("mclust") + + res <- fit(spec, ~., iris) + + preds <- predict(res, iris[c(25, 75, 125), ]) + + expect_identical( + preds, + tibble::tibble(.pred_cluster = factor(paste0("Cluster_", 1:3))) + ) +}) + +test_that("all levels are preserved with 1 row predictions", { + set.seed(1234) + spec <- gm_clust(num_clusters = 3) %>% + set_engine("mclust") + + res <- fit(spec, ~., mtcars) + + preds <- predict(res, mtcars[1, ]) + + expect_identical( + levels(preds$.pred_cluster), + paste0("Cluster_", 1:3) + ) +}) + +test_that("extract_centroids() works", { + set.seed(1234) + spec <- gm_clust(num_clusters = 3) %>% + set_engine("mclust") + + res <- fit(spec, ~., iris) + + centroids <- extract_centroids(res) + + expect_identical( + colnames(centroids), + c(".cluster", "Sepal.Length", "Sepal.Width", "Petal.Length", + "Petal.Width", "Speciesversicolor", "Speciesvirginica") + ) + + expect_identical( + centroids$.cluster, + factor(c("Cluster_1", "Cluster_2", "Cluster_3")) + ) +}) + +test_that("extract_cluster_assignment() works", { + set.seed(1234) + spec <- gm_clust(num_clusters = 3) %>% + set_engine("mclust") + + res <- fit(spec, ~., iris) + + clusters <- extract_cluster_assignment(res) + + res$fit$classification + + expected <- vctrs::vec_cbind( + tibble::tibble(.cluster = factor(paste0("Cluster_", res$fit$classification))) + ) + + expect_identical( + clusters, + expected + ) +}) diff --git a/tests/testthat/test-gm_clust.R b/tests/testthat/test-gm_clust.R index f855e8c..eea9a20 100644 --- a/tests/testthat/test-gm_clust.R +++ b/tests/testthat/test-gm_clust.R @@ -1,26 +1,49 @@ test_that("primary arguments", { - basic <- hier_clust(mode = "partition") - basic_stats <- translate_tidyclust(basic %>% set_engine("stats")) + basic <- gm_clust(mode = "partition") + basic_mclust <- translate_tidyclust(basic %>% set_engine("mclust")) expect_equal( - basic_stats$method$fit$args, + basic_mclust$method$fit$args, list( - data = rlang::expr(missing_arg()), - linkage_method = new_empty_quosure("complete") + x = rlang::expr(missing_arg()), + + G= rlang::expr(missing_arg()), + circular = rlang::expr(missing_arg()), + zero_covariance = rlang::expr(missing_arg()), + shared_orientation = rlang::expr(missing_arg()), + shared_shape = rlang::expr(missing_arg()), + shared_size = rlang::expr(missing_arg()), + + circular = new_empty_quosure(TRUE), + zero_covariance = new_empty_quosure(TRUE), + shared_orientation = new_empty_quosure(TRUE), + shared_shape = new_empty_quosure(TRUE), + shared_size = new_empty_quosure(TRUE) ) ) }) test_that("engine arguments", { - stats_print <- hier_clust(mode = "partition") + mclust_print <- gm_clust(mode = "partition") expect_equal( translate_tidyclust( - stats_print %>% - set_engine("stats", members = NULL) + mclust_print %>% + set_engine("mclust") )$method$fit$args, list( - data = rlang::expr(missing_arg()), - linkage_method = new_empty_quosure("complete"), - members = new_empty_quosure(NULL) + x = rlang::expr(missing_arg()), + + G = rlang::expr(missing_arg()), + circular = rlang::expr(missing_arg()), + zero_covariance = rlang::expr(missing_arg()), + shared_orientation = rlang::expr(missing_arg()), + shared_shape = rlang::expr(missing_arg()), + shared_size = rlang::expr(missing_arg()), + + circular = new_empty_quosure(TRUE), + zero_covariance = new_empty_quosure(TRUE), + shared_orientation = new_empty_quosure(TRUE), + shared_shape = new_empty_quosure(TRUE), + shared_size = new_empty_quosure(TRUE) ) ) }) @@ -28,33 +51,70 @@ test_that("engine arguments", { test_that("bad input", { expect_snapshot( error = TRUE, - hier_clust(mode = "bogus") + gm_clust(mode = "bogus") ) expect_snapshot( error = TRUE, { - bt <- hier_clust(linkage_method = "bogus") %>% set_engine("stats") + bt <- gm_clust(circular = "bogus") %>% set_engine("mclust") fit(bt, mpg ~ ., mtcars) } ) expect_snapshot( error = TRUE, - translate_tidyclust(hier_clust(), engine = NULL) + { + bt <- gm_clust(zero_covariance = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + } + ) + expect_snapshot( + error = TRUE, + { + bt <- gm_clust(shared_orientation = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + } + ) + expect_snapshot( + error = TRUE, + { + bt <- gm_clust(shared_shape = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + } + ) + expect_snapshot( + error = TRUE, + { + bt <- gm_clust(shared_size = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + } + ) + expect_snapshot( + error = TRUE, + { + bt <- gm_clust(num_clusters = "bogus") %>% set_engine("mclust") + fit(bt, mpg ~ ., mtcars) + } ) expect_snapshot( error = TRUE, - translate_tidyclust(hier_clust(formula = ~x)) + translate_tidyclust(gm_clust(), engine = NULL) + ) + expect_snapshot( + error = TRUE, + translate_tidyclust(gm_clust(formula = ~x)) ) }) test_that("predictions", { set.seed(1234) - hclust_fit <- hier_clust(num_clusters = 4) %>% - set_engine("stats") %>% + + mclust_fit <- gm_clust(num_clusters = 4) %>% + set_engine("mclust") %>% fit(~., mtcars) set.seed(1234) - ref_res <- cutree(hclust(dist(mtcars)), k = 4) + mclustBIC <- mclust::mclustBIC + ref_res <- mclust::Mclust(mtcars, G = 4, modelNames = "EII")$classification ref_predictions <- ref_res %>% unname() @@ -63,98 +123,48 @@ test_that("predictions", { } expect_equal( - relevel_preds(predict(hclust_fit, mtcars)$.pred_cluster), - predict(hclust_fit, mtcars)$.pred_cluster %>% as.numeric() + relevel_preds(predict(mclust_fit, mtcars)$.pred_cluster), + predict(mclust_fit, mtcars)$.pred_cluster %>% as.numeric() ) expect_equal( relevel_preds(ref_predictions), - extract_cluster_assignment(hclust_fit)$.cluster %>% as.numeric() + extract_cluster_assignment(mclust_fit)$.cluster %>% as.numeric() ) }) -test_that("extract_cluster_assignment works if you don't set num_clusters", { - set.seed(1234) - hclust_fit <- hier_clust(num_clusters = 4) %>% - set_engine("stats") %>% - fit(~., mtcars) - - set.seed(1234) - hclust_fit_no_args <- hier_clust() %>% - set_engine("stats") %>% - fit(~., mtcars) - - expect_identical( - extract_cluster_assignment(hclust_fit, mtcars), - extract_cluster_assignment(hclust_fit_no_args, mtcars, num_clusters = 4) - ) -}) - -test_that("predict works if you don't set num_clusters", { - set.seed(1234) - hclust_fit <- hier_clust(num_clusters = 4) %>% - set_engine("stats") %>% - fit(~., mtcars) - - set.seed(1234) - hclust_fit_no_args <- hier_clust() %>% - set_engine("stats") %>% - fit(~., mtcars) - - expect_identical( - predict(hclust_fit, mtcars), - predict(hclust_fit_no_args, mtcars, num_clusters = 4) - ) -}) test_that("extract_centroids work", { set.seed(1234) - hclust_fit <- hier_clust(num_clusters = 4) %>% - set_engine("stats") %>% + mclust_fit <- gm_clust(num_clusters = 4) %>% + set_engine("mclust") %>% fit(~., mtcars) set.seed(1234) - ref_res <- cutree(hclust(dist(mtcars)), k = 4) + mclustBIC <- mclust::mclustBIC + ref_res <- mclust::Mclust(mtcars, G = 4, modelNames = "EII")$classification ref_predictions <- ref_res %>% unname() expect_identical( - extract_centroids(hclust_fit) %>% - dplyr::mutate(.cluster = as.integer(.cluster)), + extract_centroids(mclust_fit) %>% + dplyr::mutate(.cluster = as.double(.cluster)), mtcars %>% dplyr::group_by(.cluster = ref_predictions) %>% dplyr::summarize(dplyr::across(dplyr::everything(), mean)) ) }) -test_that("extract_centroids work if you don't set num_clusters", { - set.seed(1234) - hclust_fit <- hier_clust() %>% - set_engine("stats") %>% - fit(~., mtcars) - - set.seed(1234) - ref_res <- cutree(hclust(dist(mtcars)), k = 4) - - ref_predictions <- ref_res %>% unname() - - expect_identical( - extract_centroids(hclust_fit, num_clusters = 4) %>% - dplyr::mutate(.cluster = as.integer(.cluster)), - mtcars %>% - dplyr::group_by(.cluster = ref_predictions) %>% - dplyr::summarize(dplyr::across(dplyr::everything(), mean)) - ) -}) test_that("predictions with new data", { set.seed(1234) - hclust_fit <- hier_clust(num_clusters = 4) %>% - set_engine("stats") %>% + mclust_fit <- gm_clust(num_clusters = 4) %>% + set_engine("mclust") %>% fit(~., mtcars) set.seed(1234) - ref_res <- cutree(hclust(dist(mtcars)), k = 4) + mclustBIC <- mclust::mclustBIC + ref_res <- mclust::Mclust(mtcars, G = 4, modelNames = "EII")$classification ref_predictions <- ref_res %>% unname() @@ -163,45 +173,116 @@ test_that("predictions with new data", { } expect_equal( - relevel_preds(predict(hclust_fit, mtcars[1:10, ])$.pred_cluster), - predict(hclust_fit, mtcars[1:10, ])$.pred_cluster %>% as.numeric() + relevel_preds(predict(mclust_fit, mtcars[1:10, ])$.pred_cluster), + predict(mclust_fit, mtcars[1:10, ])$.pred_cluster %>% as.numeric() ) }) test_that("Right classes", { expect_equal( - class(hier_clust()), - c("hier_clust", "cluster_spec", "unsupervised_spec") + class(gm_clust()), + c("gm_clust", "cluster_spec", "unsupervised_spec") ) }) test_that("printing", { expect_snapshot( - hier_clust() + gm_clust() ) expect_snapshot( - hier_clust(num_clusters = 10) + gm_clust(num_clusters = 3) ) }) test_that("updating", { expect_snapshot( - hier_clust(num_clusters = 5) %>% + gm_clust(num_clusters = 5) %>% update(num_clusters = tune()) ) }) -test_that("reordering is done correctly for stats hier_clust", { +test_that("reordering is done correctly for gm_clust", { set.seed(42) - kmeans_fit <- hier_clust(num_clusters = 6) %>% - set_engine("stats") %>% + gm_fit <- gm_clust(num_clusters = 6) %>% + set_engine("mclust") %>% fit(~., data = mtcars) - summ <- extract_fit_summary(kmeans_fit) + summ <- extract_fit_summary(gm_fit) expect_identical( summ$n_members, unname(as.integer(table(summ$cluster_assignments))) ) }) + +test_that("model errors when parameters cannot be estimated", { + set.seed(42) + + expect_error( + gm_clust(num_clusters = 10, circular=F,zero_covariance=F,shared_orientation=F,shared_shape=F,shared_size=F) %>% + set_engine("mclust") %>% + fit(~., data = mtcars) + ) + +}) + + +test_that("mappings to different model names are correct", { + expect_identical( + tidyclust:::mclust_helper(T, NA, NA, NA, T), + "EII" + ) + expect_identical( + tidyclust:::mclust_helper(T, NA, NA, NA, F), + "VII" + ) + expect_identical( + tidyclust:::mclust_helper(F, T, NA, T, T), + "EEI" + ) + expect_identical( + tidyclust:::mclust_helper(F, T, NA, F, T), + "EVI" + ) + expect_identical( + tidyclust:::mclust_helper(F, T, NA, T, F), + "VEI" + ) + expect_identical( + tidyclust:::mclust_helper(F, T, NA, F, F), + "VVI" + ) + expect_identical( + tidyclust:::mclust_helper(F, F, T, T, T), + "EEE" + ) + expect_identical( + tidyclust:::mclust_helper(F, F, T, F, T), + "EVE" + ) + expect_identical( + tidyclust:::mclust_helper(F, F, T, T, F), + "VEE" + ) + expect_identical( + tidyclust:::mclust_helper(F, F, T, F, F), + "VVE" + ) + expect_identical( + tidyclust:::mclust_helper(F, F, F, T, T), + "EEV" + ) + expect_identical( + tidyclust:::mclust_helper(F, F, F, F, T), + "EVV" + ) + expect_identical( + tidyclust:::mclust_helper(F, F, F, T, F), + "VEV" + ) + expect_identical( + tidyclust:::mclust_helper(F, F, F, F, F), + "VVV" + ) +}) From 0b563d8cd47e26c41c00d83f78e99ac94b275828 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Wed, 4 Jun 2025 12:45:19 -0700 Subject: [PATCH 20/44] updated documentation --- NAMESPACE | 1 + R/db_clust.R | 4 +- R/extract_fit_summary.R | 15 ++- R/gm_clust.R | 9 +- man/db_clust.Rd | 4 +- man/gm_clust.Rd | 24 ++-- man/rmd/db_clust_dbscan.Rmd | 58 +++++++++ man/rmd/gm_clust_mclust.Rmd | 57 +++++++++ tests/testthat/_snaps/k_means.new.md | 85 -------------- tests/testthat/test-gm_clust.R | 162 ++++++++++++++++++++++++++ vignettes/articles/db_clust.Rmd | 103 ++++++++++++---- vignettes/articles/gm_clust.Rmd | 100 ++++++++++------ vignettes/articles/gmm_models/eee.jpg | Bin 0 -> 50421 bytes vignettes/articles/gmm_models/eei.jpg | Bin 0 -> 46980 bytes vignettes/articles/gmm_models/eev.jpg | Bin 0 -> 50337 bytes vignettes/articles/gmm_models/eii.jpg | Bin 0 -> 45380 bytes vignettes/articles/gmm_models/eve.jpg | Bin 0 -> 51770 bytes vignettes/articles/gmm_models/evi.jpg | Bin 0 -> 46695 bytes vignettes/articles/gmm_models/evv.jpg | Bin 0 -> 50580 bytes vignettes/articles/gmm_models/vee.jpg | Bin 0 -> 46283 bytes vignettes/articles/gmm_models/vei.jpg | Bin 0 -> 46214 bytes vignettes/articles/gmm_models/vev.jpg | Bin 0 -> 43934 bytes vignettes/articles/gmm_models/vii.jpg | Bin 0 -> 44938 bytes vignettes/articles/gmm_models/vve.jpg | Bin 0 -> 48193 bytes vignettes/articles/gmm_models/vvi.jpg | Bin 0 -> 43963 bytes vignettes/articles/gmm_models/vvv.jpg | Bin 0 -> 46505 bytes 26 files changed, 461 insertions(+), 161 deletions(-) create mode 100644 man/rmd/db_clust_dbscan.Rmd create mode 100644 man/rmd/gm_clust_mclust.Rmd delete mode 100644 tests/testthat/_snaps/k_means.new.md create mode 100644 vignettes/articles/gmm_models/eee.jpg create mode 100644 vignettes/articles/gmm_models/eei.jpg create mode 100644 vignettes/articles/gmm_models/eev.jpg create mode 100644 vignettes/articles/gmm_models/eii.jpg create mode 100644 vignettes/articles/gmm_models/eve.jpg create mode 100644 vignettes/articles/gmm_models/evi.jpg create mode 100644 vignettes/articles/gmm_models/evv.jpg create mode 100644 vignettes/articles/gmm_models/vee.jpg create mode 100644 vignettes/articles/gmm_models/vei.jpg create mode 100644 vignettes/articles/gmm_models/vev.jpg create mode 100644 vignettes/articles/gmm_models/vii.jpg create mode 100644 vignettes/articles/gmm_models/vve.jpg create mode 100644 vignettes/articles/gmm_models/vvi.jpg create mode 100644 vignettes/articles/gmm_models/vvv.jpg diff --git a/NAMESPACE b/NAMESPACE index 091b875..5c8bac1 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -72,6 +72,7 @@ S3method(translate_tidyclust,hier_clust) S3method(translate_tidyclust,k_means) S3method(tunable,cluster_spec) S3method(tunable,db_clust) +S3method(tunable,gm_clust) S3method(tunable,k_means) S3method(tune_args,cluster_spec) S3method(tune_cluster,cluster_spec) diff --git a/R/db_clust.R b/R/db_clust.R index 098e2a4..85b9860 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -3,9 +3,9 @@ #' @description #' #' `db_clust` defines a model that fits clusters based on areas with observations -#' that are densely packed together +#' that are densely packed together using the DBSCAN algorithm #' -#' There are different ways to fit this model, and the method of estimation is +#' There are multiple implementations for this model, and the implementation is #' chosen by setting the model engine. The engine-specific pages for this model #' are listed below. #' diff --git a/R/extract_fit_summary.R b/R/extract_fit_summary.R index 555eaf9..c8e22c2 100644 --- a/R/extract_fit_summary.R +++ b/R/extract_fit_summary.R @@ -203,6 +203,10 @@ extract_fit_summary.dbscan <- function(object, ...) { outlier_idx <- which(unique(clusts) == "Outlier") centroids[outlier_idx, ] <- rep(NA, ncol(centroids)) + + # reorder centroids + centroids <- centroids[c(outlier_idx, setdiff(1:n_clust, outlier_idx)), ] + sse_within_total_total <- map2_dbl( by_clust$data, seq_len(n_clust), @@ -210,8 +214,9 @@ extract_fit_summary.dbscan <- function(object, ...) { ) + clust_names <- unique(clusts)[c(outlier_idx, setdiff(1:n_clust, outlier_idx))] list( - cluster_names = unique(clusts), + cluster_names = clust_names, centroids = centroids, n_members = unname(as.integer(table(clusts))), sse_within_total_total = sse_within_total_total, @@ -242,11 +247,19 @@ extract_fit_summary.Mclust <- function(object, ...) { map(dplyr::summarize_all, mean) %>% dplyr::bind_rows() + sse_within_total_total <- map2_dbl( + by_clust$data, + seq_len(n_clust), + ~ sum(Rfast::dista(centroids[.y, ], .x)) + ) + list( cluster_names = unique(clusts), centroids = centroids, n_members = unname(as.integer(table(clusts))), + sse_within_total_total = sse_within_total_total, + sse_total = sum(Rfast::dista(t(overall_centroid), training_data)), orig_labels = NULL, cluster_assignments = clusts ) diff --git a/R/gm_clust.R b/R/gm_clust.R index 2089c0d..1301ae9 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -3,9 +3,9 @@ #' @description #' #' `gm_clust` defines a model that fits clusters based on fitting a specified number of -#' multivariate normal distributions to the data. +#' multivariate Gaussian distributions (MVG) to the data. #' -#' There are different ways to fit this model, and the method of estimation is +#' There are multiple implementations for this model, and the implementation is #' chosen by setting the model engine. The engine-specific pages for this model #' are listed below. #' @@ -16,6 +16,11 @@ #' @param engine A single character string specifying what computational engine #' to use for fitting. The engine for this model is `"mclust"`. #' @param num_clusters Positive integer, number of clusters in model (required). +#' @param circular Boolean, whether or not to fit circular MVG distributions for each cluster +#' @param zero_covariance Boolean, whether or not to assign covariances of 0 for each MVG +#' @param shared_orientation Boolean, whether each cluster MVG should have the same orientation +#' @param shared_shape Boolean, whether each cluster MVG should have the same shape +#' @param shared_size Boolean, whether each cluster MVG should have the same size/volume #' #' @importFrom mclust mclustBIC #' diff --git a/man/db_clust.Rd b/man/db_clust.Rd index d085cfb..db44a06 100644 --- a/man/db_clust.Rd +++ b/man/db_clust.Rd @@ -27,9 +27,9 @@ A \code{db_clust} cluster specification. } \description{ \code{db_clust} defines a model that fits clusters based on areas with observations -that are densely packed together +that are densely packed together using the DBSCAN algorithm -There are different ways to fit this model, and the method of estimation is +There are multiple implementations for this model, and the implementation is chosen by setting the model engine. The engine-specific pages for this model are listed below. \itemize{ diff --git a/man/gm_clust.Rd b/man/gm_clust.Rd index cc5d972..385ada3 100644 --- a/man/gm_clust.Rd +++ b/man/gm_clust.Rd @@ -8,11 +8,11 @@ gm_clust( mode = "partition", engine = "mclust", num_clusters = NULL, - circular = FALSE, - zero_covariance = FALSE, - shared_orientation = FALSE, - shared_shape = FALSE, - shared_size = FALSE + circular = TRUE, + shared_size = TRUE, + zero_covariance = TRUE, + shared_orientation = TRUE, + shared_shape = TRUE ) } \arguments{ @@ -23,15 +23,25 @@ possible value for this model is "partition".} to use for fitting. The engine for this model is \code{"mclust"}.} \item{num_clusters}{Positive integer, number of clusters in model (required).} + +\item{circular}{Boolean, whether or not to fit circular MVG distributions for each cluster} + +\item{shared_size}{Boolean, whether each cluster MVG should have the same size/volume} + +\item{zero_covariance}{Boolean, whether or not to assign covariances of 0 for each MVG} + +\item{shared_orientation}{Boolean, whether each cluster MVG should have the same orientation} + +\item{shared_shape}{Boolean, whether each cluster MVG should have the same shape} } \value{ A \code{gm_clust} cluster specification. } \description{ \code{gm_clust} defines a model that fits clusters based on fitting a specified number of -multivariate normal distributions to the data. +multivariate Gaussian distributions (MVG) to the data. -There are different ways to fit this model, and the method of estimation is +There are multiple implementations for this model, and the implementation is chosen by setting the model engine. The engine-specific pages for this model are listed below. \itemize{ diff --git a/man/rmd/db_clust_dbscan.Rmd b/man/rmd/db_clust_dbscan.Rmd new file mode 100644 index 0000000..3934928 --- /dev/null +++ b/man/rmd/db_clust_dbscan.Rmd @@ -0,0 +1,58 @@ +```{r, child = "aaa.Rmd", include = FALSE} +``` + +`r descr_models("db_clust", "dbscan")` + +## Tuning Parameters + +```{r stats-param-info, echo = FALSE} +defaults <- + tibble::tibble(tidyclust = c("radius", "min_points"), + default = c("no default", "no_default")) + +param <- + db_clust() %>% + set_engine("dbscan") %>% + set_mode("partition") %>% + make_parameter_list(defaults) +``` + +This model has `r nrow(param)` tuning parameters: + +```{r dbscan-param-list, echo = FALSE, results = "asis"} +param$item +``` + +## Translation from tidyclust to the original package (partition) + +```{r stats-cls} +db_clust(radius = 0.5, min_points = 5)%>% + set_engine("dbscan") %>% + set_mode("partition") %>% + translate_tidyclust() +``` + +## Preprocessing requirements + +```{r child = "template-makes-dummies.Rmd"} +``` + +```{r child = "template-same-scale.Rmd"} +``` + + +## References + +- Ester, M., Kriegel, H.-P., Sander, J., & Xu, X. (1996). A Density-Based Algorithm for Discovering Clusters in Large Spatial Databases with Noise. + +- Hahsler, M., Piekenbrock, M., & Doran, D. (2019a). Dbscan : Fast Density-Based Clustering with r. Journal of Statistical Software, 91(1). https://doi.org/10.18637/jss.v091.i01 + +- Hahsler, M., Piekenbrock, M., & Doran, D. (2019b). dbscan: Fast density-based clustering +with R. Journal of Statistical Software, 91(1), 1–30. https://doi.org/10.18637/jss.v091. +i01 + +- Kriegel, H., Kröger, P., Sander, J., & Zimek, A. (2011). Density-based clustering. WIREs Data Mining and Knowledge Discovery, 1(3), 231–240. https://doi.org/10.1002/widm. 30 + +- Tran, T. N., Drab, K., & Daszykowski, M. (2013). Revised DBSCAN algorithm to cluster data with dense adjacent clusters. Chemometrics and Intelligent Laboratory Systems, 49 120, 92–96. https://doi.org/10.1016/j.chemolab.2012.11.006 + + diff --git a/man/rmd/gm_clust_mclust.Rmd b/man/rmd/gm_clust_mclust.Rmd new file mode 100644 index 0000000..0cef423 --- /dev/null +++ b/man/rmd/gm_clust_mclust.Rmd @@ -0,0 +1,57 @@ +```{r, child = "aaa.Rmd", include = FALSE} +``` + +`r descr_models("gm_clust", "mclust")` + +## Tuning Parameters + +```{r stats-param-info, echo = FALSE} +defaults <- + tibble::tibble(tidyclust = c("num_clusters", "circular", "zero_covariance", "shared_orientation", "shared_shape", "shared_size"), + default = c("no default", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE")) + +param <- + gm_clust() %>% + set_engine("mclust") %>% + set_mode("partition") %>% + make_parameter_list(defaults) +``` + +This model has `r nrow(param)` tuning parameters: + +```{r dbscan-param-list, echo = FALSE, results = "asis"} +param$item +``` + +## Translation from tidyclust to the original package (partition) + +```{r stats-cls} +gm_clust(num_clusters = 3, circular = FALSE, zero_covariance = FALSE) %>% + set_engine("mclust") %>% + set_mode("partition") %>% + translate_tidyclust() +``` + +## Preprocessing requirements + +Gaussian Mixture Models should be fit with only quantitative predictors and without any categorical predictors. No scaling is required since the variance-covariance matrices of the Gaussian distributions account for the unequal variances between predictors and their covariances. + +## References + +- Banfield, J. D., & Raftery, A. E. (1993). Model-Based Gaussian and Non-Gaussian Clustering. Biometrics, 49(3), 803. https://doi.org/10.2307/2532201 + +- Celeux, G., & Govaert, G. (1995). Gaussian parsimonious clustering models. Pattern Recognition, 28(5), 781–793. https://doi.org/10.1016/0031-3203(94)00125-6 + +- Dempster, A. P., Laird, N. M., & Rubin, D. B. (1977). Maximum Likelihood from Incomplete Data via the EM Algorithm. + +- McNicholas, P. D. (2016). Model-Based clustering. Journal of Classification, 33(3), 331–373. https://doi.org/10.1007/s00357-016-9211-9 + +- Scrucca, L., Fop, M., Murphy, T., Brendan, & Raftery, A., E. (2016). Mclust 5: Clustering, Classification and Density Estimation Using Gaussian Finite Mixture Models. The R Journal, 8(1), 289. https://doi.org/10.32614/RJ-2016-021 + +- Scrucca, L., Fraley, C., Murphy, T. B., & Raftery, A. E. (2023). Model-based clustering, +classification, and density estimation using mclust in R. Chapman; Hall/CRC. https: +//doi.org/10.1201/9781003277965 + + + + diff --git a/tests/testthat/_snaps/k_means.new.md b/tests/testthat/_snaps/k_means.new.md deleted file mode 100644 index 51be933..0000000 --- a/tests/testthat/_snaps/k_means.new.md +++ /dev/null @@ -1,85 +0,0 @@ -# bad input - - Code - k_means(mode = "bogus") - Condition - Error in `modelenv::check_spec_mode_engine_val()`: - ! 'bogus' is not a known mode for model `k_means()`. - ---- - - Code - bt <- k_means(num_clusters = -1) %>% set_engine("stats") - fit(bt, mpg ~ ., mtcars) - Condition - Error in `check_args()`: - ! The number of centers should be >= 0. - ---- - - Code - translate_tidyclust(k_means(), engine = NULL) - Condition - Error in `translate_tidyclust.default()`: - ! Please set an engine. - ---- - - Code - translate_tidyclust(k_means(formula = ~x)) - Condition - Error in `k_means()`: - ! unused argument (formula = ~x) - -# printing - - Code - k_means() - Output - K Means Cluster Specification (partition) - - Computational engine: stats - - ---- - - Code - k_means(num_clusters = 10) - Output - K Means Cluster Specification (partition) - - Main Arguments: - num_clusters = 10 - - Computational engine: stats - - -# updating - - Code - k_means(num_clusters = 5) %>% update(num_clusters = tune()) - Output - K Means Cluster Specification (partition) - - Main Arguments: - num_clusters = tune() - - Computational engine: stats - - -# errors if `num_clust` isn't specified - - Code - k_means() %>% set_engine("stats") %>% fit(~., data = mtcars) - Condition - Error in `fit()`: - ! Please specify `num_clust` to be able to fit specification. - ---- - - Code - k_means() %>% set_engine("ClusterR") %>% fit(~., data = mtcars) - Condition - Error in `fit()`: - ! This engine requires some package installs: 'ClusterR' - diff --git a/tests/testthat/test-gm_clust.R b/tests/testthat/test-gm_clust.R index eea9a20..5a25f9d 100644 --- a/tests/testthat/test-gm_clust.R +++ b/tests/testthat/test-gm_clust.R @@ -285,4 +285,166 @@ test_that("mappings to different model names are correct", { tidyclust:::mclust_helper(F, F, F, F, F), "VVV" ) +}) + + + test_that("mappings to different model names are correct", { + set.seed(42) + + iris_sub <- iris %>% dplyr::select(Sepal.Length, Sepal.Width) + + gm_fit <- gm_clust(num_clusters = 3) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "EII" + ) + + gm_fit <- gm_clust(num_clusters = 3, + shared_size = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "VII" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "EEI" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + shared_shape = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "EVI" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + shared_size = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "VEI" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "EEE" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE, + shared_shape = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "EVE" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE, + shared_size = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "VEE" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE, + shared_shape = FALSE, + shared_size = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "VVE" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE, + shared_orientation = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "EEV" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE, + shared_orientation = FALSE, + shared_shape = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "EVV" + ) + + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE, + shared_orientation = FALSE, + shared_size = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "VEV" + ) + + gm_fit <- gm_clust(num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE, + shared_orientation = FALSE, + shared_shape = FALSE, + shared_size = FALSE) %>% + set_engine("mclust") %>% + fit(~., data = iris_sub) + + expect_identical( + gm_fit %>% extract_fit_engine() %>% .$modelName, + "VVV" + ) + + + }) diff --git a/vignettes/articles/db_clust.Rmd b/vignettes/articles/db_clust.Rmd index 14a0cc2..575694e 100644 --- a/vignettes/articles/db_clust.Rmd +++ b/vignettes/articles/db_clust.Rmd @@ -77,15 +77,15 @@ Note that I have standardized bill length and bill depth since DBSCAN uses eucli ```{r} -penguins_std <- penguins %>% - mutate(bill_length_std = scale(bill_length_mm)[,1], - bill_depth_std = scale(bill_depth_mm)[,1]) %>% - select(bill_length_std, bill_depth_std) +penguins_recipe <- recipe(~bill_length_mm + bill_depth_mm, data = penguins) %>% + step_normalize(all_numeric_predictors()) + +db_workflow <- workflow() %>% + add_model(db_clust_spec) %>% + add_recipe(penguins_recipe) -db_clust_fit <- db_clust_spec %>% - fit( ~ bill_length_std + bill_depth_std, - data = penguins_std - ) +db_clust_fit <- db_workflow %>% + fit(data = penguins) db_clust_fit %>% summary() @@ -117,7 +117,7 @@ db_clust_fit %>% extract_cluster_assignment() While the centroids produced by a db_clust fit may not be of primary interest, they can still be accessed via the `extract_fit_summary()` object. ```{r} -db_clust_summary$centroids +db_clust_fit %>% extract_centroids() ``` ## Prediction @@ -128,8 +128,8 @@ Since $DBSCAN$ algorithm ultimately assigns training observations to the cluster ```{r} new_penguin <- tibble( - bill_length_std = -1.2454235, - bill_depth_std = 0.5012132 + bill_length_mm = 45, + bill_depth_mm = 15 ) db_clust_fit %>% @@ -143,6 +143,14 @@ Density-Based Spatial Clustering of Applications with Noise (DBSCAN) is a method In DBSCAN, observations are considered as locations in multidimensional space. The algorithm works by defining a cluster as a dense region of connected points. During the fitting process, points are classified as core points, border points, or noise based on their proximity to other points (**radius**) and a density threshold (**min_points**). +```{r, include = FALSE} +penguins_std <- penguins %>% + mutate(bill_length_std = scale(bill_length_mm)[,1], + bill_depth_std = scale(bill_depth_mm)[,1]) %>% + select(bill_length_std, bill_depth_std) +``` + + The fitting process can be described as follows: ```{r, echo = FALSE, include = FALSE} @@ -151,11 +159,12 @@ penguins_std %>% ggplot() + geom_point(aes(x = bill_length_std, y = bill_depth_std)) + theme_minimal() + -coord_fixed() +coord_fixed() + +labs(x = "Standardized Bill Length", y = "Standardized Bill Depth") ``` -1. For each observation in the data, determine whether each point is a core point. A core point is defined as an observation which has more than the specified **min_points** points (including the point itself) within the specified **radius** around the point. +1. Begin scanning the dataset for core points. A core point is defined as an observation which has more than the specified **min_points** points (including the point itself) within the specified **radius** around the point. ```{r, include = FALSE} @@ -167,7 +176,6 @@ dbscan_fit <- dbscan(penguins_std, eps = eps, minPts = min_points) ``` ```{r, echo = FALSE} -par(mfrow=c(1,2)) penguins_std %>% ggplot() + @@ -179,37 +187,81 @@ penguins_std %>% geom_point(tibble(x = c(-0.79162259), y = c(0.2)), mapping = aes(x = x, y = y, color = c("1"))) + coord_fixed() + theme(legend.position = "none") + - scale_color_manual(values = c("red")) + scale_color_manual(values = c("red"))+ +labs(x = "Standardized Bill Length", y = "Standardized Bill Depth") + + +``` + + +2. If a core point is found, form a cluster with the core point and begin recursively building out the cluster to nearby core points. + + +```{r} + +penguins_std %>% + ggplot() + + geom_point(aes(x = bill_length_std, y = bill_depth_std)) + + theme_minimal() + + geom_circle(tibble(x = c(-0.79162259), y = c(0.2), radius = rep(eps,1)), + mapping = aes(x0 = x, y0 = y, r = eps), + color = "gray", linewidth = 0.8) + + geom_point(tibble(x = c(-0.79162259), y = c(0.2)), mapping = aes(x = x, y = y, color = c("1")), size = 2) + + coord_fixed() + + theme(legend.position = "none") + + scale_color_manual(values = c("#619CFF"))+ +labs(x = "Standardized Bill Length", y = "Standardized Bill Depth") + + +``` + + +3. For every other point within the specified **radius** of the core point, search for other core points to add to the cluster. For every core point added, recursively search for core points within **radius** distance of any core point added until core points for the single cluster have been found. +```{r} penguins_new <- penguins_std penguins_new$cluster <- (db_clust_fit %>% extract_cluster_assignment())$.cluster # factor(dbscan_fit$cluster) -penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = min_points)) == 1, "Yes", "No"), levels = c("Yes", "No")) +penguins_new$cp2 <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = min_points)) == 1 & penguins_new$cluster == "Cluster_2", "Yes", "No"), levels = c("Yes", "No")) + +penguins_new$radius <- if_else(penguins_new$cp == "Yes", eps, 0) + +penguins_new_sub <- penguins_new %>% filter(cp == "Yes") %>% + .[c(2,3,4,5,7,9,16),] penguins_new %>% ggplot(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + geom_point() + theme_minimal() + + geom_circle(mapping = aes(x0 = bill_length_std, y0 = bill_depth_std, r = radius), color = "gray", linewidth = 0.8, data = penguins_new_sub) + coord_fixed() + - scale_color_manual(values = c("red", "black")) + - theme(legend.position = "none") + scale_color_manual(values = c("#619CFF", "black")) + + theme(legend.position = "none")+ +labs(x = "Standardized Bill Length", y = "Standardized Bill Depth") + + + ``` -2. For each core point, assign it to a cluster as well as all other core points within the specified **radius** of the point. Do until all core points have been assigned to a cluster. +4. Repeat the previous steps until all core points for every cluster have been identified. ```{r, echo = FALSE} +penguins_new$cp <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = min_points)) == 1, "Yes", "No"), levels = c("Yes", "No")) + penguins_new %>% mutate(cp_color = if_else(cp == "Yes", cluster, "0")) %>% ggplot() + geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cp_color)) + theme_minimal() + coord_fixed() + - scale_color_manual(values = c("black", "#F8766D", "#00BA38", "#619CFF")) + - theme(legend.position = "none") + scale_color_manual(values = c("black", "#F8766D", "#619CFF", "#00BA38")) + + theme(legend.position = "none")+ +labs(x = "Standardized Bill Length", y = "Standardized Bill Depth") + ``` -3. For the remaining points not assigned to a cluster, check whether the point is within the radius of a core point. For points not in the radius of any core points, assign the point as an outlier. Otherwise, assign the point to the cluster of the closest core point. +5. For the remaining points not assigned to a cluster, check whether the point is within the radius of a core point and assign to cluster corresponding to nearest core point. Points not in the radius of any core points, are considered outliers. ```{r, echo = FALSE} @@ -218,7 +270,10 @@ penguins_new %>% geom_point(aes(x = bill_length_std, y = bill_depth_std, color = cluster)) + theme_minimal() + coord_fixed() + - scale_color_manual(values = c("#F8766D", "#00BA38", "#619CFF", "black")) + - theme(legend.position = "none") + scale_color_manual(values = c("black", "#F8766D", "#619CFF", "#00BA38")) + + theme(legend.position = "none")+ +labs(x = "Standardized Bill Length", y = "Standardized Bill Depth") + ``` + diff --git a/vignettes/articles/gm_clust.Rmd b/vignettes/articles/gm_clust.Rmd index d0dc4a2..06cfaca 100644 --- a/vignettes/articles/gm_clust.Rmd +++ b/vignettes/articles/gm_clust.Rmd @@ -29,6 +29,7 @@ Load Libraries: library(tidyclust) library(tidyverse) library(tidymodels) +library(mclust) ``` @@ -53,16 +54,23 @@ penguins <- penguins %>% -At the end of this vignette, you will find a brief overview of the GMM algorithm. +At the end of this vignette, you will find a brief overview of the GMM algorithm and examples of each GMM model specification. ## `gm_clust` specification in {`tidyclust`} -To specify a GMM model in `tidyclust`, simply set the value for `num_clusters`: +To specify a GMM model in `tidyclust`, set the value for `num_clusters` and use the TRUE/FALSE parameters to select which model specification to use: ```{r} -gm_clust_spec <- gm_clust(num_clusters = 3) +gm_clust_spec <- gm_clust( + num_clusters = 3, + circular = FALSE, + zero_covariance = FALSE, + shared_orientation = TRUE, + shared_shape = FALSE, + shared_size = FALSE +) gm_clust_spec ``` @@ -98,13 +106,6 @@ The cluster assignments for the training data can be accessed using the `extract gm_clust_fit %>% extract_cluster_assignment() ``` -**Should probably make some way to extract probabilities of belonging to each group** - -```{r} -gm_clust_fit$fit$z %>% head() -``` - - If you have not yet read the `k_means` vignette, we recommend reading that first; functions that are used in this vignette are explained in more detail there. @@ -134,17 +135,6 @@ gm_clust_fit %>% ``` -## A brief introduction to density-based clustering - - -Gaussian Mixture Models (GMM) is a probabilistic unsupervised learning method that models data as a mixture of multiple Gaussian distributions. Unlike clustering methods such as k-means, GMM provides a soft clustering approach, where each observation has a probability of belonging to multiple clusters. This allows for more flexibility in capturing complex data distributions. - -In GMM, observations are assumed to be generated from a combination of Gaussian distributions, each with its own mean and covariance. The algorithm works by iteratively estimating the parameters of these distributions using the Expectation-Maximization (EM) algorithm. During the fitting process, observations are assigned to clusters based on their probability of belonging to each Gaussian component (**num_clusters**), making GMM effective for identifying overlapping or elliptical clusters in data. - - - - - ```{r} #| include: false plot_state <- function(obj) { @@ -181,9 +171,53 @@ plot_state <- function(obj) { theme(legend.position = "none") } + + +get_state <- function(params) { + + list(mean1 = unname(params$mean[,1]), + mean2 = unname(params$mean[,2]), + mean3 = unname(params$mean[,3]), + sigma1 = unname(params$variance$sigma)[,,1], + sigma2 = unname(params$variance$sigma)[,,2], + sigma3 = unname(params$variance$sigma)[,,3]) +} + ``` + +| Model Name | Circular Clusters? | Zero Covariance? | Shared Orientation? | Shared Shape? | Shared Size? | Example | +|-----------|-----------|-----------|-----------|-----------|-----------|-----------| +| EII | TRUE | -- | -- | -- | TRUE | ![](gmm_models/eii.jpg) | +| VII | TRUE | -- | -- | -- | FALSE | ![](gmm_models/vii.jpg) | +| EEI | FALSE | TRUE | -- | TRUE | TRUE | ![](gmm_models/eei.jpg) | +| EVI | FALSE | TRUE | -- | FALSE | TRUE | ![](gmm_models/evi.jpg) | +| VEI | FALSE | TRUE | -- | TRUE | FALSE | ![](gmm_models/vei.jpg) | +| VVI | FALSE | TRUE | -- | FALSE | FALSE | ![](gmm_models/vvi.jpg) | +| EEE | FALSE | FALSE | TRUE | TRUE | TRUE | ![](gmm_models/eee.jpg) | +| EVE | FALSE | FALSE | TRUE | FALSE | TRUE | ![](gmm_models/eve.jpg) | +| VEE | FALSE | FALSE | TRUE | TRUE | FALSE | ![](gmm_models/vee.jpg) | +| VVE | FALSE | FALSE | TRUE | FALSE | FALSE | ![](gmm_models/vve.jpg) | +| EEV | FALSE | FALSE | FALSE | TRUE | TRUE | ![](gmm_models/eev.jpg) | +| EVV | FALSE | FALSE | FALSE | FALSE | TRUE | ![](gmm_models/evv.jpg) | +| VEV | FALSE | FALSE | FALSE | TRUE | FALSE | ![](gmm_models/vev.jpg) | +| VVV | FALSE | FALSE | FALSE | FALSE | FALSE | ![](gmm_models/vvv.jpg) | + +: GMM Model Specifications with gm_clust() + + + + +## A brief introduction to density-based clustering + + +Gaussian Mixture Models (GMM) is a probabilistic unsupervised learning method that models data as a mixture of multiple Gaussian distributions. Unlike clustering methods such as k-means, GMM provides a soft clustering approach, where each observation has a probability of belonging to multiple clusters. This allows for more flexibility in capturing complex data distributions. + +In GMM, observations are assumed to be generated from a combination of Gaussian distributions, each with some mean vector and variance-covariance matrix. The algorithm works by iteratively estimating these parameters for each cluster using the Expectation-Maximization (EM) algorithm. After estimating these parameters observations are assigned to clusters based on their probability of belonging to each Gaussian component. + + + ```{r} #| include: false param_init <- list( @@ -229,42 +263,32 @@ param_conv <- list( #| echo: false plot_state(param_init) ``` + + ```{r} #| echo: false plot_state(param_iter1) ``` + + ```{r} #| echo: false plot_state(param_iter2) ``` + + ```{r} #| echo: false plot_state(param_conv) ``` -```{r} -#| include: false -penguins %>% - mutate(cluster = (gm_clust_fit %>% extract_cluster_assignment())$.cluster) %>% - ggplot(aes(x = bill_length_mm, y = bill_depth_mm, color = cluster)) + - geom_point() + - stat_ellipse(level = .50, type = "norm", linetype = 1) + - stat_ellipse(level = .75, type = "norm", linetype = 1) + - stat_ellipse(level = .95, type = "norm", linetype = 1) + - theme_minimal() + - scale_color_manual(values = c("#F8766D", "#00BA38", "#619CFF")) + - theme(legend.position = "none") -``` -```{r} -gmm_engine <- gm_clust_fit %>% extract_fit_engine() -mclust::plot.Mclust(gmm_engine) -``` + diff --git a/vignettes/articles/gmm_models/eee.jpg b/vignettes/articles/gmm_models/eee.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b5c0dc69643260c308436b1e057736c06288467 GIT binary patch literal 50421 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 z zt9(ngl}QFn`=njV=r(h?9T}B(l|NA`f$KMt9%D_Sx?uGcH+JCRyzn8^ID9QR1G1bH zj``m123vI=$QXGb4C@sNe1`bUN!~ag582rOrm{*EPZiV(6@PXDVk`q6IYVX@!!td` zT9BSLzU(_b@d`;^{F_GorC5{qkkEPy(^$3-T@T*z&_S}f9u81NYQ6aJP==wLaLOzXtKVCt`*T zT`NaY>8z<7#@msA8|dgok7f3#w;Rs?Jd_c4;^WSJ??W!D9d|l$^ z$VAE96l11dXm^7WpKnHtZ|_k@&+*)wHXc~0N}}HNk0ovBuX94Ja!Dt)5)wKYjJ8B* zY5H#|!{4zm%QnH>#3*o$dW-lQs{=(1OCL@^ccdjt{e3sxp8@3HiCE^({T()=4t8?U z#xLe8ts8_{J4?zP$Az{kA)DZy7ybhYu z)mR4X)tYV!(@6XKG$0pzuKrVAua+2iBoO({=3LSel&*PyM7zq&{oODPGz?&9#W?Hb zG-;ZbHQjjg2c^|8q*Mz*O=bB?GfOyle*qr=d2BF*9Vsi3?faSWnCKCU2#~Ky z%JjGF7a=)jQm7&)YHZz}cKwcHcaK>C}b$l3|x{}X-k^M|`TJ0eP}qQg7{V^6}LJ z#tVoKz65y%#0KHjBpXTX#$fl7wwOX}+hEhV`{(Th@av{I^PxTXo)MQSN@Inu5Ea%9 zwCW%_cWUvf-!8;z6^%H*;%UTaZC|AT3!Pb%!4Uya`t##9KG`BL22%cYjk6P1t6^+o zgM6#4GTQfZd@-JbDcpsXD;NK$QgKz{+LKJj+`TUVzojCVWA}>nH89A`ADi+T)<0!% zyARaySXduzXZ=oG@@Fk7!D>9J8SipOsA%{+!pUF|KmjPTNs?xsKTG=xOYhRg7o31D z-yDON#x0xKUr{@WgNLU(HuWS)<@zt`>RQyk6vq^ z;bSK2u-=h0>vD+mRjk%9vc;B`p6;Dpv3~Uwh4Ks`T(6PnjSWlFyX?1EJ7Smwa^&4_ zP2Q+_Q-9wY!6#K|1Mf8eHUnwqG0m#&=HBY@-;H>#*ou1UC zxZ5r?*D$~@vVwS$TBVMNfWh*&J7RnWWWSw~|8#tcxjXQD*F>FAT7}S`FYBIjc|?GX zThUl2ln&#qQCyhxr=as5($@nHv~h}xq(!`PDl{X7?gTQnMACP9ukmhnx)J4zp2q)}nE#xr-xU1<7rTE} zzX9c1TXV2DwIs>Vg|966%)h!iK%{PWr7c+k7l9B7i;-^P%(=+SVgLD$#WDt%5YpQt zV?vMS)Laj{pepd64Enge;s-{UXn7{f@RWY&V|o7C!iZr)z}_^a0m&f z?WDcC_iia_PYh>ivz3j*jY3hYQ_-1f+nn0$dj`PNVy1y^I33oOeT1tI0hXsvA+ zG=Qm7vF77>hVXB{zq&x?hr+EDg(-d-v>AKwKqu8mu+%|WyjR`uwWwL-JM(^BJ*o3M z$)V@O4#bt`)$Bl|!?yaZV@jdbbv5d|u%V7!*y8w3o7ON+HS>jaSY4LjIeaz@2yXCB zM{;I;UEz+X!vy553i`a49Q;X+(rl<$LXIICl+PV07J7Y$HWsekJV7F{h+yP0@S4 zz@+CQ!fxslAJ?m;U|sl%3e)XI`5?kyt8 zH)MC2Az99AG~I0vQOz2bv}o^^!%9mBac(UU(>Jbdw9HtpSKN9cCV$>@ubMU$C={sOzHtUh2X`AOau)kg{O4oa6gwysb@gK~3!*f53ef+;QG+kw`V zZne+5D1NPkztp~9rko!IPxdelDMw-+xg2qCaG76bGo*-oG83M+rv~25vmQ=&yv@mU zojk2{uf!lwLP(&KkRaE_M~VvTL#3){0xGn>x+bvVd3*F?P|8du_e9MW#-&i1YR&P5 z9{s@?jRc^f87x`o&1A3jvvrjsGUI9V5(VSPH zHczGGXXNj4B+Njq4yh_WK5_@_N$5#I<$x!Hw(GX-EN{*SOr$Iv#m35OHheOGUH z^wVIG_=cCBL80aew(&9HJ-)_5ymGL0#G2ZpEE5$OkvwnMcK>peF(y(wM*BfTwRa4B z-0lPX~G!3>0}L@kVwC1S4LZ4dix@ z=P=dj_v8vcC#9&SY5)(d_c2YSsi-7z^A+I$f4y-6dVxIx4}5efxjJt7KJE48&7kdo zUpYgkm2Zeo+sh$hE-w?X6)odGQ&c~gBKEIhks}{%(aFZGF-6_zBI=q&dGhJ?l0Ce$ zcKV9%)d4YRz`AQwPKV(4U0FEebRc)ZV7WXQk4*HXJ8p4@rkH&kM^SBmdNqu~Te7S_ z#mi7!>({R1h2;ZBcDyD0HwD7ex1}Wa1H`dI)E}o2-re@As8?TcuMY0Z&(I_L&}Q@RBzJpt9|<2KYa;Bv%4VhrXK=q~%)c>6@HUUdJb(WprR^r=}!>^>DwEza~wYzt8XpK?X zTbO)>W=abTKRd98+xJc*M{#oGNfGuoTJmM>qQS?#jTO{kGbMxuMuvzh)=g6~_IEh4 z7J&qiPh%<&4+p#Z>Mqk}=hVE5M9Zvp9Ccucxd*L3{xg~WN5VYwHkFgE=W_6EXA)!4 zjb9u1V(OzFpN57tcEcU&pr9hLwHiSdc)=UrBjhvGmI`II(Rfn*V&ABdU!AOQa4-U4uJ~SD+v?2Y}p8C&m4w@(x+c!#4WaIj8REcIpl``* zXQq=DZk8Mg%KaWMqPLr@->w(m;CB3ecEwE6PB`~?9$~yM)40mr?Si1QN@1$QcWp1+ zNr%x5`R;TS!(Vyf)8Dcey;w0Op9!$-0bIuyiMtDVhvyE&0q?+C{vpQRo^U+b5K8<3A$VW8C+8?p5id|zZH6YKxF8dDj|rmxvu(I=+vJCDiF~}DoW7TT>Cu|!#n+( zC2TrrN|^`y1U0#L$)pG6%e?A-#&f6_FfR9zFOQ`~H>o4*jGXc?b=o_(zU#bjkf$Qb zGydE%R0TL2cb95&!d;M84JwhTO}F_Ov*08Ad*&+{xTTc5iIGUe_7rt1wspw^%y#`N z38qRNV^Usj9O#gyA7M4qdvl?M;wJpsDx6gP3qh9ai0ic^Z>VNgxrz*m)(=@y?E$= zWN}!}y?+V((z3_uJfT+>6V&yzMr4pK!Xj4kmx*c4(3!K zlcpL>Q^#%;FC2CrPsks9I0CQf>H$J31~a#)k6mUtaO9hc0*DHrny)A$4-3mY3{Yiv zWH_}_$SfjqlnblTBg!nf2b8|FMDoB55LaeETqkCTBN9u$ln9O1%X`h$HD#=n%I%wrusWC>K*R9L zSsw6UF=d~*wf>A3j(>h&zgcn!eYxd)g=D2kjJtkOR-06Bz!aVGf zY&u7tYa_JqqI}{0m^%pW`FL#wcI?t@Y$ZI!UVm>SU#(xs!P9gYfzIw+qusO{Uh%!Q zU5uO^zst`QgX-AgrT6am;R&`{Emx!+m9HeD-Fg?)%T2EQ5ltmMK2H{IUQ0Wi10*?? zjf8i~`wfyw9^W3d@vbooH+!3MkNwCfr)o5Za}Gu!8_OW9#M+}Y>bwweJbaLzvyEu! zbly(De!G2;v!tWk6%B!J39rEPVjpc6x~ADxT%?>}l(dLbF3C%;TSWoqHMqO+OqlGI zNd&p&E!-i0SvlN2ekEWn#kYE|SiVhkXv%%S#?7O|@1{|XIF+g%BY2x3J1TukMY4K` z$b69*+ER0X%kS}<&AlCz>|DUpCw{1b^*S1)I4BGE84TUz&dfQR(o=;v`_-rhQnzn` z14RFMV{Yv$&|iM#yOT3(HRM+_Q&(&(OdX;jzjy7!JPt^<%Fbz z5O1HCBcf(?`adnmb7c+SgEDwzTCtvwvi6Qx_E--Kb)z(~dk0XG!%@84>`PL%J!IrW z;pjUL7NF-qtN!rXgJn5;LV}9WuXis~PV%?N$|ygRa-lAhGFhAA8mJei5KaK~h8NX) z*ZBhBoi>YA&*AvDK^v4y3XYV&I<_}3{YLgqdG4`uJhSCx!Q-ga={x?C)|(qRnQ?Tn zv~`1in;RjCvw&VeC($Bgi*b1zo!&sw!btgXySwrxqwRROyhBUux;RmViykz{HlyXJ z^s_5OEc2yLP-=RW*$D_J*nO;b2grcI)3W99S@^)TlwV`bEgQm4nf&SgJ zf87P0dCeO@QO57nJ08W2JH)%%$RoZMmF}aKs$NZ~DUe)&z4qDzO0WQ5We%%cYDw{R zcW3F`ZdIQv7C4sVV&yJBJE29I6j)I?xBDQT(v8&uaHu>Ql}q&M(lDw#x^@+$@{U6? z!x~3`jc+VY`TGttDoQkp^D;pmaKcVBiesvA3X)7WdepL;;R(bZe4Xu$x4=CSYsa&P z{SEMXn5b~cLC~`F9)26QayIs+1JMQArX5%)4-RG)H_o#VaG+`dL}Q`TJvBfPg?s*Z zOQo*ir>Rbu(>3_c(mvj~De%5IB-wEc9B7AAb#;k&Y4MAG;k?7ZF|4+6!E=-bsAD9V za?jsh6J6ihce}5mL~H!)7=T}vkyI1tk4r2!Am19!UuUX_yIB>%@`j&U<>|Rlw9Zri z0iD^Z2#>#uw%+IVyJRBE#B#fId1EiKGw$0^>LM${{r$dPJY ziP1<2ez%6$g6s~|$9wQWZ@OnT$6PPRT;@`iM2I^AZn~$s1@{8~1=lU35R0rID_HxV zHYOUX;VFg7Ln%uQ%-^4U>@V;A^rJO5;D)$vZ=QJflN%1uXNM!fW?v42mh~hO2!LWG z-qW>4xt%V%{C_C{{}XBXug4BtQ_H#FyqABFupiGaRHZHOC~hB(ZDM!My=vJlkt!`K8?>by84wDkT1my{42@>#=<1^4EiEl*rHGw1VR?H{ zbX@|VF?m_lftQlx%pygG%-$t}h(@yG=dJ_E<0O%J)p(1iAjYMn0n;o;+O1aEn>@A| z>|<MK{h89cTt!Z^kUu1>*?_ls zx&|?k&v`|WGllPBQiglngWAUI0?tS|SEM~~%G*F$1gG4D2a`5cUWxnuwpbz0Iz=@* zvk(?M2Y9;3xPq>|XQgK^X?2qbSGZWq4#!c>QBU~yxs_40v^D-6a@P1DntxtXq7H4GBaTwt`;BUB|`K=hP+`F7JF z`fzZ@>`JjLZdLJ=-=QjU5pVK$q(%Y` zWy2g-9w768BUCSLXXHVWJ@1`r?poph0MgewGHQb)FeOe-1?QP97tEpq9|iS{V4u#9 zZx>%?M=0#n4;n4pjO%pjA+R9&C6pS_x71)h;BGD*}^RAZ=frDceAqbMu#;bvrE z_)je&rqDoUg6}az-CAewt$qe|zXk4pw^C<=|7K*)#%7n7rpH@ost(1z;v@~uxHWWc zB1xDJfF+&LDSjXg5e+S{(}9yJEGO(8JE+Pt1Vnuoz;mAE z9l|;$CLsY~dN7aU9#C~0GIq;B|6(oibiXf+jz0B!?b;)QWbfRs8aQQjtX6UI%(zZ) z3?43i0;&!oIRso4xije8;<4SZDH@p?;YfSqyDEL&4?~PfizESpCR!r%MxoUp)w5w8 zBVrb5D}M2FJI@p0z%fX--n0&a9p>C=On~B`ALRs56#Tmg-W*7H_zE>xzi!xB4)&J2 z|Ecfx)FfSa$F3YgZ4!v!jtV->*{W+rjiaK3o_OW(U{V5byRxzjN?iD$?M|^qn;o+0 zWEO_@OA{ZE`^Y>TOtdT;^HA^*TZlJ}jis$JK6nq%&X&R`#M<843;>bRHc}4$+*cs( zfXD^Q{| zLCz&${X$E%?X)q7Wy(D#WT~kX8arT;Qu{;=YK4= zfA~@5<>ez0^ot2Xe{ZLm`8J8|qiGH<3U`Jb`6EudV!@5o9KV?HGnxFYgs#L{`ICB< zw9gL)Q-4w}-&jOE!z5)COzFMAYPR84?n%~+r|6&wc0|&ycs|um!B|MWZ>wz``<%C{ zm+`A1xel1i=cL*nF#3}3+i8ce?FE0Q`@a1wX*@xVY96CjDYyFbP}lnNzPtaREany+1n(vSN@f0PuHh&L$4e%c6%2%+o|m9Ywixa!zHTv z%Y$tn5%3Bt0Eg+EMseIl+gm{!Xhm8&l~>&ngRp}Sd$P9gYfwQFa)6f5nLtr9F4;~)(UE_ZCgSXHur@P7syH+kMlYrRh&jq zib)(J*UVIrdg$QI+x9%9BTkR+?CeUG=IoAHm;<}9J7$g?2M7macF*KNEARUiit{rO%yii24oAE;Dz zu2LKzzrM6)+iEpp_|%Kc(_3)S@LB$4kYpLj_*I9d@e2CIOCBEf8oO3pDEw+K%Ha5* zHR2j+*aNxEL}&H`t5cfX;!V``LaiO)5SJ0oEFBM7_eoN-U~HKK>`99~6(+;jlrc8v zP&GwZ;)cmtX<7UWnwxsOzk&0M_$K~m!l^6>eIOX(7^!m{p18*h=$)yW4(Gk+^4xAvT4mHku@kW}JG$*QZ_)Gd15 z^u^n_3rWuW?fslwmxWfIMWm}~P+BRUzUkS@WS+iAG56e?0Qp&|Bq|aAS;L*5vfRk7 z(B*nl%Q`7a$;Q=1EgR3Lh$Shm*5H=~0owHh9u~P6wSJcIWqrOlE{iypG@Q&`i&{;y3 zWazIWi0THe0H)D*yF#{<`R!ZM+XX}L;2bV4pZ?GpRDzK6OK6LG?Imhx~hpjU5{SKAHLigr<-g6H~Q6 z*f5I%W1rFi$(%EufZRbN9lVd?1hh@~#CQX71>Prg0-6!*KZDc#WyB_Y*wU#ZWv&x( zd`Zoxv9-+S`;Dt8JDJ_H|L&KAlLq3)DYwLNopT*C{FYM4(9PPzV6e|OLk+@exROgB)--M);z|T5MY`8B~tYM#rJsZ{kx^M>6Vr5 zzj#>GV8OrOg57tc^|zcb!;1Q?o{Vw8SsDygWNC)IedqIG`D1mZPl=a#O|P%!yFofN zEt!sgy;e>LALY)&sg|jk4wQGq)n4YMdjVAN$guBHBRu9wG{61Sr4dh3_d5jRE0j;? zMb~7!1IjB_7#|;Tyfq<%$eDU}I4od4$K!B3;(u-Lcx?USB^jDfm}Lq?eTZEkEU*BB1u&T=&|3K}MwQQq{v>&-rFVkppLv+8NaHnRn-H z*u4xEy|Js&%VeQMM*@+J>W9M|%l_xo9mz zYJT^Yv@BKUY)LF$ZdH{cw=V(OVi-a1+UG`)i z^#yNUzc!b(%hT}29~m!gY2d?8v@108e=+ygaZ$G08ZZVTAR}CU)1W?l&KpFtVaHNDg2rV02-dGA-YElik93+;0e@<33cCQ_m(^Y$0 zOOa_9k=;uAgjt2rCY7lZkq`L}Az=|3H>>Q*FUyc|emxsW6e0M{a*|qOoH`Jo(fl2kL>VQC1Lz9qA8*yOG!O%J)#+!zIbH_?7JAKKfJUJiX zj?4*6v{#l%QMYQSq>JBaN?)g;#KyNC{PrNHEUq;+jcp=l!ooA<9nUEoU7paV7v8$v z$tV{2Hv(f#LK9B+N9#TU^=6=qj!)I`)46S0<<-WleS(So9C+{59o9r-PewqsT0SjY zzSJzmiu^I6Yr-3&@gVUQ%Bs4HIl>$zJxS{gjxRg2pLO=tfskG2+z@`F&TJTYn!dtV z`UHS9>xBf)mL_`&k2`if@w3uW4hi!DFb;WQx0#5Y9%%SEBwV9_n$-egE2hY!=Qt7J z$BFFs;7(a7w@|pdCxa`ET7rGs$MGv@f9nX+`oQ5GDOXRE|1C2u;cX^8uqIRFA*r#~ z&Il{f6SkA#ulfKx%Ls3&^wP>VQb!&7r(4M`3rA7TmMwa55A1dc+Y8HoHwNa7I0(z5 z)CsXmQEv^`B#M}Umqx_4NN}K3L#mL>tamZ~;QRzE+oE zl=a!tD}mC?{vw1Y%6d#EOiLwOKZphiLO)@o2oj7hMr9Tt$EuV6$-4AhHTsr}tu@V5 zbt&22g3%E%yfmzkSi@5{-LeID!oCR9YO|V7PSd$19x_B4E>AaScx@PP@Y~Ps+#v* zZJF6bRT~g*2_Ftx=fdgDVK-bEkogd)2wd^;JqoKw`K!+Ncej(N>ch78uZc^#2xIaUSTPhP1#$aSC%~PrvpbJrNSzWj@wz@U^lO^MdByu!Th+b*WCnasczI&y zb7{`wpjUNk1}jhip#F!iD&}YO#eV`9{hJ@~4~O8%PCJRDzANf+SI6p6HmTIq70_cF znO$(SYh8EpYpO8n;Mxj5}AjqHCyR>yKPsk*qVt|W4J?N%iHIeLiO+ry5TXT_2IYqw%Z z&(Tx5g=DEj7l_pE#8k{xwbu5s$7t47B0MOi^+UkjoL#&)P(Iq^prBe@tXL8cILtIj zQh23-2uD(JDTpzOZD|UZprdpg>t|N04pIZpbGU;7NA7JeS}<65R|`t*@?mm-nYy)s z_6oO$=NvX%SWoPNy8=BZ^J{+4$UL3D)x#-A)(bE{vjDub%(_CkTTp*+a~$i8y;?Em zZU;bSAnT!++;b%4&YSWy8>THFE~N!f{=uqX=3Y^E2uNc`OCiEmve}H>dw^FgY~jPz zi*BmU52F3UXI4w6>b__HAPSYS&xR5tVHrA3K!bJ?gs!ukiI5%Ninw}wpl}N_$&2p4 zSC=9!;i=u?RYpp>y)DI$iZk%^^B)YTd%d%6>@8i^IBmxW&+i`6~ zy4J0KdIDR~%v~k0y0|fJ#LUAm%cLL-?H#cm^UiW~vQ-84-bYRh{VQ?|kp3q;pa3%x^OR$|B2oPe`b!(kX}}HN_23;KDu-ii1|FR?D_cUrkosH+um+ zkAr~HuG$aw!(O5nw15GelXWAsGLY?j-BAb37c}Z6He9!`wWi5p^;xcw7r%>`lV>>) za_XFW=Sl&~tYTh24LC@dMF?t6ZF9P=6q)8qZIurJ`+i#(Ec(tfYSeh80*GWq+ipqp zY(zbF&tv&u*6VboJLNgE2j*MBkT5wS>>hx!t){G3bC)PUtA{4bMznJTB)JoDD)pwy zE=E6jCjN%zMLE;D;4@UBZ^kR}wXW-g^XK-C!@$}dgC3Si&ys?l(FXZDDc)lri<1s@i~XE+di7h89Qx8N35A~bz2-k0Y>m{$4 z=R&cN3Ms_+UFl|j?WJ4*;F`2N_yKyzD|}IEl`c2LHWLburE9>9DsNA1>#@b|U}e6H zAKlnCX8I1mo+I$~diSDt)};pyYkJ*RWn5hVV_GFRA38MHLT%Gp*uu~n#784dgyYN& zx;-0c6eJWTbXD!q8;Q3;o)ST~|6Arxj%!t#)_H8m@`pR$e3>9N<|1=p^Q1STou${* z{4?)rgr}_4UBEqF`#Qqlu)I=K@RHILwCtmM6S@6PNS*j;X{6VwwtYh>H%0#dhc2&X z1w*@hY4T24`)rwI-do{I*U;?; z92&CLZ$Wl03{E03_)~`=We3#izIBbF#BJk33LnAiaU3wQq0DOX z*8scF)0wT?2B^=-JTC?ps~KkF>Z7yHF~CSDnlF%?qqxaiLk-CDx*LQKpG!Bzgg=kI zn1DJ3G^MycEL(ETyLvZ4VuD%mJ(-N>8^pIhZ5~t;y{YjN{S6ypZ4=EAt_D?Sb|Pg> z=V_sxEkp!Q7CAryX@3J4Q}$XwWNCk%9rNKmmJ*l<5SyW(g3dBsT84ay)3sqRIS;;p zSk)A+6(|z`f)OH6(~s$nO_C!i1)gEQ5I+N!0a0yUEDK5{k>_<%9?=3${n{A}l^PJS zSgnv_3q2!6zs+C?IvRk5Dn6g^5FAE|__mg1`x=cb34#aMy^nzaF3Le(P}iXKL-qnT zXZgjwsl(Fo0jRZhO$_A|`onbkS)ZGdL&^KL%47Pg%o+)++A2EID; z_p#Wozu_DU*kuAHNy;`+N1`P=JuNjsy-`Q>Q;8krwp~Uc^L*A?oXlZu0(bPVwg|~l zg~}-07UF1G-mbD?(LGl_EJmCqRK3=(C2Rji7GSG@LQD=ocq4sFif-f%R>cC^msa?G znJ7FGR+3Td1}79|HY&M^0L93u>=#;Bv?LkbJ{3jJS7m97cE)km_Te5G=U>M%%?d2A z(OKq$Fa97>j!=${>K=#mtjG0ovL}=v5FJU*V7@Tiz@T>G$9=|>&?LYmtlz;l= zsk>I-YM_2{TvJ;zZ|iirWSq(PaK>nLRgKrd#gUra-IAi7Nv!@F2qJG2HtWXFT#kmN zcFXBFze5}^-yu}wio*Tf?k+}`xsaZq^bzZEHd%u$$1iPATj9G7SJ5uJk0g>9UR?6d^>uOAL9;alV+X75Xl=uTJVXs^L8^z1!Un0SN z!qc!@T}IO`DRPB92{{jC30D{QC>JY|SZlt6Kjw1Q1q|E1(r&UBIWQTe+yke*(DzU% z3cfi^{_*QpS0MyABgSGBYmXi_#oemCJ=6|Fdk#TRQuH34nkX&U&IgwQty>ON!m46c zemBvW!uf!mF{+S-0(05w8}o{mW#)A8bXi))JTic(H;+}~0!pHM;(&98+bufg`JyMa zEhdPbUHmk>wT#P)aa3n6Ut1x4pSuutqi0=b7({Uw`&wu~&I#XO8GH-?T&<&lfEOUv zS3?e(miEp|FO{mkruhYrS1od2Y*l#`b?oGXdYJI@Oo^)oXa;;Vr1iU>7XPk0)!*lt z)!L4F@CP!$6Ze28D*t=_ZenbdA`V*^h%*c`y!p1xcD0MIjW6PnQThH7;%{#N)+RsY zK*sT}68_(mvqI|1npB6WJKAHsg%qf2`WxB! zlqM?=)!%93-_1BbdqgsIE9DiFfNvoGVb+grwIo;Xi5-}uVIr> zFoI9qTSfB@-kQv2*i@ABZpQCcG=-q(9{Y>(vd0rDT4%8LI8qbue1TNib0M~JV7kw4 z{!%wNJPY%ApO-g=HJ-ypWJqzvYOJXDMtD`hGHf>;4%$ds^-ZQXuC*3joOv^fQN6Tt z{jP5zdXX%HJ%o4h{#zP@EG}4@jIB5_$hx{t_6oMY^K2Gc8MnWJO{%Z_`0Jg8y{FbsazEJvUv(x45;Qs4R&`F8F>~tAb2Q%noavv;n$R&v#@)QN6{>j5n}1EP(U@Ln7DxbH6~?yv!|R?myQGkU%l>x!dz$lKyzKw8f3r{EG=CT}s1lLHQwcTrVx6hSQBS6n zTcsYk8e76%41--~`6}l773@N{3OY)y`fXqPcP1M{l@1_uKqI*y(x&GJ_?08@P>%-f z9S`YVfZte?CmFoihFDa5t%FnO1pSPKUo*}=jyL9O~s@ca|gf;0OuS=dYFn>m9+oCQoSE>AjQ^H|)tc=1xoRRHzi z*{4|^{lcGtN!p-Fbv?kw$lIJp%m2=AS8|iV8-rAfopHF$t)zwnadke3lM~?JgfGjpFeCGzJ3S`^v}^ND zOtI%P0B;0xgFpvWelevtImved*YsyU$RIw0v>rq2NPcPXQS`A{>F3!yF11K5+DZ2{ z^f~v@y4(Ru_YE9x;)l&x)h;LdKtx1Bq+WYEotg+BCHaLxDfo#;`Spub&mQ`VIZhP< zIHCYl#&4*`;O|3)=Yu7G^!k&XU;IqwMXd{9{{5_jVrU}qd=H8`53ztQL6KKB5r zH|iQWlaGX4Aj6lzc@L+FKX^{8^b8At^JwI;bKfde&jI-wsGx`8@MEaxhmk!Y#zcy8 zUuU_@`rx%O8vQLyf8!OQ?}M~`lnZeWefET!)-bWYB{dz>oPHQ(9Iex?93q90cU_gO z?`H6}x$Rd^D*8J8=niuO8nIg$uPB~O$%5Yw3joVAZ=1S2yI6hUB8`@Wyynhz9u{yo zx0=pV`ePGT_jEu<2^%ooJ@C+4iB;jvE#@-aJ(VM)6x9+p3@#R9@f1jmd~FFZK|KR& z7gG9f0m1O$`g(zQtELEN2!eU)iRyk2qeq=M=O5Qplm4QRVF9>km0P58UKt*BOr?DYMDkZtTEcmo z9=NvQ_Tk?ER;j?O5xFl)F@*#caCeE}4#~UO)~<8k7O<;zCnRc6so6TR20~7g_5)az z5fD5uX8y>?tcLpqNVY{E-Z;%1jMw)~XUCRCz*p5{o5ndjyFd_wv?9t?2yO4h@K*5b z>0F-RH1??huC{(+z$Wu{L8`yD*9R-m$q4HtKESA11iZvPro1BxI}gO0Gw34@-+^8r zHvz6Ujgi&oa&rl%tq&@h;{e0IwlpkF^IqxZ@HET8BNYjslukmiTp{czuNT0o_EezV zXD4!xYw7y!+}@Ww0mpeOm&U)sTi(E3B1;3m#qrw`iXRTxx#tyS;p%Dp-FG1M!buUI zTR3~2_nSE4m$vAGdxA2b1O2f+t~k8P{Ei8)wdv*ImF zPMw+(qdqGt6N3RL!ST8Eg@-e1rV-%jQ+16MQPRv=9P-mE(f`vckpn0rz&Y_( zhr}<#Oo9@CwEBzu`|Bai-@E5ktfPUPk5baJOXM zrUWub)gfT=o_r5`W+7qV7k3unylD%oxJ^jvcQqOuazY!YA}UG$Xc637-=WEuGx>{O}l|Wd~f-A@hcBzq8`F~XX zPt>F|pul8j9Pk`Sga+^fSD^_PN&qx)q-kx7n<4KqerIlX^Ajl6dQDnKwXT-s@j#>{kl4K41FOEf82U`>0tXE#mw! zsV==oYNKF5&AJH$wTE6yXvtyBc5lN~Z~ir=V_c|CAwCf&nWMy0tvD|`Ed9OIx*{A) z`;s3su&^`rt*drz<+R%Z7feu{TjGL+cF2s`h-0&cm5#~kB$oCyOnb`#{>F=RpcFYM z92XU4Z!e!Mg8@9>DUQ9~adn^##J0AA**W3PdHKFIq)T~?Q!|X(CeylyUdTiT zD=vO3=5UML>!M#ydr0m?hj~mn4HW|HnsTu}hyW-`&dm6g z2KBK^JQ+^zuJ`5u`&{jqc@8?V#cL&+5KIvAbwnW=drdp&MkEq-uT$b&f*LFEX%5Xj zV;&;TyczK}z_YFo=~XLV!p3xaQ!z%dB&M#T1X z3_+HIWj>a0O$wyZv!8n`A*u^H&_1g`IOwy+zgL5yp%k{Y%l@zHwin{8ajZuqX+>Tp z$-uas%MqUH=v7&wpE9{0KlAs}_i&>IhQT>!gY4b#XzC*Hzp;Lv9$ZE^Lm zN>BP5D#mPR(2K(!qY_qU!PW6Cl8ygU$nYl+y@$A?z_noa39FB{&Sc`kVDkIiByC=F zsC#s>!<#&}#BXpHL9laQX3{Js)@WmOB_Hq;wrpT5dZiKbn`iXv2OM==Q^jv`1NF5X z(}3svoFjz%Eni=v;f>m$V6LuGWQL?&`3+W<%Q9QJA~eKZ2{rSt6K}yJCp{^Q*S#3~ zJ*3QE3~_z_WJI=TIDj8!3_4zK_PUCqYXDI-6_^QI+osB6h0ABdYE?V#OMH_^Iag5? zuaIzV)rxzvgmr=aSjeTeEXe{!=J*xqd2?=Q;FV=nJW##qcBe)FhYyRvL$p!zus-ij zUTyJ9*)WG23+x|0*>rgM?_CvNPky^5IzcHR5t6~udqlGlM_XetZ*Z|GTiYfwdD1`E z>OmF;gv$H+)2ja~a~e(FpV=Az42}%C17~YI*J_=VE*5|O8h!2C54*3gzc#^;nIZuH z{URjOKU=Fb#L>N={?=rtG&D{GzwE77V&HVF@ zl%A8X@lyR4Zp^NduqxZMs^Ra_Fzp(~=Z&O`WN#c-&LAuI+k}jMJxA^Dw*Sg=|JMcj z7j9Hxi*?A+1y$$^HrBwpAfcdYHvf1CpUYSL`j&-PX&{7;+o zudn|f^o4(VV+z#%!M(OwX8tbe{v`)Xc)gfWTxi<2l?l)rmo_2x-(`mUD)X<7`|o=7 z|GMKBJ9arM_H9sfXF1cnC&C|3-j-+*hkVK8LgiXcP{-#;s%DAp<~l zg2W`FZV2<;f=ga~3=#;cvR*E>K@&#OCH$blGl@M78f6>T1j zw84p2bt0$d7oLBxE$!!x1#k180X-d}ua+{VeY_oxxlKT}ts&^Dc{8>&jT14CaQ9Fs z#8DW@_qf@DIx{ep`ChyMg^LwyM7iGF)+>oQRU)ux6_YI*~TQ?!v=O{NiW(ce+vm&6PsecgFgJXp> zCvX}l5N3?m@}{-A&I^)0o0&8PQ>^&9@E$#~j!L=+RBafz4EVQCzbuJZ5tME2;qURx z)+Cf?jN=#vw^;?&D*H*mE-lxdLgrg6vIl+;nf8!Q%oXrBx|cFZAA~|?>A-oq@JGc4 zwLH26A`MB?9gC(fFDARPCd+Iqlz$Tct>)HVb~)EZEOxhuZ(A%<4$<%d-k-WWjO~X*IL+^rW?4)QaRd6xg7N6i#GdIq4Iu! zdNnii4nAKDPC42t<5=<#CZ?Xtr!}$A{zVpr|N4-icH6I~&)HS|KMKVB^ya`f_a z#)*=6kBAoiE!Krk25l-X>q18p1$o4ZI$R8NY|M_|d-Q>?A@J*wc8X)_%F!5BKiI-H zvDPvhyhn2_fE9aKRa@wzy2W+3vl^cv|MoRt-BNJ0UgC@y@}fhts6-vrUPJn`5cJ;H z!-(FICEI32~EeUEp<`SoO@^APQ`B9eS=bh;O}bBP+g#%Um;zoq)e5ND5Iu@JmjWFVy1{V^6Y%7-=3dbE05P z@#tKk730c*_QpURCyk0Q$O`O+!J`#@mI0hh%EVfwPW5ncNDgrWN%C2z>nOdmbbXVL zi<Z-clfgf&Ft4(?XBlFv~>`MJo4e@_2u`M}XjKtn{%sY)$N~F6Z#+AZ( zq{9fRpC!;NfQ!Sjc*i^*rQKWdeX5egL=#|agnk3edR^S?ZdAT|tKoNb6PV)2?@_+h zeupp}E;*d+qvUyY=5ti|Od{QGfxBEG1Dv~?XoWNBkG+xp*U~AS_HQ1L8T=IP&wqbd z?7u$A_@|2He=XgA-KaVwr1+N=`hU43|BGS%=fY6;cYb0G@Y=N#jm@xecL0{@by`1jFC{Ocd{zd|vY`Aw2WCj=0d zebv&NUbg*PB&^aW>Y1MY#8~?3ch!BSo?dnJig`trrkH83EKf$FknAh5up?DFix#2n zFw9YaHLR$bB2^yF_E^5pb)c*=siR<_YA2Tyeo0rieR1^hBXQDe9|%l29S5-B%2uQ! z9x*3=?}_Q$D>Gbs{N(Mg25n$pwSihvbV2jT88uXTA?td2T1eOmxO`mybQSdzQY*q}wB525D|bz5pr*(uk7c4vVIa zwdfhohq<$PJ`&@_oh2LpGQiFKSwr>_uySGlL6oN-H8*qG#ra{72=`s|^sN0MP(Lom z2WNM{M4W}JL~_?p4aW86CjmU>vt)qCqV_P^@%K|`vn2v@j+&#!D+ z(BJ2_q)WI7KTI`5dXDi-R-i{;)AMxW z1=^5~X@K&~sS?s?O|}}Zt)s=825NCQ2J#cu;~MgZ;w5)#5s?mfwszR$TYj9c!4D#t z5;#Gt(P!mz<(X(BT}yhAcQdpH~yTFl)(f*OsZ6DO=ZIN@|UB{gSaGByH){ z$mq=?>q%vg0e}W7=;AqXQI6P1{riM#n!&JzHge1eISeaD45gFbnS0q4?Vbb2N6Qep zv@)8j=yCC{w*a6NhHTM_aNpNdPxJ|wRuQvn-Ju$27_d<_4xT&&hZfz);8Xl&-b!f3Te_ zuoJYWV6(a)oEjV8K#kK-cE8S4I-zTN9QPC*1Ug=UZO5d*TA9F^mEn|TY(0Bv@C8#i zPDl(o54-3WFbhl75ibdCGijZ{IrN7*Dwq8Ts&@IR=oSP2`zEfyf2XYZ$kYWEX{b zTKN3%y~FRD1#h?R4H&UHbGQlb9p*0;jOeKGfET`lDVP6#tG+g+lMADEv1)2b1Of3> zSECm`Dz&jJ1)_E}l2(YK?biD3Z;vp!#Mx z=ATS6k0|!auxBFFBv;XTt65Q-`r0^^N+cEFcR4AWE`N!fKW$fjK^zX*+b`fkgJ2Kz z%`qy4W{-0_1RKAIDoIp;qCH9UnB0X4MZO!_rp`ItzLk_TXb9l93}#46R6x zOT5OKFTbu8`b3Hci-2|*I(7~!6vzX=0-o|+IN($~AVfFeX!`YM9u6L8QF}XI4-yN@ zezORFT?kx!xbkzIUH17`%Ao_ZpNIczo9+K^6a+_lTDIoO;pG`~4V&@tW`W&~hKB$j z16Ji$%zYLC`MFDutV8bWSVe(ug{t*{&CLaRDC_G}`ZV)BVVJN2cYNrqD80U%QcIFY~3cD$=p6QGGWuI$Tg}CyJbhWB8YyjjrOwe-$RmWUTJ@3*S2OZ zPCmz+k*f=Xx|9;sTrV#98hGRp_C9&<)8jZNN+`)!66uPuJi!@{pdb{rZZWo)SqCLl zV+|$#{QB*!M>9;2!I2y@%(>_!Z9GDuFlY=Mka--BUlIe*F+XjxcVl5|Fov>|=-mP# zV6gXGM60tE7lOyf;})+by_TT|0uwP_XV^z*;%)OMv>I6;Gx8)-Vw73=*P3B8cMT|? zSmse4hGKS%0&AauH^C?6>N@SAjBY)CIjqfzaN#b*09>(0b6TTA$l`9JH^9n41*d3} z>;Xdw6)9-1T6xaLRvzeZ;_7HM3eRD3tZ2Vq?9*E zP9q~O-z5vm1`-Iq;q2uGvg6HaawmtKe`aVD`ZyDFN|!y@O90TY=?bVaYH>Wg9&{L=gohwqfyp{` z?JXCKGjb>W{b9`FCO4G%(7@zltr{j28982>m0758U!E6xh8+d0hK38kvGXKh9!8ux zXlIDKnOwuY_HqD!WkoU)1muA@jgqLc;q}m%rwNn(?sr%bzoHoqC^!l5#i>c*kFNG_ z-FEe|-N8PUhXs6RxcKF*hU>S@1RIW#~*BRU%~ zI=;5MJbZm$lcW91#i8_SgE_a2#UIh9D_+o`x~tM0+1hj=EZH05V<3Pt+3E6sNpl;q>$9azBr z6hzXxNKORm@uB;ylCPKXK8d(^s3*6P=oIvDO#&Um_s-z&0uTGf;!9DH@2(# zn@~Yrtw)0Ct&u`@byKXS)SYnjF{J5u$l}*_Py>Y8MfmRlV9>k~DwIO&jtgg_@a5bT zto)|-wc8ELu8g(fbRw8p=WGTfW^_#O40hz&Gj|Muro-bQN>_q*XR@EmXLE$?CGzQB zd6>>h4eZ8r`OMf%;{bFTREr`WGzKXfhfVS|>_&-Lr|<*56Pdi{J3}c_mbW@X=#}VJ zzyJqCTY~{*r%{UDy6}0mf)A|M!#t4P5FquPsQ!RX^cvuWk#u&pHiQaIO}0~1-`1CV z^_nAdO)kAE*Q|SkM)g(H_~-I+zy5KBV1U{2<@0TpPsC@k*lJBs5@lI9E7U=L;AhUZ zlnMUPZy98DEu!!YB2SX%7BN+cdhW`y*UvuAcsq=#(wd^@wKOQL+c|H`G)$|4l~0 zQ;JZki}Y{Ok5MoW6%TY>?VVZ=gBfa9;81zF1&@+J&>gif|I4Rnv=S7jH*ghz}oT@9q8;zR&_%inJ`Prf?mqzp7h z|Hg0sYdvz@i@vZj;YTDQbWPsR!Lo^n5io#CKDamc=Axq9N$Wm8X=l~Me{5dcL~%6Y zvkPs{74SGxgpO}adWQeV2*UT;Rt+tk9z@cv2emLG_7xj^j0Yl|GS0m>kadHwF1EViA6iz-^ zy&C9ooX#gTUX1Ly43%K)Pa8z)eBInkS!;`ID*^`lJ`LkY=^=`q^*u3-g4&3~)D=i1 z_F1Lu3#H{qND@;I(&J#B5`?ar@6KZLopYDVb13q1ltg}Xv-*eu%to&~CCrz$g+yz# zC5elu{Rb+J*s2Y*QL%v%H)m?2l5{$)GnSXs?wc5BfxaAq@|+38=sR=U7gIGV`{3$> z{`Vtbw!kdem~t9Zw#X@|)X%j!^s3xA#y}dIvXkG|2qt$>q+zKXk~bHgvROD%Mi>KR zPT>XWmm9Nbv>pPfnT86NpMXO&K9jzDMr2H6LzD}Pd z>I_cW4)R-mR$B6|oz;iw&6-#A#{!plg`K6ik#XPpCyY05cYd7?5{(0FCn_lauv)$~ z0jM@b)#xgH(`OM?^7XrbbAAdG(PCdbGh=c2Y7(=qc>VpW0A(^@tU*-)W@4AJdA;>j z%oA>C`trrh302|=VpgqRM@U{UB4sqE zQFSA_PxGbdaS#nzcG#N>r}P6U$1IaIUuez;o};09oDF}$0XdN`1}8tTf0SyGyBqU9jOWXW8pV_?oljg!Vw&?9CQe^}>JpB!~TnK9Vd#cFd zfZ}p)-0d1gLznngH?VJR$Vjo@N57Y)AtxEyH^h5r=Dg_o9j!y^E?sMO+daQ;VS4TT zvdNH$=9LkA$`<4~C!$nNC_!OUn3apem8oz{%9Y0_V-0+z+QhL&?=dv|{$$41CJEIO(#<_}ka0B|n>Is^R-eKk?-FXkbh@4>@;a{i= zj01V+$|Wj0W>zj;yE?IK{kRRSF-agAutvID+-~P$mOOgq2sV&!LRrJ_B1p%taJ`*B z@Oz02tu;9UD2wa9$Dv^4E(W^jrume418Vucm6g#24%TNbK{v)^oG`me7G%TIdM10D z!tl~dULTo##;dEEFc))Bg3SQ8_}Sbz^V0hr{zO2CZ-|qD%E7jQyiTx=f?3{Xv#sRi zvtf6yk|n($66e=@&`EY%&6w;Q5tFa`C${nF^Rw?*ZKac`s9)S>B>MYyH(l4i+3z8q zu8_G_R;Z&REn*@TwL-{Xk$?cBdpO4M> zr}zI4U-vIuuH0!A(X2`P^&sERVN)y@|_%E(I6Xo1n|gO*lrjh~jD7h?a}sHs0|Y7p_WY;cwr}HaD);?(pp-3xdh9dwTFbp z@+XT>@g7ZJE*>=DgwZmN^TBYmf|&V$d@RLMi{%~BEr1hh-#}`6e_i8gpY{qqd%yHr zw8~IT57I7?1Z{0w0Iar2>4LO1YN8*%QetDaEp*i$Ew5vAs=$M3o!l&S~blDdxnbYU$w-Ep*wu zf5g~kNxXgg+Lz=Nk{pD=3Q`pW6T`H=yeOix~Fh15Zc}V%t6&cB`J z_kBVz9mEdJ{HZn6YyVY|^bb9K?fz!pSOfR&C$cb62PYc^kBrkPVN*<>F3;Sl&-y9p z9RJ*_|4}l25tE!RxZt8LFy382QM_=IX(G+~Gm*}I_6V=BnV=XJa%3NMtS*5pFk@zZ zJf4`rNEs4PW)+U7w#R6Mx&$wTrRC|tjL|Ie<(K81Qg_>yzWpHDk`^FYKqTcVBjLy;FA2zR?=5cnAh7}7s#wtPCj7Gw{$t& zwd`kF8dRu-f@ffJ%uR?ii0Rz1DeM7$)HLDEclh8C{G!LLK_QE}O$gm&XDpCUC(5CK zfOR^#)IBXG)F^#S%G8)_V&ZX?Q4rth%tM;e7`|5TD;z0FH0$>&)zU(9orVj~zX-9E z?IogCWvC%UB#j~gOczZ;(LtmsdDIFJC9xEL*J&8_kuCOR*oKs3mhNhtc#596aG>Ss zA4H7#=REzh4r%75xzRKBSyQlAE)3nykt*NwCR!?G!28`|UKt2OO}evf-NBDrkJx>WEYDo;^m&R zC_)RU4`Y%wceP+j%IeT%gTnUZ7b4)m9DN$JoUN-ZK4*S4QBHRo%lon71Lo^Yua{@e zq~SnbUXtwfN7Txhs!xbGyn9cw;rM=%C%X2AiKsy1M0T(S-P&DvNTdAl)WZ#8xj*TL zfnVBfN#X&zZf=H*E5^+}R6~uPSyf3a6OOe4hqoWJ7@IRhCw#bbg+6_s#QQ*~0hpOf z`_IiD4ny$CnHR;%CtYn3hw+$;UeQY!-nZ3Il+W{EEfmGK7&mFV$OoI(Ja52%5Sf7E zse*b+2MQcr&yHL$@-Jj5!?IvTsM1_CT0oZzQU(t`PEROyE05XS!#qJ?`EgwUI>Fxq zl;WbHpa_;L+cjh?Hsxi3xx(!UQVy4(F^7Hc0{B4sitfz8bD_LV7`HKK?}rq|!fvgf zGUL~G@%|L>C0;*=+eoQY=m*-b^yxK4T(9d(A9e|CMi`k87o9UxP<;i+6Y0O-LT7%e z1m~X*N%;57G5%pd|5sCzjI1@czc^(7AVm9H#Px47mlKc4UwyGb%XmpIQ1|BwfK+M5 ze=jp1HYg0FK~nBjO-ag@K^`LQ&X7CcCtce<-k8%s zv3j0U6gXUcy~&zTF@B#p<4f-L<@GNv)=fulsk3~(5>L8?D}c*{=3u1N*KAQ|n#&UJ zp(Ly<`|Z9)QpUJe?i1!O*bXGEoX@3TZb4qlsH-|26b5GWS72`nZlUex0;`SlC($_u z-*$4Fv&-k9UWh6E`>VZ9H*3T56Kfhzyw98sb!K=wM}O&^{R@pEox0zW@HnPSut3}H ze!hG2(FIy^jtT+NUFTK(;#mawgbTPaMq9k{ zwoC8btq1LQu-{(P-qUbBVs0Sp=6rr59 z?%6+GYIPE5eRur?9R$?_!tehfll%M5&Q~>s<;d{xsMfwh<`8~7wEL~>7^U>t=Xwvz z)T4AN8aqPXVX1*Q_!9v)LVe7cNsLM7AZ;%bF~N)uzyNXz8{m z8z@jTze;&=S-g_!c*GlRs#As5n2*N`Ym~ThXK)nVHHxH8C}ML9xzcuUwIIpCIzZy` zNHn`SPW-aQKg zuChoYVY!*7zO8-xb9i`CrSs)-X;uNluaeXd?{WgoPB68T>OKm zbmKZy@Q$6%^_x+;T_Y`EQs^cx?y2_oqgUM3PseaJKvF>U0<2t16tn-_Dl5Bh+WBf_#G@}>o))|Sw1wKkw58gaR=r?a2rFPT20y|2PVO9S ztmNIUM5&kTeQmREFinJ1hX}xK9As@)3r5v$*){K~ft!c(gLh=_BFs=1Gy5w<%<|k3 z&Q_2`3FHP4*_7xzr(;mOQu&HDNSc1ocm}^LVuX$xFD))BQT*~GYfVN4J(9LE&D1X@ zZoRnbbZO!=-?tQ=8Fev4^ALmzebmHEqs~xUU`<^QYpZ11MW9bF!n5W-+Gmby{Xgwp zc|6qJzgP5FA}M5vQAkLVqHL2qC`)4}dns$EEE&s8ku^*RA&oU;-?N155n?Ra*GNo^ z&@eOK?xA{~+kJlbb?^QCy3hUR{&SpjzF*%t-*e9QbI#{;-k_< zwPuFRLuvhm<+9h&C%rvIDDPTUAiV0H2R>-Nc*t7uLyOpkE1MyLXfuUnH$R>{m3!XA zRSq9f-i|p}>qfh>ntx?^?w&V%qVC~`b&<%uG_m`G-=b@zduxHjg}T*9-F9@P4Ctmp^CjK>$1OWKCO^18VQw6VAMprmf$f{~ z(i9oRpPF)i5fpt6KKyWPb5Bk52NW%lEtz<;$t#zwuavD}mm8(gW)QJ$uTyJiSYLk^ z>8*Km4R(|)JK!)0zaM`o$f~lB;iGhRD`Rbi(qe7Xmch;l#Jc0ySti;|MP+$&dztw6 zR4c&c{qY{q=y(VcX9QnKa1)-2H9hcJG$bp&G0MpE&(J?kYe-Wb#N zCg%R|2;0FVt4GeyZY$)7VhN{M>)N_|6HYuVd z%NC(I;2^F^;C9M*^Ig;7r~rdc=RRc==H)F>5YxKbYl%Y=Fq!HSaT9;iC?fnQ=P4q< zj*^3B@i0*)m_NNynoaj99|}XTAjcaJLsnV z`wPtTsD?vp1_wh{5-rx9x-&+GRLYUIEe~Vqip6nZX{b_+bO4{zmBhE3Cr04u$l3H| zS&dk+XCKR@T8cV-^(j)=IRG^yOD;WFtexSWG7)S+jI|$te4k~b>(6?@HnRb0=A69yEuL1A=3sZu{4zO(@7%a*g{+`m$J zHL?S?w#9L>GW9x=pgB*gLlBIRZ?(G)hWc(Q#8OobBDJ|F@8gK4XR9sRO>MWetkmr_Qtk{F3`U z)sx5UGYC$#xz`-vY~F0iP9}+{q05HQW#cGW8{AAQESQaP^JQ4gosmNd!JpA0Z$Q*J z55tQiLj8P^iooL%|N7A!?tLpP4B1>xx-cwkTMbWEm*izP8DNlvre?6D4+hsDA@i92 z_n515u%tX8fRv>=BF}vx(m?K5tY!&%T=WTawV-+_beyGTYSgZOAKKL?{20vT^9$e| z^t=Y|qB~!6v@4?(EM)Kmf>QJNP1DPlYrm)trnU?$fw&&Y%S(&zZT5?`1iK-RrwNJe zdi*Z#i~9yk6GHL{_%T(T0@x|&j+20eyaCF?= zz&@t(Abof+i^Dn$bq9EcVcv`f=O%cmdnpgosQLBoK}?%Rq=ytq2-a?8h!sf0iK z&7|tA!)tGS!k30h*ACubn#z)o619($X+NqUCM1@O42STQZy2fCR8hXw!;Kakr%cX< z%xhoFY)j<^e!(r+EKc}cvO|b8mR&*Yy5+@VuE8D~l8#P>qcy93!?T)1NmD-6q8cNs2v;cVx);Y_mPyIjr{(xNMXV zZBNND@>%CST$7<)^WA{?qo3$9(I4^b5!NWWl>1&+Y*+;K>c{cmmQv5r(h_zMd}!#^ z!M!R{X}9?FwLefz7__CN_$xD{CQ(xvroN()DiB~N2x#-ww{ZFE^WNPPEhcvHy9#j9 zVoiMY)N6Ea?OUASw-{^c-+Xs;nzoLDzeiD%Nxby4f^jtE@zi;hW-6}`t6+L=jvb$b z!vzFxSkk_D=7=RNZ0Je>!XI*0f(^6@>223&m!X&P->VFQiBucS{m<0vn+B2$b~9}( z=(nOvEepng@LwwEByWKW9ahxoc~_&@-oVeoGGfn+*uo~c;n!wcXh6v%74uu zw#Q2szcreAq&Yx+s_7bRbYt1 zNArKIFC<@d6b|5g7eJ@>WKSFb(;3E)oqCQ7;#^1dm|i>K8PiqI5k(MXdYDGTG$M85 z!qitPS|j_LmjWz~Dc??CWS2Lvy$oiTocbZDA3e+ybmkS&3fD-U;~`w zM!Y0ox<-ZyuonRcnP!a>GshQMR!`3W$NPGD)l1b}*!xa{0!kH*Nq%(dFHp-{WM`1RcZ&Ho2XLik3(T)hpU4M0LIKcirDW-zDS4-#uV6` z%cZPWSyEl5kj$!(<_2% zebh80WXHK0Ii|RYZ?Y9?g8f#DV6$tW%<^x9JhG3OgDjG>v!_8IuUf?3caQ*PR=9&8 z`>K7Q$=G>f1A4@xGlFhkWzC%)XA-wyF+wrLXG=FN(I|c)BLD$ZfGVVB7nWn3ZvuP+ zXoNQPkthM8f%wb(VeFT~?vVQBI~F`-HfOB3_6uM`$un@01af4DwnFWVmqKEzp@2ZP z3p=&sKiSznp8>ABzk#pvi86d%$8__z7WI^J0x;*(WPaKeG5ztzOob^~pL1+cZiHHO z4N5HH-ok`{7gJ^~#>!oG8ORY758U|UDnPI{lzCa`)>ieJx@mbo?wU9`PF%bE zpg}_Dq}nxw#9gj3&aVLYnaKxv%d_G6T)Pqx@W`#o?|x zX0eo^xG&Z%vpaIy!%%b{7rkeJan*y|am%>22~T}#B&JwBQ%zQpx3{ZG3VzPPFJYRt z5y9En|CF_dYn1+#gDvBy+9g@0?6tbhK5=}a&RU4^@2aE+k#Me=>%{13a3I|e@!~W@ z0AAkQA-}J6NZ|$B>A<>i4r0o@Gx6KG9eD&Ex%@HM}GSCo) z7~G_E@EYkJa>~r4&8k-}0EtT6hShtj215IYy7eo~Z|4_~?kAL+=9Y|LS`sCwoq5V> z!-H)}e0L^3IXRSdLp&Z{4J*x7#U=^&e2-LYbozjBa|}!Cm*8P&k-qH(FR%T7AeDaM z8ktpeY|P|(Z>UR?lyXA*jmn5{k7upLNXJ+mi7wX6Vx&W$sijqj-sS4jhP)FJO(Ms} zj3);;IHqF1HTUN~f8#p-Z8KpHpx%Etu54v8#|dPG)D3+V0J5K4gSGt#R^gP}SNW5b z_J^@m6uZVmM9X|P#isM@+IF(}hQ|DnZjm_%bAQ67^ZVddpZEJ%EdQBg>)Yr4jJo^% zTd3$C{6jyATzRoJx$}lH*2#47J+qPrGrj!Cn44Z)uH6F5)jG##uK0?`t0Kz!TsIcQ z5APf9^cPSXL1SKe4`$l&9w#1{lI|@jb9l*chruksD%z!9jdt|bQ|^^dqOpdk zSdHF2JIbnVCSlhtQc;0JWj9Kz)C+c?MG&7VT4uZk(ufXIcLK@hgSkg`?{0YI`~EHs zAle;e{@|1S_Fil2ys`e^8t3;u($`d>b8_Sop1Npd6`-nBM^SwK+XXCFkZ-%7eaA;blUJ*6onzCHRCAStP-mWx1PFUI_@r zhm8Q+SBO2-$;$%s(&_K&u?>W9Ngh|bs=>Z=T!}1vU?MP}#RL!dvA*3}%DlKXky%5I zPa9tv$%NE|7bdG%df$u#Q`~|c!TZ2+2^zUZ4mWk2VR+T6t_er&2RARuFC_L^L&SThC0PX`p1s)1NRzM)cG6{5yr#* zymzmbS(f__!HZhA#s{5LY`iNF1C-9mD6JBH4Vn5@gKBn>@~l z-f0hmo7Iv+2+7a~Kqb;)^OefpTaREt_EL1Qp}rF?aU;ny!1*ym)7K%pj_hAk$CMJW zjkZP7#}AFlg)N#D`fc<^csL*V zAL5x`A!uy9%u0X}z+%G=1z7@>=(qi=z!i$2ew?Ohwmc^go}q?!#rUIGd)$kS5(ZTX zV^YADa>t({T2o%;+q27eh-1?KH}*5VBKdC_y7l$6o+s6u@rR*(>LAlTNv$ch~V$4p>9_1 z$Dc&r&yw1c(Nib538p zdQ-o<_hi8;-&)#r#&n~d%vxSJ!H}~lw&}`|(j3=rJycC*n}I}$)RP@{GZo$GKD_f4 z?;h0bM32bjPu!Fj<^9}HhKqc=fA`adXmWNZS!vnj_dd=!oPf_s_c?ne!hUE;n|RR6 zkWp?w0bOUYLR}lb(h0AOi3-+Y-kcUfC!JPWcsTY{LfA1WGB1`Y`K zz(!=ClsKQEpfH#+s=P4MR)m%>t#T$Q5)a=%Vu!TQ1L~IORrb>|#PC;@8`*0X%el5F zNe>-UXOb&?sg4=))ijQpM&Gp#WyS~Zog?PVLLqiS1E)6l>)*IM{eZ5|h@C3;n+@HO zRrv%2FfRcl&W&)c8r~eWj7BP!uT+;@z_P|BAT#!)P$VIg1!_S1Bbb}Se>XgXNM9-I}`<>IlBl?6}%yFvZ>iu7-sGOJ6okJi-^Y{wq^qg9L+ZlJUyg=Xv`O?_Gu zcdUjo_u|l#{KWhmbW5&(M^X8g8!-|at?*nJpl&(gfq~9%j>LQz)tS?|TKnaVmp^RK z6NH7DZ}S^`5BXw{l|YG>E!>y;+im z;XdU8Cp^p|pnvx*(qk*c7d?iBQG&R-?jA2q*F zq=|55tUP9_0LVLQY@4Oj9DjduJX-kf@Dq$N29I6sTFZoh!AS$Cg5Qd%+m-)%nyFEN zeKSn7PChw{mUNzszuz85?x+p0cP>NY;Qh}?HWW$9_X1|S>hDS81iRum%^r7o;{+-` z^NSX9F2!GqRk(KD-Aev5f@A}8S<9dlV=6Xr&|u35#df=ye@|-1G^@xBH&#MERO#w} zIChPtcr9}>p{=X^390vH$9tRiojxDWSg#bX%qgsi55woN3p$iyC=M$9R#4rp`g>9h zX%K+ZMiFuVvlM>O-y5;?BCL^Yu1*Z)d_CL+ zDvXvG7fr9|2nIQkHqU?=uKJhDSbw*J3AK!NI)xu+2dPn()=3d!f~0jVtWPSut;nf_ znb~{}&-EMj5WLY+Yy2^1jymQ(L{-uGm5S;23@C0y4g1>P(1Gb}<=~Fh+oB@Qfi-)u zOSTeOU#YGl4{V&a(FBZ*x0$2VUx58`G4c>(o#G?%DzKdzU={Q3_i>`wiOManGdeie z4jf0vWd_zQQClUb_xPat(e)4Qq^Ml>M=i|i(gI4%=>&%qA5;&zJ`LfkKy6;>HtgdJ z+tdjYMZi{Gbx}%Atr0IzvMpHM95;CeMca$}VVP4FCf6TszFZvd&YIT51(GXm7WnlD z^Sb~l_bq>}M@x318j6)EOsezz(SL>Ry%4_Pg4vSV3z zdPa9Z`gyVR0CLWz%){of^VtDQM!GtfagTa**!i?WVD~nmTl0OeEw*Pu;`U7F{!5D6 zH+RLVST@}AA7p+^8}#;+245u*6@Sk+`0ZEhIR!rpFqd=S;{z^wzoy1F%Ys-X7AMb< zZiNqK{dm2EZ8`ZzQQ;R&@n7{Ehf$~VRT2^5B?FZs{_a-%Ja+kR6%32bDl$E}W4*hJ zlUj`RtA_5myK*e3m3wI&@ATubL;W;zvA<{``0pt&_Iu%Pd2yt@5l`yjsCJz?JSXc@;}}}o*7U7${4@F2M)W^>f0Zx}%giQz zl~B;v5veMm-_I#)-%Vwu(dS_Jo~_y%=|7WSJ?7i<=K{a>lcRIFd|@g#Q=gXjp609% z_w2!g*`@PG@+;@rpU*ng7+M$2$%@-2xl`|&uEvEo^x6@ZwmLpz>pgYLe$Dsv4|@M$ z%0oqMzYD;*H}h56(X_pKmOb~is2ENNpFc{qi-R?pm1<|`ulk(-!O#Cum1SpV`ybW# UpH%ffcHjS>`LBB*|Lfqt0WaZOjsO4v literal 0 HcmV?d00001 diff --git a/vignettes/articles/gmm_models/eei.jpg b/vignettes/articles/gmm_models/eei.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da8a6a1cbfe2d83f37e4c3e1a41404d2d89fb18b GIT binary patch literal 46980 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

cSx+9u+DP3?Bb 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 amns11KrAe9eaci{|D!(OpH=TN(ehs_rSMDu literal 0 HcmV?d00001 diff --git a/vignettes/articles/gmm_models/eve.jpg b/vignettes/articles/gmm_models/eve.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f304840bc13b78b9795220f5351c6c1ed016e74 GIT binary patch literal 51770 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 literal 0 HcmV?d00001 diff --git a/vignettes/articles/gmm_models/evi.jpg b/vignettes/articles/gmm_models/evi.jpg new file mode 100644 index 0000000000000000000000000000000000000000..460b9dfbce76af3754650a3260a622d375dab9f7 GIT binary patch literal 46695 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�S17Z=ypWphOp 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ⅅ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 z�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 P>tgBn|5Fd(KXv>Y9{KJM literal 0 HcmV?d00001 diff --git a/vignettes/articles/gmm_models/vei.jpg b/vignettes/articles/gmm_models/vei.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fb96067af93d23d41a06eb2e9d3dfc7e19210ad9 GIT binary patch literal 46214 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 KM?whvzX0MB|fb=3A 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 literal 0 HcmV?d00001 From 342ca2703e34ddafc6498c287d175f724ed5bd16 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:54:30 -0700 Subject: [PATCH 21/44] added redundant gmm model specification warnings --- R/gm_clust.R | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/R/gm_clust.R b/R/gm_clust.R index 1301ae9..907836c 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -151,6 +151,10 @@ check_args.gm_clust <- function(object) { rlang::abort("The number of clusters should be > 0.") } + if (length(args$num_clusters) > 1) { + rlang::abort("The number of clusters should be a single number.") + } + if (all(!is.logical(args$circular))) { rlang::abort("The circular cluster shape argument should be TRUE or FALSE.") } @@ -247,6 +251,27 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { } } + if (circular) { + if (!zero_covariance) { + warning("circular = TRUE so zero_covariance = FALSE has no effect on the fitted model specification") + } + if (!shared_orientation) { + warning("circular = TRUE so shared_orientation = FALSE has no effect on the fitted model specification") + } + if (!shared_shape) { + warning("circular = TRUE so shared_shape = FALSE has no effect on the fitted model specification") + } + + } else { + if (zero_covariance) { + if (!shared_orientation) { + warning("zero_covariance = TRUE so shared_orientation = FALSE has no effect on the fitted model specification") + } + } + } + + + model_name <- mclust_helper(circular, zero_covariance, shared_orientation, From 26ca1e906a7887755617f0045692d45336ada63b Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Thu, 12 Jun 2025 09:55:26 -0700 Subject: [PATCH 22/44] fix tiny error in hier_clust that makes tests fail --- R/predict_helpers.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/predict_helpers.R b/R/predict_helpers.R index d2541e9..2c8242e 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -183,7 +183,7 @@ make_predictions_w_outliers <- function(x, prefix, n_clusters) { } pred_clusts <- unique(clusters$.cluster)[pred_clusts_num] - pred_clust + pred_clusts } .db_clust_predict_dbscan <- function(object, new_data, prefix = "Cluster_") { From 207185d17e09817c20e372a48cd42e072591df96 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Thu, 12 Jun 2025 09:56:49 -0700 Subject: [PATCH 23/44] tests/documentation updates --- man/details_db_clust_dbscan.Rd | 65 +++++++++++++++++++++++++ man/details_gm_clust_mclust.Rd | 78 +++++++++++++++++++++++++++++ man/rmd/db_clust_dbscan.md | 62 +++++++++++++++++++++++ man/rmd/gm_clust_mclust.md | 81 +++++++++++++++++++++++++++++++ man/set_args.cluster_spec.Rd | 2 +- man/set_engine.cluster_spec.Rd | 2 +- man/set_mode.cluster_spec.Rd | 2 +- tests/testthat/_snaps/db_clust.md | 4 +- tidyclust.Rproj | 1 - 9 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 man/rmd/db_clust_dbscan.md create mode 100644 man/rmd/gm_clust_mclust.md diff --git a/man/details_db_clust_dbscan.Rd b/man/details_db_clust_dbscan.Rd index 3ac9204..97fd9c5 100644 --- a/man/details_db_clust_dbscan.Rd +++ b/man/details_db_clust_dbscan.Rd @@ -6,4 +6,69 @@ \description{ \code{\link[=db_clust]{db_clust()}} creates DBSCAN model. } +\details{ +For this engine, there is a single mode: partition +\subsection{Tuning Parameters}{ + +This model has 2 tuning parameters: +\itemize{ +\item \code{radius}: Radius (type: double, default: no default) +\item \code{min_points}: Min Points (type: integer, default: no_default) +} +} + +\subsection{Translation from tidyclust to the original package (partition)}{ + +\if{html}{\out{

}} +} + +\subsection{Preprocessing requirements}{ + +Factor/categorical predictors need to be converted to numeric values +(e.g., dummy or indicator variables) for this engine. When using the +formula method via , tidyclust will convert factor columns to +indicators. + +Predictors should have the same scale. One way to achieve this is to +center and scale each so that each predictor has mean zero and a +variance of one. +} + +\subsection{References}{ +\itemize{ +\item Ester, M., Kriegel, H.-P., Sander, J., & Xu, X. (1996). A +Density-Based Algorithm for Discovering Clusters in Large Spatial +Databases with Noise. +\item Hahsler, M., Piekenbrock, M., & Doran, D. (2019a). Dbscan : Fast +Density-Based Clustering with r. Journal of Statistical Software, +91(1). \url{https://doi.org/10.18637/jss.v091.i01} +\item Hahsler, M., Piekenbrock, M., & Doran, D. (2019b). dbscan: Fast +density-based clustering with R. Journal of Statistical Software, +91(1), 1–30. \url{https://doi.org/10.18637/jss.v091}. i01 +\item Kriegel, H., Kröger, P., Sander, J., & Zimek, A. (2011). Density-based +clustering. WIREs Data Mining and Knowledge Discovery, 1(3), 231–240. +\url{https://doi.org/10.1002/widm}. 30 +\item Tran, T. N., Drab, K., & Daszykowski, M. (2013). Revised DBSCAN +algorithm to cluster data with dense adjacent clusters. Chemometrics +and Intelligent Laboratory Systems, 49 120, 92–96. +\url{https://doi.org/10.1016/j.chemolab.2012.11.006} +} +} +} \keyword{internal} diff --git a/man/details_gm_clust_mclust.Rd b/man/details_gm_clust_mclust.Rd index 385a563..a662e3a 100644 --- a/man/details_gm_clust_mclust.Rd +++ b/man/details_gm_clust_mclust.Rd @@ -6,4 +6,82 @@ \description{ \code{\link[=gm_clust]{gm_clust()}} creates GMM model. } +\details{ +For this engine, there is a single mode: partition +\subsection{Tuning Parameters}{ + +This model has 6 tuning parameters: +\itemize{ +\item \code{num_clusters}: # Clusters (type: integer, default: no default) +\item \code{circular}: Circular cluster shapes? (type: logical, default: TRUE) +\item \code{zero_covariance}: Zero covariance between predictors? (type: logical, +default: TRUE) +\item \code{shared_orientation}: Shared orientation between clusters? (type: +logical, default: TRUE) +\item \code{shared_shape}: Shared shape between clusters? (type: logical, +default: TRUE) +\item \code{shared_size}: Shared size between clusters? (type: logical, default: +TRUE) +} +} + +\subsection{Translation from tidyclust to the original package (partition)}{ + +\if{html}{\out{
}}\preformatted{gm_clust(num_clusters = 3, circular = FALSE, zero_covariance = FALSE) \%>\% + set_engine("mclust") \%>\% + set_mode("partition") \%>\% + translate_tidyclust() + +## GMM Clustering Specification (partition) +## +## Main Arguments: +## num_clusters = 3 +## circular = FALSE +## zero_covariance = FALSE +## shared_orientation = TRUE +## shared_shape = TRUE +## shared_size = TRUE +## +## Computational engine: mclust +## +## Model fit template: +## tidyclust::.gm_clust_fit_mclust(x = missing_arg(), G = missing_arg(), +## circular = missing_arg(), zero_covariance = missing_arg(), +## shared_orientation = missing_arg(), shared_shape = missing_arg(), +## shared_size = missing_arg(), G = 3, circular = FALSE, zero_covariance = FALSE, +## shared_orientation = TRUE, shared_shape = TRUE, shared_size = TRUE) +}\if{html}{\out{
}} +} + +\subsection{Preprocessing requirements}{ + +Gaussian Mixture Models should be fit with only quantitative predictors +and without any categorical predictors. No scaling is required since the +variance-covariance matrices of the Gaussian distributions account for +the unequal variances between predictors and their covariances. +} + +\subsection{References}{ +\itemize{ +\item Banfield, J. D., & Raftery, A. E. (1993). Model-Based Gaussian and +Non-Gaussian Clustering. Biometrics, 49(3), 803. +\url{https://doi.org/10.2307/2532201} +\item Celeux, G., & Govaert, G. (1995). Gaussian parsimonious clustering +models. Pattern Recognition, 28(5), 781–793. +\url{https://doi.org/10.1016/0031-3203(94)00125-6} +\item Dempster, A. P., Laird, N. M., & Rubin, D. B. (1977). Maximum +Likelihood from Incomplete Data via the EM Algorithm. +\item McNicholas, P. D. (2016). Model-Based clustering. Journal of +Classification, 33(3), 331–373. +\url{https://doi.org/10.1007/s00357-016-9211-9} +\item Scrucca, L., Fop, M., Murphy, T., Brendan, & Raftery, A., E. (2016). +Mclust 5: Clustering, Classification and Density Estimation Using +Gaussian Finite Mixture Models. The R Journal, 8(1), 289. +\url{https://doi.org/10.32614/RJ-2016-021} +\item Scrucca, L., Fraley, C., Murphy, T. B., & Raftery, A. E. (2023). +Model-based clustering, classification, and density estimation using +mclust in R. Chapman; Hall/CRC. https: //doi.org/10.1201/9781003277965 +} +} +} \keyword{internal} diff --git a/man/rmd/db_clust_dbscan.md b/man/rmd/db_clust_dbscan.md new file mode 100644 index 0000000..e5655a4 --- /dev/null +++ b/man/rmd/db_clust_dbscan.md @@ -0,0 +1,62 @@ +For this engine, there is a single mode: partition + +## Tuning Parameters + +This model has 2 tuning parameters: + +- `radius`: Radius (type: double, default: no default) + +- `min_points`: Min Points (type: integer, default: no\_default) + +## Translation from tidyclust to the original package (partition) + + db_clust(radius = 0.5, min_points = 5)%>% + set_engine("dbscan") %>% + set_mode("partition") %>% + translate_tidyclust() + + ## DBSCAN Clustering Specification (partition) + ## + ## Main Arguments: + ## radius = 0.5 + ## min_points = 5 + ## + ## Computational engine: dbscan + ## + ## Model fit template: + ## tidyclust::.db_clust_fit_dbscan(x = missing_arg(), eps = missing_arg(), + ## minPts = missing_arg(), eps = 0.5, minPts = 5) + +## Preprocessing requirements + +Factor/categorical predictors need to be converted to numeric values +(e.g., dummy or indicator variables) for this engine. When using the +formula method via \code{\link\[=fit.cluster\_spec\]{fit()}}, tidyclust +will convert factor columns to indicators. + +Predictors should have the same scale. One way to achieve this is to +center and scale each so that each predictor has mean zero and a +variance of one. + +## References + +- Ester, M., Kriegel, H.-P., Sander, J., & Xu, X. (1996). A + Density-Based Algorithm for Discovering Clusters in Large Spatial + Databases with Noise. + +- Hahsler, M., Piekenbrock, M., & Doran, D. (2019a). Dbscan : Fast + Density-Based Clustering with r. Journal of Statistical Software, + 91(1). + +- Hahsler, M., Piekenbrock, M., & Doran, D. (2019b). dbscan: Fast + density-based clustering with R. Journal of Statistical Software, + 91(1), 1–30. . i01 + +- Kriegel, H., Kröger, P., Sander, J., & Zimek, A. (2011). + Density-based clustering. WIREs Data Mining and Knowledge Discovery, + 1(3), 231–240. . 30 + +- Tran, T. N., Drab, K., & Daszykowski, M. (2013). Revised DBSCAN + algorithm to cluster data with dense adjacent clusters. Chemometrics + and Intelligent Laboratory Systems, 49 120, 92–96. + diff --git a/man/rmd/gm_clust_mclust.md b/man/rmd/gm_clust_mclust.md new file mode 100644 index 0000000..be85739 --- /dev/null +++ b/man/rmd/gm_clust_mclust.md @@ -0,0 +1,81 @@ +For this engine, there is a single mode: partition + +## Tuning Parameters + +This model has 6 tuning parameters: + +- `num_clusters`: \# Clusters (type: integer, default: no default) + +- `circular`: Circular cluster shapes? (type: logical, default: TRUE) + +- `zero_covariance`: Zero covariance between predictors? (type: + logical, default: TRUE) + +- `shared_orientation`: Shared orientation between clusters? (type: + logical, default: TRUE) + +- `shared_shape`: Shared shape between clusters? (type: logical, + default: TRUE) + +- `shared_size`: Shared size between clusters? (type: logical, + default: TRUE) + +## Translation from tidyclust to the original package (partition) + + gm_clust(num_clusters = 3, circular = FALSE, zero_covariance = FALSE) %>% + set_engine("mclust") %>% + set_mode("partition") %>% + translate_tidyclust() + + ## GMM Clustering Specification (partition) + ## + ## Main Arguments: + ## num_clusters = 3 + ## circular = FALSE + ## zero_covariance = FALSE + ## shared_orientation = TRUE + ## shared_shape = TRUE + ## shared_size = TRUE + ## + ## Computational engine: mclust + ## + ## Model fit template: + ## tidyclust::.gm_clust_fit_mclust(x = missing_arg(), G = missing_arg(), + ## circular = missing_arg(), zero_covariance = missing_arg(), + ## shared_orientation = missing_arg(), shared_shape = missing_arg(), + ## shared_size = missing_arg(), G = 3, circular = FALSE, zero_covariance = FALSE, + ## shared_orientation = TRUE, shared_shape = TRUE, shared_size = TRUE) + +## Preprocessing requirements + +Gaussian Mixture Models should be fit with only quantitative predictors +and without any categorical predictors. No scaling is required since the +variance-covariance matrices of the Gaussian distributions account for +the unequal variances between predictors and their covariances. + +## References + +- Banfield, J. D., & Raftery, A. E. (1993). Model-Based Gaussian and + Non-Gaussian Clustering. Biometrics, 49(3), 803. + + +- Celeux, G., & Govaert, G. (1995). Gaussian parsimonious clustering + models. Pattern Recognition, 28(5), 781–793. + + +- Dempster, A. P., Laird, N. M., & Rubin, D. B. (1977). Maximum + Likelihood from Incomplete Data via the EM Algorithm. + +- McNicholas, P. D. (2016). Model-Based clustering. Journal of + Classification, 33(3), 331–373. + + +- Scrucca, L., Fop, M., Murphy, T., Brendan, & Raftery, A., E. (2016). + Mclust 5: Clustering, Classification and Density Estimation Using + Gaussian Finite Mixture Models. The R Journal, 8(1), 289. + + +- Scrucca, L., Fraley, C., Murphy, T. B., & Raftery, A. E. (2023). + Model-based clustering, classification, and density estimation using + mclust in R. Chapman; Hall/CRC. https: + //doi.org/10.1201/9781003277965 diff --git a/man/set_args.cluster_spec.Rd b/man/set_args.cluster_spec.Rd index d36e8a9..a9143d2 100644 --- a/man/set_args.cluster_spec.Rd +++ b/man/set_args.cluster_spec.Rd @@ -7,7 +7,7 @@ \method{set_args}{cluster_spec}(object, ...) } \arguments{ -\item{object}{A \link[parsnip:model_spec]{model specification}.} +\item{object}{A model specification.} \item{...}{One or more named model arguments.} } diff --git a/man/set_engine.cluster_spec.Rd b/man/set_engine.cluster_spec.Rd index f0600ff..cfd1412 100644 --- a/man/set_engine.cluster_spec.Rd +++ b/man/set_engine.cluster_spec.Rd @@ -7,7 +7,7 @@ \method{set_engine}{cluster_spec}(object, engine, ...) } \arguments{ -\item{object}{A \link[parsnip:model_spec]{model specification}.} +\item{object}{A model specification.} \item{engine}{A character string for the software that should be used to fit the model. This is highly dependent on the type diff --git a/man/set_mode.cluster_spec.Rd b/man/set_mode.cluster_spec.Rd index 03d6b7d..226c64e 100644 --- a/man/set_mode.cluster_spec.Rd +++ b/man/set_mode.cluster_spec.Rd @@ -7,7 +7,7 @@ \method{set_mode}{cluster_spec}(object, mode, ...) } \arguments{ -\item{object}{A \link[parsnip:model_spec]{model specification}.} +\item{object}{A model specification.} \item{mode}{A character string for the model type (e.g. "classification" or "regression")} diff --git a/tests/testthat/_snaps/db_clust.md b/tests/testthat/_snaps/db_clust.md index 40d8e03..68ad4b5 100644 --- a/tests/testthat/_snaps/db_clust.md +++ b/tests/testthat/_snaps/db_clust.md @@ -3,8 +3,8 @@ Code db_clust(mode = "bogus") Condition - Error in `modelenv::check_spec_mode_engine_val()`: - ! 'bogus' is not a known mode for model `db_clust()`. + Error in `db_clust()`: + ! "bogus" is not a known mode for model `db_clust()`. --- diff --git a/tidyclust.Rproj b/tidyclust.Rproj index ee85d21..7f1b52b 100644 --- a/tidyclust.Rproj +++ b/tidyclust.Rproj @@ -1,5 +1,4 @@ Version: 1.0 -ProjectId: 7aa6e982-3f23-4734-8da7-2ab97b3d66a5 RestoreWorkspace: No SaveWorkspace: No From d784ab99fea0bd7c5b153e3475d5a4367c48f405 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Thu, 12 Jun 2025 09:57:14 -0700 Subject: [PATCH 24/44] tests/documentation updates --- tests/testthat/_snaps/gm_clust.md | 4 +- tests/testthat/_snaps/tune_cluster.new.md | 140 ++++++++++++++++++++++ 2 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 tests/testthat/_snaps/tune_cluster.new.md diff --git a/tests/testthat/_snaps/gm_clust.md b/tests/testthat/_snaps/gm_clust.md index 5a89562..c6f6346 100644 --- a/tests/testthat/_snaps/gm_clust.md +++ b/tests/testthat/_snaps/gm_clust.md @@ -3,8 +3,8 @@ Code gm_clust(mode = "bogus") Condition - Error in `modelenv::check_spec_mode_engine_val()`: - ! 'bogus' is not a known mode for model `gm_clust()`. + Error in `gm_clust()`: + ! "bogus" is not a known mode for model `gm_clust()`. --- diff --git a/tests/testthat/_snaps/tune_cluster.new.md b/tests/testthat/_snaps/tune_cluster.new.md new file mode 100644 index 0000000..64be851 --- /dev/null +++ b/tests/testthat/_snaps/tune_cluster.new.md @@ -0,0 +1,140 @@ +# verbose argument works + + Code + res <- tune_cluster(wflow, resamples = folds, grid = grid, control = control, + metrics = metrics) + Message + i Fold1: preprocessor 1/3 + v Fold1: preprocessor 1/3 + i Fold1: preprocessor 1/3, model 1/3 + v Fold1: preprocessor 1/3, model 1/3 + i Fold1: preprocessor 1/3, model 1/3 (predictions) + i Fold1: preprocessor 1/3, model 2/3 + v Fold1: preprocessor 1/3, model 2/3 + i Fold1: preprocessor 1/3, model 2/3 (predictions) + i Fold1: preprocessor 1/3, model 3/3 + v Fold1: preprocessor 1/3, model 3/3 + i Fold1: preprocessor 1/3, model 3/3 (predictions) + i Fold1: preprocessor 2/3 + v Fold1: preprocessor 2/3 + i Fold1: preprocessor 2/3, model 1/3 + v Fold1: preprocessor 2/3, model 1/3 + i Fold1: preprocessor 2/3, model 1/3 (predictions) + i Fold1: preprocessor 2/3, model 2/3 + v Fold1: preprocessor 2/3, model 2/3 + i Fold1: preprocessor 2/3, model 2/3 (predictions) + i Fold1: preprocessor 2/3, model 3/3 + v Fold1: preprocessor 2/3, model 3/3 + i Fold1: preprocessor 2/3, model 3/3 (predictions) + i Fold1: preprocessor 3/3 + v Fold1: preprocessor 3/3 + i Fold1: preprocessor 3/3, model 1/3 + v Fold1: preprocessor 3/3, model 1/3 + i Fold1: preprocessor 3/3, model 1/3 (predictions) + i Fold1: preprocessor 3/3, model 2/3 + v Fold1: preprocessor 3/3, model 2/3 + i Fold1: preprocessor 3/3, model 2/3 (predictions) + i Fold1: preprocessor 3/3, model 3/3 + v Fold1: preprocessor 3/3, model 3/3 + i Fold1: preprocessor 3/3, model 3/3 (predictions) + i Fold2: preprocessor 1/3 + v Fold2: preprocessor 1/3 + i Fold2: preprocessor 1/3, model 1/3 + v Fold2: preprocessor 1/3, model 1/3 + i Fold2: preprocessor 1/3, model 1/3 (predictions) + i Fold2: preprocessor 1/3, model 2/3 + v Fold2: preprocessor 1/3, model 2/3 + i Fold2: preprocessor 1/3, model 2/3 (predictions) + i Fold2: preprocessor 1/3, model 3/3 + v Fold2: preprocessor 1/3, model 3/3 + i Fold2: preprocessor 1/3, model 3/3 (predictions) + i Fold2: preprocessor 2/3 + v Fold2: preprocessor 2/3 + i Fold2: preprocessor 2/3, model 1/3 + v Fold2: preprocessor 2/3, model 1/3 + i Fold2: preprocessor 2/3, model 1/3 (predictions) + i Fold2: preprocessor 2/3, model 2/3 + v Fold2: preprocessor 2/3, model 2/3 + i Fold2: preprocessor 2/3, model 2/3 (predictions) + i Fold2: preprocessor 2/3, model 3/3 + v Fold2: preprocessor 2/3, model 3/3 + i Fold2: preprocessor 2/3, model 3/3 (predictions) + i Fold2: preprocessor 3/3 + v Fold2: preprocessor 3/3 + i Fold2: preprocessor 3/3, model 1/3 + v Fold2: preprocessor 3/3, model 1/3 + i Fold2: preprocessor 3/3, model 1/3 (predictions) + i Fold2: preprocessor 3/3, model 2/3 + v Fold2: preprocessor 3/3, model 2/3 + i Fold2: preprocessor 3/3, model 2/3 (predictions) + i Fold2: preprocessor 3/3, model 3/3 + v Fold2: preprocessor 3/3, model 3/3 + i Fold2: preprocessor 3/3, model 3/3 (predictions) + +# tune model only - failure in formula is caught elegantly + + Code + cars_res <- tune_cluster(helper_objects$kmeans_mod, ~z, resamples = data_folds, + grid = cars_grid, control = tune::control_grid(extract = function(x) { + 1 + }, save_pred = TRUE)) + Message + x Fold1: preprocessor 1/1: Error in `get_all_predictors()`: + ! The following predi... + x Fold2: preprocessor 1/1: Error in `get_all_predictors()`: + ! The following predi... + Condition + Warning: + All models failed. + i See the `.notes` column. + +# argument order gives errors for recipes + + Code + tune_cluster(helper_objects$rec_tune_1, helper_objects$kmeans_mod_no_tune, + rsample::vfold_cv(mtcars, v = 2)) + Condition + Error in `tune_cluster()`: + ! The first argument to `tune_cluster()` should be either a model or workflow. + +# argument order gives errors for formula + + Code + tune_cluster(mpg ~ ., helper_objects$kmeans_mod_no_tune, rsample::vfold_cv( + mtcars, v = 2)) + Condition + Error in `tune_cluster()`: + ! The first argument to `tune_cluster()` should be either a model or workflow. + +# ellipses with tune_cluster + + Code + tune_cluster(wflow, resamples = folds, grid = 3, something = "wrong") + Condition + Warning: + The `...` are not used in this function but one or more objects were passed: 'something' + Output + # Tuning results + # 2-fold cross-validation + # A tibble: 2 x 4 + splits id .metrics .notes + + 1 Fold1 + 2 Fold2 + +# select_best() and show_best() works + + Code + tmp <- tune::show_best(res) + Condition + Warning in `tune::show_best()`: + No value of `metric` was given; "sse_within_total" will be used. + +--- + + Code + tmp <- tune::select_best(res) + Condition + Warning in `tune::select_best()`: + No value of `metric` was given; "sse_within_total" will be used. + From 3ba190f1e5b7744802476e2d5af8ad3c493d835c Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Thu, 12 Jun 2025 10:16:44 -0700 Subject: [PATCH 25/44] fixed errors where RcppHungarian was not installed --- .../_snaps/reconcile_clusterings.new.md | 17 --- tests/testthat/_snaps/tune_cluster.md | 8 +- tests/testthat/_snaps/tune_cluster.new.md | 140 ------------------ 3 files changed, 4 insertions(+), 161 deletions(-) delete mode 100644 tests/testthat/_snaps/reconcile_clusterings.new.md delete mode 100644 tests/testthat/_snaps/tune_cluster.new.md diff --git a/tests/testthat/_snaps/reconcile_clusterings.new.md b/tests/testthat/_snaps/reconcile_clusterings.new.md deleted file mode 100644 index 8bb2168..0000000 --- a/tests/testthat/_snaps/reconcile_clusterings.new.md +++ /dev/null @@ -1,17 +0,0 @@ -# reconciliation works with uneven numbers - - Code - reconcile_clusterings_mapping(primary_cluster_assignment, - alt_cluster_assignment, one_to_one = TRUE) - Condition - Error in `reconcile_clusterings_mapping()`: - ! The package "RcppHungarian" is required. - -# reconciliation errors for uneven lengths - - Code - reconcile_clusterings_mapping(letters, letters[1:10]) - Condition - Error in `reconcile_clusterings_mapping()`: - ! The package "RcppHungarian" is required. - diff --git a/tests/testthat/_snaps/tune_cluster.md b/tests/testthat/_snaps/tune_cluster.md index 78f7054..64be851 100644 --- a/tests/testthat/_snaps/tune_cluster.md +++ b/tests/testthat/_snaps/tune_cluster.md @@ -79,10 +79,10 @@ 1 }, save_pred = TRUE)) Message - x Fold1: preprocessor 1/1: Error in `hardhat::mold()`: - ! The following predictor ... - x Fold2: preprocessor 1/1: Error in `hardhat::mold()`: - ! The following predictor ... + x Fold1: preprocessor 1/1: Error in `get_all_predictors()`: + ! The following predi... + x Fold2: preprocessor 1/1: Error in `get_all_predictors()`: + ! The following predi... Condition Warning: All models failed. diff --git a/tests/testthat/_snaps/tune_cluster.new.md b/tests/testthat/_snaps/tune_cluster.new.md deleted file mode 100644 index 64be851..0000000 --- a/tests/testthat/_snaps/tune_cluster.new.md +++ /dev/null @@ -1,140 +0,0 @@ -# verbose argument works - - Code - res <- tune_cluster(wflow, resamples = folds, grid = grid, control = control, - metrics = metrics) - Message - i Fold1: preprocessor 1/3 - v Fold1: preprocessor 1/3 - i Fold1: preprocessor 1/3, model 1/3 - v Fold1: preprocessor 1/3, model 1/3 - i Fold1: preprocessor 1/3, model 1/3 (predictions) - i Fold1: preprocessor 1/3, model 2/3 - v Fold1: preprocessor 1/3, model 2/3 - i Fold1: preprocessor 1/3, model 2/3 (predictions) - i Fold1: preprocessor 1/3, model 3/3 - v Fold1: preprocessor 1/3, model 3/3 - i Fold1: preprocessor 1/3, model 3/3 (predictions) - i Fold1: preprocessor 2/3 - v Fold1: preprocessor 2/3 - i Fold1: preprocessor 2/3, model 1/3 - v Fold1: preprocessor 2/3, model 1/3 - i Fold1: preprocessor 2/3, model 1/3 (predictions) - i Fold1: preprocessor 2/3, model 2/3 - v Fold1: preprocessor 2/3, model 2/3 - i Fold1: preprocessor 2/3, model 2/3 (predictions) - i Fold1: preprocessor 2/3, model 3/3 - v Fold1: preprocessor 2/3, model 3/3 - i Fold1: preprocessor 2/3, model 3/3 (predictions) - i Fold1: preprocessor 3/3 - v Fold1: preprocessor 3/3 - i Fold1: preprocessor 3/3, model 1/3 - v Fold1: preprocessor 3/3, model 1/3 - i Fold1: preprocessor 3/3, model 1/3 (predictions) - i Fold1: preprocessor 3/3, model 2/3 - v Fold1: preprocessor 3/3, model 2/3 - i Fold1: preprocessor 3/3, model 2/3 (predictions) - i Fold1: preprocessor 3/3, model 3/3 - v Fold1: preprocessor 3/3, model 3/3 - i Fold1: preprocessor 3/3, model 3/3 (predictions) - i Fold2: preprocessor 1/3 - v Fold2: preprocessor 1/3 - i Fold2: preprocessor 1/3, model 1/3 - v Fold2: preprocessor 1/3, model 1/3 - i Fold2: preprocessor 1/3, model 1/3 (predictions) - i Fold2: preprocessor 1/3, model 2/3 - v Fold2: preprocessor 1/3, model 2/3 - i Fold2: preprocessor 1/3, model 2/3 (predictions) - i Fold2: preprocessor 1/3, model 3/3 - v Fold2: preprocessor 1/3, model 3/3 - i Fold2: preprocessor 1/3, model 3/3 (predictions) - i Fold2: preprocessor 2/3 - v Fold2: preprocessor 2/3 - i Fold2: preprocessor 2/3, model 1/3 - v Fold2: preprocessor 2/3, model 1/3 - i Fold2: preprocessor 2/3, model 1/3 (predictions) - i Fold2: preprocessor 2/3, model 2/3 - v Fold2: preprocessor 2/3, model 2/3 - i Fold2: preprocessor 2/3, model 2/3 (predictions) - i Fold2: preprocessor 2/3, model 3/3 - v Fold2: preprocessor 2/3, model 3/3 - i Fold2: preprocessor 2/3, model 3/3 (predictions) - i Fold2: preprocessor 3/3 - v Fold2: preprocessor 3/3 - i Fold2: preprocessor 3/3, model 1/3 - v Fold2: preprocessor 3/3, model 1/3 - i Fold2: preprocessor 3/3, model 1/3 (predictions) - i Fold2: preprocessor 3/3, model 2/3 - v Fold2: preprocessor 3/3, model 2/3 - i Fold2: preprocessor 3/3, model 2/3 (predictions) - i Fold2: preprocessor 3/3, model 3/3 - v Fold2: preprocessor 3/3, model 3/3 - i Fold2: preprocessor 3/3, model 3/3 (predictions) - -# tune model only - failure in formula is caught elegantly - - Code - cars_res <- tune_cluster(helper_objects$kmeans_mod, ~z, resamples = data_folds, - grid = cars_grid, control = tune::control_grid(extract = function(x) { - 1 - }, save_pred = TRUE)) - Message - x Fold1: preprocessor 1/1: Error in `get_all_predictors()`: - ! The following predi... - x Fold2: preprocessor 1/1: Error in `get_all_predictors()`: - ! The following predi... - Condition - Warning: - All models failed. - i See the `.notes` column. - -# argument order gives errors for recipes - - Code - tune_cluster(helper_objects$rec_tune_1, helper_objects$kmeans_mod_no_tune, - rsample::vfold_cv(mtcars, v = 2)) - Condition - Error in `tune_cluster()`: - ! The first argument to `tune_cluster()` should be either a model or workflow. - -# argument order gives errors for formula - - Code - tune_cluster(mpg ~ ., helper_objects$kmeans_mod_no_tune, rsample::vfold_cv( - mtcars, v = 2)) - Condition - Error in `tune_cluster()`: - ! The first argument to `tune_cluster()` should be either a model or workflow. - -# ellipses with tune_cluster - - Code - tune_cluster(wflow, resamples = folds, grid = 3, something = "wrong") - Condition - Warning: - The `...` are not used in this function but one or more objects were passed: 'something' - Output - # Tuning results - # 2-fold cross-validation - # A tibble: 2 x 4 - splits id .metrics .notes - - 1 Fold1 - 2 Fold2 - -# select_best() and show_best() works - - Code - tmp <- tune::show_best(res) - Condition - Warning in `tune::show_best()`: - No value of `metric` was given; "sse_within_total" will be used. - ---- - - Code - tmp <- tune::select_best(res) - Condition - Warning in `tune::select_best()`: - No value of `metric` was given; "sse_within_total" will be used. - From 9c867a1416728d00d9b7d6ad21d0953d680de954 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:39:04 -0700 Subject: [PATCH 26/44] documentation --- DESCRIPTION | 3 +++ vignettes/articles/gm_clust.Rmd | 2 ++ 2 files changed, 5 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION index 2a4a273..656d160 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -22,14 +22,17 @@ Imports: dials (>= 1.3.0), dplyr (>= 1.0.9), flexclust (>= 1.3-6), + forcats, foreach, generics (>= 0.1.2), glue (>= 1.6.2), hardhat (>= 1.0.0), + mclust, modelenv (>= 0.2.0), parsnip (>= 1.0.2), philentropy (>= 0.9.0), prettyunits (>= 1.1.0), + Rfast, rlang (>= 1.0.6), rsample (>= 1.0.0), stats, diff --git a/vignettes/articles/gm_clust.Rmd b/vignettes/articles/gm_clust.Rmd index 06cfaca..73a16f2 100644 --- a/vignettes/articles/gm_clust.Rmd +++ b/vignettes/articles/gm_clust.Rmd @@ -135,6 +135,8 @@ gm_clust_fit %>% ``` +## Gaussian Mixture Model Specifications + ```{r} #| include: false plot_state <- function(obj) { From b9e38c487580e40f62b3d5250ae2fd871ddedf2f Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 17 Jun 2025 18:34:23 -0700 Subject: [PATCH 27/44] use philentropy distance functions --- R/extract_fit_summary.R | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/R/extract_fit_summary.R b/R/extract_fit_summary.R index ad8db00..dccd7ba 100644 --- a/R/extract_fit_summary.R +++ b/R/extract_fit_summary.R @@ -223,7 +223,13 @@ extract_fit_summary.dbscan <- function(object, ...) { sse_within_total_total <- map2_dbl( by_clust$data, seq_len(n_clust), - ~ sum(Rfast::dista(centroids[.y, ], .x)) + ~sum( + philentropy::dist_many_many( + as.matrix(centroids[.y, ]), + as.matrix(.x), + method = "euclidean" + ) + ) ) @@ -233,7 +239,13 @@ extract_fit_summary.dbscan <- function(object, ...) { centroids = centroids, n_members = unname(as.integer(table(clusts))), sse_within_total_total = sse_within_total_total, - sse_total = sum(Rfast::dista(t(overall_centroid), training_data)), + sse_total = sse_total = sum( + philentropy::dist_many_many( + t(overall_centroid), + as.matrix(training_data), + method = "euclidean" + ) + ), orig_labels = NULL, cluster_assignments = clusts ) @@ -263,16 +275,27 @@ extract_fit_summary.Mclust <- function(object, ...) { sse_within_total_total <- map2_dbl( by_clust$data, seq_len(n_clust), - ~ sum(Rfast::dista(centroids[.y, ], .x)) + ~sum( + philentropy::dist_many_many( + as.matrix(centroids[.y, ]), + as.matrix(.x), + method = "euclidean" + ) + ) ) - list( cluster_names = unique(clusts), centroids = centroids, n_members = unname(as.integer(table(clusts))), sse_within_total_total = sse_within_total_total, - sse_total = sum(Rfast::dista(t(overall_centroid), training_data)), + sse_total = sse_total = sum( + philentropy::dist_many_many( + t(overall_centroid), + as.matrix(training_data), + method = "euclidean" + ) + ), orig_labels = NULL, cluster_assignments = clusts ) From b392a1d08cfb38d8a0e72808fa7576b4abe2f371 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 17 Jun 2025 18:36:11 -0700 Subject: [PATCH 28/44] fix typo --- R/extract_fit_summary.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/extract_fit_summary.R b/R/extract_fit_summary.R index dccd7ba..05186ae 100644 --- a/R/extract_fit_summary.R +++ b/R/extract_fit_summary.R @@ -239,7 +239,7 @@ extract_fit_summary.dbscan <- function(object, ...) { centroids = centroids, n_members = unname(as.integer(table(clusts))), sse_within_total_total = sse_within_total_total, - sse_total = sse_total = sum( + sse_total = sum( philentropy::dist_many_many( t(overall_centroid), as.matrix(training_data), @@ -289,7 +289,7 @@ extract_fit_summary.Mclust <- function(object, ...) { centroids = centroids, n_members = unname(as.integer(table(clusts))), sse_within_total_total = sse_within_total_total, - sse_total = sse_total = sum( + sse_total = sum( philentropy::dist_many_many( t(overall_centroid), as.matrix(training_data), From 82dbcb791a780916eeac7ef5dae79e28aaca3f7c Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 17 Jun 2025 18:53:03 -0700 Subject: [PATCH 29/44] assign NA to within sum squares for outlier group after philentropy call --- R/extract_fit_summary.R | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/R/extract_fit_summary.R b/R/extract_fit_summary.R index 05186ae..b58186f 100644 --- a/R/extract_fit_summary.R +++ b/R/extract_fit_summary.R @@ -214,12 +214,8 @@ extract_fit_summary.dbscan <- function(object, ...) { dplyr::bind_rows() outlier_idx <- which(unique(clusts) == "Outlier") - centroids[outlier_idx, ] <- rep(NA, ncol(centroids)) - # reorder centroids - centroids <- centroids[c(outlier_idx, setdiff(1:n_clust, outlier_idx)), ] - sse_within_total_total <- map2_dbl( by_clust$data, seq_len(n_clust), @@ -234,7 +230,7 @@ extract_fit_summary.dbscan <- function(object, ...) { clust_names <- unique(clusts)[c(outlier_idx, setdiff(1:n_clust, outlier_idx))] - list( + summary <- list( cluster_names = clust_names, centroids = centroids, n_members = unname(as.integer(table(clusts))), @@ -249,6 +245,14 @@ extract_fit_summary.dbscan <- function(object, ...) { orig_labels = NULL, cluster_assignments = clusts ) + + summary$centroids[outlier_idx, ] <- rep(NA, ncol(summary$centroids)) + summary$sse_within_total_total[outlier_idx] <- NA + + # reorder centroids + summary$centroids <- summary$centroids[c(outlier_idx, setdiff(1:n_clust, outlier_idx)), ] + + summary } #' @export From e2d9fc0e8ea7c8e9b4242f36453aa02a4cc1b6db Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Fri, 27 Jun 2025 18:10:05 -0700 Subject: [PATCH 30/44] remove rfast from imports and add dbscan to suggests --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 656d160..b1807ab 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -32,7 +32,6 @@ Imports: parsnip (>= 1.0.2), philentropy (>= 0.9.0), prettyunits (>= 1.1.0), - Rfast, rlang (>= 1.0.6), rsample (>= 1.0.0), stats, @@ -46,6 +45,7 @@ Suggests: ClusterR, clustMixType (>= 0.3-5), covr, + dbscan, klaR, knitr, modeldata (>= 1.0.0), From 670599c19073b55cd464c003c357b8e17ae80d7e Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Fri, 27 Jun 2025 18:32:47 -0700 Subject: [PATCH 31/44] add skip_if_not_installed for tests relating to dbscan engine and removing forcats use in tests --- tests/testthat/test-db_clust-dbscan.R | 15 +++++++++------ tests/testthat/test-db_clust.R | 10 ++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/tests/testthat/test-db_clust-dbscan.R b/tests/testthat/test-db_clust-dbscan.R index 8ec0966..4e6e3dd 100644 --- a/tests/testthat/test-db_clust-dbscan.R +++ b/tests/testthat/test-db_clust-dbscan.R @@ -1,4 +1,5 @@ test_that("fitting", { + skip_if_not_installed("dbscan") set.seed(1234) spec <- db_clust(radius = 10, min_points = 5) %>% set_engine("dbscan") @@ -13,6 +14,7 @@ test_that("fitting", { }) test_that("predicting", { + skip_if_not_installed("dbscan") set.seed(1234) spec <- db_clust(radius = .42, min_points = 5) %>% set_engine("dbscan") @@ -33,6 +35,7 @@ test_that("predicting", { test_that("all levels are preserved with 1 row predictions", { + skip_if_not_installed("dbscan") set.seed(1234) spec <- db_clust(radius = 50, min_points = 5) %>% set_engine("dbscan") @@ -69,6 +72,7 @@ test_that("all levels are preserved with 1 row predictions", { # }) test_that("extract_cluster_assignment() works", { + skip_if_not_installed("dbscan") set.seed(1234) spec <- db_clust(radius = .42, min_points = 5) %>% set_engine("dbscan") @@ -78,12 +82,11 @@ test_that("extract_cluster_assignment() works", { clusters <- extract_cluster_assignment(res) - expected <- vctrs::vec_cbind( - tibble::tibble(.cluster = factor(paste0("Cluster_", res$fit$cluster)) %>% - forcats::fct_recode("Outlier" = "Cluster_0") %>% - relevel(ref = "Outlier")) - - ) + expected <- paste0("Cluster_", res$fit$cluster) %>% + ifelse(. == "Cluster_0", "Outlier", .) %>% + as.factor() %>% + relevel(ref = "Outlier") %>% + tibble::tibble(.cluster = .) expect_identical( diff --git a/tests/testthat/test-db_clust.R b/tests/testthat/test-db_clust.R index d7e0317..1c6df8b 100644 --- a/tests/testthat/test-db_clust.R +++ b/tests/testthat/test-db_clust.R @@ -1,4 +1,5 @@ test_that("primary arguments", { + basic <- db_clust(mode = "partition") basic_dbscan <- translate_tidyclust(basic %>% set_engine("dbscan")) expect_equal( @@ -27,6 +28,9 @@ test_that("primary arguments", { test_that("bad input", { expect_snapshot(error = TRUE, db_clust(mode = "bogus")) + + skip_if_not_installed("dbscan") + expect_snapshot(error = TRUE, { bt <- db_clust(radius = -1) %>% set_engine("dbscan") fit(bt, mpg ~ ., mtcars) @@ -40,6 +44,7 @@ test_that("bad input", { }) test_that("predictions", { + skip_if_not_installed("dbscan") set.seed(1234) db_clust_fit <- db_clust(radius = 60, min_points = 5) %>% set_engine("dbscan") %>% @@ -73,6 +78,7 @@ test_that("predictions", { test_that("extract_centroids work", { + skip_if_not_installed("dbscan") set.seed(1234) dbscan_fit <- db_clust(radius = 20, min_points = 3) %>% set_engine("dbscan") %>% @@ -127,6 +133,7 @@ test_that("updating", { test_that("reordering is done correctly for dbscan db_clust", { + skip_if_not_installed("dbscan") set.seed(42) dbscan_fit <- db_clust(radius = 20, min_points = 3) %>% @@ -143,6 +150,7 @@ test_that("reordering is done correctly for dbscan db_clust", { test_that("errors if `radius` and `min_points` aren't specified", { + skip_if_not_installed("dbscan") expect_snapshot( error = TRUE, db_clust() %>% @@ -152,6 +160,7 @@ test_that("errors if `radius` and `min_points` aren't specified", { }) test_that("errors if `radius` isn't specified", { + skip_if_not_installed("dbscan") expect_snapshot( error = TRUE, db_clust(min_points = 10) %>% @@ -161,6 +170,7 @@ test_that("errors if `radius` isn't specified", { }) test_that("errors if `min_points` isn't specified", { + skip_if_not_installed("dbscan") expect_snapshot( error = TRUE, db_clust(radius = 20) %>% From d8c8368dc498bbd7f1a1503f22d1092e7f9c5da8 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Fri, 27 Jun 2025 18:45:55 -0700 Subject: [PATCH 32/44] db_clust minor documentation updates and rlang::abort() -> cli::cli_abort() --- R/db_clust.R | 14 +++++++------- R/gm_clust.R | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index 85b9860..13efd92 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -12,7 +12,7 @@ #' - \link[=details_db_clust_dbscan]{dbscan} #' #' @param mode A single character string for the type of model. The only -#' possible value for this model is "partition". +#' possible value for this model is `"partition"`. #' @param engine A single character string specifying what computational engine #' to use for fitting. The engine for this model is `"dbscan"`. #' @param radius Positive double, Radius drawn around points to determine core-points and cluster assignments (required) @@ -127,11 +127,11 @@ check_args.db_clust <- function(object) { args <- lapply(object$args, rlang::eval_tidy) if (all(is.numeric(args$min_points)) && any(args$min_points < 0)) { - rlang::abort("The number of points in a cluster should be > 0.") + cli::cli_abort("The number of points in a cluster should be > 0.") } if (all(is.numeric(args$radius)) && any(args$radius < 0)) { - rlang::abort("The radius used to create a cluster should be > 0.") + cli::cli_abort("The radius used to create a cluster should be > 0.") } invisible(object) @@ -148,7 +148,7 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { #' Simple Wrapper around dbscan function #' #' This wrapper prepares the data into a distance matrix to send to -#' `dbscan::dbscan` and retains the parameters `radius` or `min_points` as an +#' `dbscan::dbscan()` and retains the parameters `radius` or `min_points` as an #' attribute. #' #' @param x matrix or data frame @@ -163,14 +163,14 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { minPts = NULL, ...) { if (is.null(eps)) { - rlang::abort( + cli::cli_abort( "Please specify `radius` to be able to fit specification.", call = call("fit") ) } if (is.null(minPts)) { - rlang::abort( + cli::cli_abort( "Please specify `min_points` to be able to fit specification.", call = call("fit") ) @@ -228,7 +228,7 @@ dbscan_helper <- function(object, non_cp_clusters$is_core <- "non cp" cp_clusters$is_core <- "cp" - training_data$id <- ave(training_data$is_core, training_data$is_core, FUN = seq_along) + training_data$id <- stats::ave(training_data$is_core, training_data$is_core, FUN = seq_along) non_cp_clusters$id <- 1:nrow(non_cp_clusters) cp_clusters$id <- 1:nrow(cp_clusters) diff --git a/R/gm_clust.R b/R/gm_clust.R index 907836c..582bdd3 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -148,31 +148,31 @@ check_args.gm_clust <- function(object) { args <- lapply(object$args, rlang::eval_tidy) if (all(is.numeric(args$num_clusters)) && any(args$num_clusters <= 0)) { - rlang::abort("The number of clusters should be > 0.") + cli::cli_abort("The number of clusters should be > 0.") } if (length(args$num_clusters) > 1) { - rlang::abort("The number of clusters should be a single number.") + cli::cli_abort("The number of clusters should be a single number.") } if (all(!is.logical(args$circular))) { - rlang::abort("The circular cluster shape argument should be TRUE or FALSE.") + cli::cli_abort("The circular cluster shape argument should be TRUE or FALSE.") } if (all(!is.logical(args$zero_covariance))) { - rlang::abort("The zero covariance argument should be TRUE or FALSE.") + cli::cli_abort("The zero covariance argument should be TRUE or FALSE.") } if (all(!is.logical(args$shared_orientation))) { - rlang::abort("The shared cluster orientation argument should be TRUE or FALSE.") + cli::cli_abort("The shared cluster orientation argument should be TRUE or FALSE.") } if (all(!is.logical(args$shared_shape))) { - rlang::abort("The shared cluster shape argument should be TRUE or FALSE.") + cli::cli_abort("The shared cluster shape argument should be TRUE or FALSE.") } if (all(!is.logical(args$shared_size))) { - rlang::abort("The shared cluster size argument should be TRUE or FALSE.") + cli::cli_abort("The shared cluster size argument should be TRUE or FALSE.") } invisible(object) @@ -207,19 +207,19 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { shared_size = NULL, ...) { if (is.null(G)) { - rlang::abort( + cli::cli_abort( "Please specify `num_clusters` to be able to fit specification.", call = call("fit") ) } if (is.null(circular)) { - rlang::abort( + cli::cli_abort( "Please specify `circular` to be able to fit specification.", call = call("fit") ) } if (is.null(shared_size)) { - rlang::abort( + cli::cli_abort( "Please specify `shared_size` to be able to fit specification.", call = call("fit") ) @@ -227,14 +227,14 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { if (!circular) { if (is.null(zero_covariance)) { - rlang::abort( + cli::cli_abort( "Please specify `zero_covariance` to be able to fit specification.", call = call("fit") ) } if (is.null(shared_shape)) { - rlang::abort( + cli::cli_abort( "Please specify `shared_shape` to be able to fit specification.", call = call("fit") ) @@ -243,7 +243,7 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { if (!zero_covariance) { if (is.null(shared_orientation)) { - rlang::abort( + cli::cli_abort( "Please specify `shared_orientation` to be able to fit specification.", call = call("fit") ) @@ -283,7 +283,7 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { res <- mclust::Mclust(x, G = G, modelNames = model_name) if (is.null(res)) { - rlang::abort( + cli::cli_abort( "Model cannot be estimated. Please specify a model specification with less parameters by setting some model arguments to TRUE", call = call("fit") ) From 624e53e80905e638615951c1ad6af36fdff00fd0 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Fri, 27 Jun 2025 18:49:44 -0700 Subject: [PATCH 33/44] dbscan helper args to match tidy names --- R/db_clust.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index 13efd92..dde8005 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -159,28 +159,28 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { #' @keywords internal #' @export .db_clust_fit_dbscan <- function(x, - eps = NULL, - minPts = NULL, + radius = NULL, + min_points = NULL, ...) { - if (is.null(eps)) { + if (is.null(radius)) { cli::cli_abort( "Please specify `radius` to be able to fit specification.", call = call("fit") ) } - if (is.null(minPts)) { + if (is.null(min_points)) { cli::cli_abort( "Please specify `min_points` to be able to fit specification.", call = call("fit") ) } - res <- dbscan::dbscan(x, eps = eps, minPts = minPts) - attr(res, "radius") <- eps - attr(res, "min_points") <- minPts + res <- dbscan::dbscan(x, eps = radius, minPts = min_points) + attr(res, "radius") <- radius + attr(res, "min_points") <- min_points attr(res, "training_data") <- x - is_core <- dbscan::is.corepoint(x, eps = eps, minPts = minPts) + is_core <- dbscan::is.corepoint(x, eps = radius, minPts = min_points) attr(res, "is_core") <- is_core res From 5931da8f086a684a9622f1fdb4aca9239c495deb Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Fri, 27 Jun 2025 19:02:20 -0700 Subject: [PATCH 34/44] make db_clust helper args match tidy names (cont.) --- R/db_clust_data.R | 6 +++--- tests/testthat/test-db_clust.R | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/R/db_clust_data.R b/R/db_clust_data.R index 9b6e0be..e34367d 100644 --- a/R/db_clust_data.R +++ b/R/db_clust_data.R @@ -27,7 +27,7 @@ make_db_clust <- function() { mode = "partition", value = list( interface = "matrix", - protect = c("x", "eps", "minPts"), + protect = c("x", "radius", "min_points"), func = c(pkg = "tidyclust", fun = ".db_clust_fit_dbscan"), defaults = list() ) @@ -49,7 +49,7 @@ make_db_clust <- function() { model = "db_clust", eng = "dbscan", exposed = "radius", - original = "eps", + original = "radius", func = list(pkg = "dials", fun = "radius"), has_submodel = TRUE ) @@ -58,7 +58,7 @@ make_db_clust <- function() { model = "db_clust", eng = "dbscan", exposed = "min_points", - original = "minPts", + original = "min_points", func = list(pkg = "dials", fun = "min_points"), has_submodel = TRUE ) diff --git a/tests/testthat/test-db_clust.R b/tests/testthat/test-db_clust.R index 1c6df8b..1b39a02 100644 --- a/tests/testthat/test-db_clust.R +++ b/tests/testthat/test-db_clust.R @@ -6,8 +6,8 @@ test_that("primary arguments", { basic_dbscan$method$fit$args, list( x = rlang::expr(missing_arg()), - eps = rlang::expr(missing_arg()), - minPts = rlang::expr(missing_arg()) + radius = rlang::expr(missing_arg()), + min_points = rlang::expr(missing_arg()) ) ) @@ -17,10 +17,10 @@ test_that("primary arguments", { db_dbscan$method$fit$args, list( x = rlang::expr(missing_arg()), - eps = rlang::expr(missing_arg()), - minPts = rlang::expr(missing_arg()), - eps = new_empty_quosure(2), - minPts = new_empty_quosure(4) + radius = rlang::expr(missing_arg()), + min_points = rlang::expr(missing_arg()), + radius = new_empty_quosure(2), + min_points = new_empty_quosure(4) ) ) }) From 441c222d9f0b1dc520279aeabd01d7ba0d180672 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Fri, 27 Jun 2025 19:02:39 -0700 Subject: [PATCH 35/44] updated documentation --- man/db_clust.Rd | 2 +- man/dot-db_clust_fit_dbscan.Rd | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/man/db_clust.Rd b/man/db_clust.Rd index db44a06..764ac65 100644 --- a/man/db_clust.Rd +++ b/man/db_clust.Rd @@ -13,7 +13,7 @@ db_clust( } \arguments{ \item{mode}{A single character string for the type of model. The only -possible value for this model is "partition".} +possible value for this model is \code{"partition"}.} \item{engine}{A single character string specifying what computational engine to use for fitting. The engine for this model is \code{"dbscan"}.} diff --git a/man/dot-db_clust_fit_dbscan.Rd b/man/dot-db_clust_fit_dbscan.Rd index d6012ca..54fa451 100644 --- a/man/dot-db_clust_fit_dbscan.Rd +++ b/man/dot-db_clust_fit_dbscan.Rd @@ -4,7 +4,7 @@ \alias{.db_clust_fit_dbscan} \title{Simple Wrapper around dbscan function} \usage{ -.db_clust_fit_dbscan(x, eps = NULL, minPts = NULL, ...) +.db_clust_fit_dbscan(x, radius = NULL, min_points = NULL, ...) } \arguments{ \item{x}{matrix or data frame} @@ -18,7 +18,7 @@ dbscan object } \description{ This wrapper prepares the data into a distance matrix to send to -\code{dbscan::dbscan} and retains the parameters \code{radius} or \code{min_points} as an +\code{dbscan::dbscan()} and retains the parameters \code{radius} or \code{min_points} as an attribute. } \keyword{internal} From fdf7456be30abc7f217aad54e295be67d7017d19 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:23:24 -0700 Subject: [PATCH 36/44] fix type in vignette --- vignettes/articles/db_clust.Rmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vignettes/articles/db_clust.Rmd b/vignettes/articles/db_clust.Rmd index 575694e..0d5b0ae 100644 --- a/vignettes/articles/db_clust.Rmd +++ b/vignettes/articles/db_clust.Rmd @@ -224,13 +224,13 @@ penguins_new$cluster <- (db_clust_fit %>% extract_cluster_assignment())$.cluster # factor(dbscan_fit$cluster) penguins_new$cp2 <- factor(if_else(as.numeric(is.corepoint(penguins_std, eps = eps, minPts = min_points)) == 1 & penguins_new$cluster == "Cluster_2", "Yes", "No"), levels = c("Yes", "No")) -penguins_new$radius <- if_else(penguins_new$cp == "Yes", eps, 0) +penguins_new$radius <- if_else(penguins_new$cp2 == "Yes", eps, 0) -penguins_new_sub <- penguins_new %>% filter(cp == "Yes") %>% +penguins_new_sub <- penguins_new %>% filter(cp2 == "Yes") %>% .[c(2,3,4,5,7,9,16),] penguins_new %>% - ggplot(aes(x = bill_length_std, y = bill_depth_std, color = cp)) + + ggplot(aes(x = bill_length_std, y = bill_depth_std, color = cp2)) + geom_point() + theme_minimal() + geom_circle(mapping = aes(x0 = bill_length_std, y0 = bill_depth_std, r = radius), color = "gray", linewidth = 0.8, data = penguins_new_sub) + From 1ee9de4193d58a6add7c5ba3fb0e34931653aa36 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:24:31 -0700 Subject: [PATCH 37/44] removed dependency on unexported dbscan:::predict_frNN() to use exported dbscan::frNN() --- R/db_clust.R | 10 +++++++++- R/predict_helpers.R | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index dde8005..9b01610 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -216,7 +216,15 @@ dbscan_helper <- function(object, } # get fit values according to closest core point - non_cp_clusters <- dbscan:::.predict_frNN(newdata = non_cp, data = cp, cp_clusters, eps = eps) + nn <- dbscan::frNN(cp, + query = non_cp, + eps = eps, + sort = TRUE) + + non_cp_clusters <- vapply( + nn$id, function(nns) if (length(nns) == 0L) 0L else cp_clusters[nns[1L]], integer(1L) + ) + # join back separated fits into proper order in training data non_cp_clusters <- data.frame(non_cp_clusters) diff --git a/R/predict_helpers.R b/R/predict_helpers.R index 2c8242e..6f64276 100644 --- a/R/predict_helpers.R +++ b/R/predict_helpers.R @@ -198,7 +198,15 @@ make_predictions_w_outliers <- function(x, prefix, n_clusters) { clusters <- (rep(0, nrow(new_data))) n_clusters <- 1 } else { - clusters <- dbscan:::.predict_frNN(newdata = new_data, data = cp, cp_clusters, eps = eps) + nn <- dbscan::frNN(cp, + query = new_data, + eps = eps, + sort = TRUE) + + clusters <- vapply( + nn$id, function(nns) if (length(nns) == 0L) 0L else cp_clusters[nns[1L]], integer(1L) + ) + n_clusters <- length(unique(object$cluster[object$cluster != 0])) + 1 } From 0dae853e356adedadd59d8c4a56b385d17b793fb Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:38:19 -0700 Subject: [PATCH 38/44] Added models to _pkgdown.yml along with bullet points for new models in NEWS.md --- NEWS.md | 6 ++++++ _pkgdown.yml | 2 ++ 2 files changed, 8 insertions(+) diff --git a/NEWS.md b/NEWS.md index b02a7a8..a32c544 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # tidyclust (development version) +## New Clustering Specifications + +* The `db_clust()` clustering specification has been added. This specification allows for the use of the DBSCAN algorithm using the dbscan engine. (#209) + +* The `gm_clust()` clustering specification has been added. This specification allows for the fitting of Gaussian mixture models using the mclust engine. (#209) + # tidyclust 0.2.4 * The philentropy package is now used to calculate distances rather than Rfast. (#199) diff --git a/_pkgdown.yml b/_pkgdown.yml index 7749c25..b295d99 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -22,6 +22,8 @@ reference: contents: - k_means - hier_clust + - db_clust + - gm_clust - cluster_spec - cluster_fit - title: Fit and Inspect From 142bf7ed37efc96bc377b5ca3149f5a8654347c1 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:08:11 -0700 Subject: [PATCH 39/44] remove forcats from imports since its no longer used --- DESCRIPTION | 1 - 1 file changed, 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index b1807ab..53472cc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -22,7 +22,6 @@ Imports: dials (>= 1.3.0), dplyr (>= 1.0.9), flexclust (>= 1.3-6), - forcats, foreach, generics (>= 0.1.2), glue (>= 1.6.2), From 6c7704bd5028923d8a19aa37b0679900defa0f67 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:25:19 -0700 Subject: [PATCH 40/44] fix documentation for .gm_clust_fit_mclust and mclust_helper --- R/gm_clust.R | 19 ++++++++++++++----- R/gm_clust_data.R | 4 ++-- man/dot-gm_clust_fit_mclust.Rd | 12 +++++++++++- man/mclust_helper.Rd | 10 +++++++++- tests/testthat/test-gm_clust.R | 4 ++-- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/R/gm_clust.R b/R/gm_clust.R index 582bdd3..8846500 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -194,19 +194,24 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { #' #' @param x matrix or data frame #' @param num_clusters Number of clusters +#' @param circular Whether or not to fit circular MVG distributions for each cluster +#' @param zero_covariance Whether or not to assign covariances of 0 for each MVG +#' @param shared_orientation Whether each cluster MVG should have the same orientation +#' @param shared_shape Whether each cluster MVG should have the same shape +#' @param shared_size Whether each cluster MVG should have the same size/volume #' #' @return mclust object #' @keywords internal #' @export .gm_clust_fit_mclust <- function(x, - G = NULL, + num_clusters = NULL, circular = NULL, zero_covariance = NULL, shared_orientation = NULL, shared_shape = NULL, shared_size = NULL, ...) { - if (is.null(G)) { + if (is.null(num_clusters)) { cli::cli_abort( "Please specify `num_clusters` to be able to fit specification.", call = call("fit") @@ -280,7 +285,7 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { - res <- mclust::Mclust(x, G = G, modelNames = model_name) + res <- mclust::Mclust(x, G = num_clusters, modelNames = model_name) if (is.null(res)) { cli::cli_abort( @@ -289,7 +294,7 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { ) } - attr(res, "num_clusters") <- G + attr(res, "num_clusters") <- num_clusters attr(res, "circular") <- circular attr(res, "zero_covariance") <- zero_covariance attr(res, "shared_orientation") <- shared_orientation @@ -306,7 +311,11 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { #' This function returns the mclust model name based on the specified #' TRUE/FALSE model arguments #' -#' @param object gm_clust object +#' @param circular Whether or not to fit circular MVG distributions for each cluster +#' @param zero_covariance Whether or not to assign covariances of 0 for each MVG +#' @param shared_orientation Whether each cluster MVG should have the same orientation +#' @param shared_shape Whether each cluster MVG should have the same shape +#' @param shared_size Whether each cluster MVG should have the same size/volume #' #' @return string containing mclust model name #' @keywords internal diff --git a/R/gm_clust_data.R b/R/gm_clust_data.R index d58e820..b69a22d 100644 --- a/R/gm_clust_data.R +++ b/R/gm_clust_data.R @@ -27,7 +27,7 @@ make_gm_clust <- function() { mode = "partition", value = list( interface = "matrix", - protect = c("x", "G", "circular", "zero_covariance", "shared_orientation", "shared_shape", "shared_size"), + protect = c("x", "num_clusters", "circular", "zero_covariance", "shared_orientation", "shared_shape", "shared_size"), func = c(pkg = "tidyclust", fun = ".gm_clust_fit_mclust"), defaults = list() ) @@ -50,7 +50,7 @@ make_gm_clust <- function() { model = "gm_clust", eng = "mclust", exposed = "num_clusters", - original = "G", + original = "num_clusters", func = list(pkg = "dials", fun = "num_clusters"), has_submodel = TRUE ) diff --git a/man/dot-gm_clust_fit_mclust.Rd b/man/dot-gm_clust_fit_mclust.Rd index c8f252b..2324620 100644 --- a/man/dot-gm_clust_fit_mclust.Rd +++ b/man/dot-gm_clust_fit_mclust.Rd @@ -6,7 +6,7 @@ \usage{ .gm_clust_fit_mclust( x, - G = NULL, + num_clusters = NULL, circular = NULL, zero_covariance = NULL, shared_orientation = NULL, @@ -19,6 +19,16 @@ \item{x}{matrix or data frame} \item{num_clusters}{Number of clusters} + +\item{circular}{Whether or not to fit circular MVG distributions for each cluster} + +\item{zero_covariance}{Whether or not to assign covariances of 0 for each MVG} + +\item{shared_orientation}{Whether each cluster MVG should have the same orientation} + +\item{shared_shape}{Whether each cluster MVG should have the same shape} + +\item{shared_size}{Whether each cluster MVG should have the same size/volume} } \value{ mclust object diff --git a/man/mclust_helper.Rd b/man/mclust_helper.Rd index d42adb1..68aac2e 100644 --- a/man/mclust_helper.Rd +++ b/man/mclust_helper.Rd @@ -13,7 +13,15 @@ mclust_helper( ) } \arguments{ -\item{object}{gm_clust object} +\item{circular}{Whether or not to fit circular MVG distributions for each cluster} + +\item{zero_covariance}{Whether or not to assign covariances of 0 for each MVG} + +\item{shared_orientation}{Whether each cluster MVG should have the same orientation} + +\item{shared_shape}{Whether each cluster MVG should have the same shape} + +\item{shared_size}{Whether each cluster MVG should have the same size/volume} } \value{ string containing mclust model name diff --git a/tests/testthat/test-gm_clust.R b/tests/testthat/test-gm_clust.R index 5a25f9d..345d23c 100644 --- a/tests/testthat/test-gm_clust.R +++ b/tests/testthat/test-gm_clust.R @@ -6,7 +6,7 @@ test_that("primary arguments", { list( x = rlang::expr(missing_arg()), - G= rlang::expr(missing_arg()), + num_clusters = rlang::expr(missing_arg()), circular = rlang::expr(missing_arg()), zero_covariance = rlang::expr(missing_arg()), shared_orientation = rlang::expr(missing_arg()), @@ -32,7 +32,7 @@ test_that("engine arguments", { list( x = rlang::expr(missing_arg()), - G = rlang::expr(missing_arg()), + num_clusters = rlang::expr(missing_arg()), circular = rlang::expr(missing_arg()), zero_covariance = rlang::expr(missing_arg()), shared_orientation = rlang::expr(missing_arg()), From d99b707fef3af6133ad6ed636e5670b4b10d09d0 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:28:52 -0700 Subject: [PATCH 41/44] added skip_if_not_installed("mclust") for tests requiring mclust package --- tests/testthat/test-gm_clust-mclust.R | 12 ++++++++++++ tests/testthat/test-gm_clust.R | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tests/testthat/test-gm_clust-mclust.R b/tests/testthat/test-gm_clust-mclust.R index 12e499d..a9cae57 100644 --- a/tests/testthat/test-gm_clust-mclust.R +++ b/tests/testthat/test-gm_clust-mclust.R @@ -1,4 +1,7 @@ test_that("fitting", { + + skip_if_not_installed("mclust") + set.seed(1234) spec <- gm_clust(num_clusters = 3) %>% set_engine("mclust") @@ -13,6 +16,9 @@ test_that("fitting", { }) test_that("predicting", { + + skip_if_not_installed("mclust") + set.seed(1234) spec <- gm_clust(num_clusters = 3) %>% set_engine("mclust") @@ -28,6 +34,9 @@ test_that("predicting", { }) test_that("all levels are preserved with 1 row predictions", { + + skip_if_not_installed("mclust") + set.seed(1234) spec <- gm_clust(num_clusters = 3) %>% set_engine("mclust") @@ -43,6 +52,9 @@ test_that("all levels are preserved with 1 row predictions", { }) test_that("extract_centroids() works", { + + skip_if_not_installed("mclust") + set.seed(1234) spec <- gm_clust(num_clusters = 3) %>% set_engine("mclust") diff --git a/tests/testthat/test-gm_clust.R b/tests/testthat/test-gm_clust.R index 345d23c..6ae7eeb 100644 --- a/tests/testthat/test-gm_clust.R +++ b/tests/testthat/test-gm_clust.R @@ -53,6 +53,9 @@ test_that("bad input", { error = TRUE, gm_clust(mode = "bogus") ) + + skip_if_not_installed("mclust") + expect_snapshot( error = TRUE, { @@ -106,6 +109,9 @@ test_that("bad input", { }) test_that("predictions", { + + skip_if_not_installed("mclust") + set.seed(1234) mclust_fit <- gm_clust(num_clusters = 4) %>% @@ -135,6 +141,9 @@ test_that("predictions", { test_that("extract_centroids work", { + + skip_if_not_installed("mclust") + set.seed(1234) mclust_fit <- gm_clust(num_clusters = 4) %>% set_engine("mclust") %>% @@ -157,6 +166,9 @@ test_that("extract_centroids work", { test_that("predictions with new data", { + + skip_if_not_installed("mclust") + set.seed(1234) mclust_fit <- gm_clust(num_clusters = 4) %>% set_engine("mclust") %>% @@ -202,6 +214,9 @@ test_that("updating", { }) test_that("reordering is done correctly for gm_clust", { + + skip_if_not_installed("mclust") + set.seed(42) gm_fit <- gm_clust(num_clusters = 6) %>% @@ -217,6 +232,9 @@ test_that("reordering is done correctly for gm_clust", { }) test_that("model errors when parameters cannot be estimated", { + + skip_if_not_installed("mclust") + set.seed(42) expect_error( @@ -289,6 +307,9 @@ test_that("mappings to different model names are correct", { test_that("mappings to different model names are correct", { + + skip_if_not_installed("mclust") + set.seed(42) iris_sub <- iris %>% dplyr::select(Sepal.Length, Sepal.Width) From 75e829bc4b5faf4bf51abd87c0302d72ac5ae65b Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 1 Jul 2025 20:10:21 -0700 Subject: [PATCH 42/44] remove mclust import to tidyclust-package.R --- R/gm_clust.R | 2 -- R/tidyclust-package.R | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/R/gm_clust.R b/R/gm_clust.R index 8846500..7e838fd 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -22,8 +22,6 @@ #' @param shared_shape Boolean, whether each cluster MVG should have the same shape #' @param shared_size Boolean, whether each cluster MVG should have the same size/volume #' -#' @importFrom mclust mclustBIC -#' #' @details #' #' ## What does it mean to predict? diff --git a/R/tidyclust-package.R b/R/tidyclust-package.R index 523796a..3a7c2f3 100644 --- a/R/tidyclust-package.R +++ b/R/tidyclust-package.R @@ -4,6 +4,7 @@ ## usethis namespace: start #' @importFrom dplyr bind_cols #' @importFrom generics tunable tune_args +#' @importFrom mclust mclustBIC #' @importFrom parsnip make_call #' @importFrom parsnip maybe_data_frame #' @importFrom parsnip maybe_matrix From 8315a059afd18245f979f23d2132ce50e33ef77b Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Tue, 1 Jul 2025 20:16:01 -0700 Subject: [PATCH 43/44] add periods to documentation for gm_clust and db_clust --- R/db_clust.R | 12 ++++++------ R/gm_clust.R | 36 +++++++++++++++++----------------- man/db_clust.Rd | 4 ++-- man/dbscan_helper.Rd | 2 +- man/dot-db_clust_fit_dbscan.Rd | 6 +++--- man/dot-gm_clust_fit_mclust.Rd | 14 ++++++------- man/gm_clust.Rd | 10 +++++----- man/mclust_helper.Rd | 12 ++++++------ 8 files changed, 48 insertions(+), 48 deletions(-) diff --git a/R/db_clust.R b/R/db_clust.R index 9b01610..9317d9a 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -15,8 +15,8 @@ #' possible value for this model is `"partition"`. #' @param engine A single character string specifying what computational engine #' to use for fitting. The engine for this model is `"dbscan"`. -#' @param radius Positive double, Radius drawn around points to determine core-points and cluster assignments (required) -#' @param min_points Positive integer, Minimum number of points required to form a core-point (required) +#' @param radius Positive double, Radius drawn around points to determine core-points and cluster assignments (required). +#' @param min_points Positive integer, Minimum number of points required to form a core-point (required). #' #' #' @details @@ -151,9 +151,9 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { #' `dbscan::dbscan()` and retains the parameters `radius` or `min_points` as an #' attribute. #' -#' @param x matrix or data frame -#' @param radius Radius used to determine core-points and cluster points together -#' @param min_points Minimum number of points needed to form a cluster +#' @param x matrix or data frame. +#' @param radius Radius used to determine core-points and cluster points together. +#' @param min_points Minimum number of points needed to form a cluster. #' #' @return dbscan object #' @keywords internal @@ -189,7 +189,7 @@ translate_tidyclust.db_clust <- function(x, engine = x$engine, ...) { #' dbscan fit helper function #' #' This function returns the cluster assignments for the training data -#' based on their distance to the CLOSEST core point in the data +#' based on their distance to the CLOSEST core point in the data. #' #' @param object db_clust object #' diff --git a/R/gm_clust.R b/R/gm_clust.R index 7e838fd..b02dbd5 100644 --- a/R/gm_clust.R +++ b/R/gm_clust.R @@ -16,11 +16,11 @@ #' @param engine A single character string specifying what computational engine #' to use for fitting. The engine for this model is `"mclust"`. #' @param num_clusters Positive integer, number of clusters in model (required). -#' @param circular Boolean, whether or not to fit circular MVG distributions for each cluster -#' @param zero_covariance Boolean, whether or not to assign covariances of 0 for each MVG -#' @param shared_orientation Boolean, whether each cluster MVG should have the same orientation -#' @param shared_shape Boolean, whether each cluster MVG should have the same shape -#' @param shared_size Boolean, whether each cluster MVG should have the same size/volume +#' @param circular Boolean, whether or not to fit circular MVG distributions for each cluster. Default `TRUE`. +#' @param zero_covariance Boolean, whether or not to assign covariances of 0 for each MVG. Default `TRUE`. +#' @param shared_orientation Boolean, whether each cluster MVG should have the same orientation. Default `TRUE`. +#' @param shared_shape Boolean, whether each cluster MVG should have the same shape. Default `TRUE`. +#' @param shared_size Boolean, whether each cluster MVG should have the same size/volume. Default `TRUE`. #' #' @details #' @@ -190,13 +190,13 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { #' `mclust::Mclust` and retains the parameters `num_clusters` as an #' attribute. #' -#' @param x matrix or data frame -#' @param num_clusters Number of clusters -#' @param circular Whether or not to fit circular MVG distributions for each cluster -#' @param zero_covariance Whether or not to assign covariances of 0 for each MVG -#' @param shared_orientation Whether each cluster MVG should have the same orientation -#' @param shared_shape Whether each cluster MVG should have the same shape -#' @param shared_size Whether each cluster MVG should have the same size/volume +#' @param x matrix or data frame. +#' @param num_clusters Number of clusters. +#' @param circular Whether or not to fit circular MVG distributions for each cluster. +#' @param zero_covariance Whether or not to assign covariances of 0 for each MVG. +#' @param shared_orientation Whether each cluster MVG should have the same orientation. +#' @param shared_shape Whether each cluster MVG should have the same shape. +#' @param shared_size Whether each cluster MVG should have the same size/volume. #' #' @return mclust object #' @keywords internal @@ -307,13 +307,13 @@ translate_tidyclust.gm_clust <- function(x, engine = x$engine, ...) { #' mclust fit helper function #' #' This function returns the mclust model name based on the specified -#' TRUE/FALSE model arguments +#' TRUE/FALSE model arguments. #' -#' @param circular Whether or not to fit circular MVG distributions for each cluster -#' @param zero_covariance Whether or not to assign covariances of 0 for each MVG -#' @param shared_orientation Whether each cluster MVG should have the same orientation -#' @param shared_shape Whether each cluster MVG should have the same shape -#' @param shared_size Whether each cluster MVG should have the same size/volume +#' @param circular Whether or not to fit circular MVG distributions for each cluster. +#' @param zero_covariance Whether or not to assign covariances of 0 for each MVG. +#' @param shared_orientation Whether each cluster MVG should have the same orientation. +#' @param shared_shape Whether each cluster MVG should have the same shape. +#' @param shared_size Whether each cluster MVG should have the same size/volume. #' #' @return string containing mclust model name #' @keywords internal diff --git a/man/db_clust.Rd b/man/db_clust.Rd index 764ac65..a99989f 100644 --- a/man/db_clust.Rd +++ b/man/db_clust.Rd @@ -18,9 +18,9 @@ possible value for this model is \code{"partition"}.} \item{engine}{A single character string specifying what computational engine to use for fitting. The engine for this model is \code{"dbscan"}.} -\item{radius}{Positive double, Radius drawn around points to determine core-points and cluster assignments (required)} +\item{radius}{Positive double, Radius drawn around points to determine core-points and cluster assignments (required).} -\item{min_points}{Positive integer, Minimum number of points required to form a core-point (required)} +\item{min_points}{Positive integer, Minimum number of points required to form a core-point (required).} } \value{ A \code{db_clust} cluster specification. diff --git a/man/dbscan_helper.Rd b/man/dbscan_helper.Rd index d6dc43a..df3503c 100644 --- a/man/dbscan_helper.Rd +++ b/man/dbscan_helper.Rd @@ -14,6 +14,6 @@ numeric vector } \description{ This function returns the cluster assignments for the training data -based on their distance to the CLOSEST core point in the data +based on their distance to the CLOSEST core point in the data. } \keyword{internal} diff --git a/man/dot-db_clust_fit_dbscan.Rd b/man/dot-db_clust_fit_dbscan.Rd index 54fa451..3fa4a41 100644 --- a/man/dot-db_clust_fit_dbscan.Rd +++ b/man/dot-db_clust_fit_dbscan.Rd @@ -7,11 +7,11 @@ .db_clust_fit_dbscan(x, radius = NULL, min_points = NULL, ...) } \arguments{ -\item{x}{matrix or data frame} +\item{x}{matrix or data frame.} -\item{radius}{Radius used to determine core-points and cluster points together} +\item{radius}{Radius used to determine core-points and cluster points together.} -\item{min_points}{Minimum number of points needed to form a cluster} +\item{min_points}{Minimum number of points needed to form a cluster.} } \value{ dbscan object diff --git a/man/dot-gm_clust_fit_mclust.Rd b/man/dot-gm_clust_fit_mclust.Rd index 2324620..777b0c9 100644 --- a/man/dot-gm_clust_fit_mclust.Rd +++ b/man/dot-gm_clust_fit_mclust.Rd @@ -16,19 +16,19 @@ ) } \arguments{ -\item{x}{matrix or data frame} +\item{x}{matrix or data frame.} -\item{num_clusters}{Number of clusters} +\item{num_clusters}{Number of clusters.} -\item{circular}{Whether or not to fit circular MVG distributions for each cluster} +\item{circular}{Whether or not to fit circular MVG distributions for each cluster.} -\item{zero_covariance}{Whether or not to assign covariances of 0 for each MVG} +\item{zero_covariance}{Whether or not to assign covariances of 0 for each MVG.} -\item{shared_orientation}{Whether each cluster MVG should have the same orientation} +\item{shared_orientation}{Whether each cluster MVG should have the same orientation.} -\item{shared_shape}{Whether each cluster MVG should have the same shape} +\item{shared_shape}{Whether each cluster MVG should have the same shape.} -\item{shared_size}{Whether each cluster MVG should have the same size/volume} +\item{shared_size}{Whether each cluster MVG should have the same size/volume.} } \value{ mclust object diff --git a/man/gm_clust.Rd b/man/gm_clust.Rd index 385ada3..4b313db 100644 --- a/man/gm_clust.Rd +++ b/man/gm_clust.Rd @@ -24,15 +24,15 @@ to use for fitting. The engine for this model is \code{"mclust"}.} \item{num_clusters}{Positive integer, number of clusters in model (required).} -\item{circular}{Boolean, whether or not to fit circular MVG distributions for each cluster} +\item{circular}{Boolean, whether or not to fit circular MVG distributions for each cluster. Default \code{TRUE}.} -\item{shared_size}{Boolean, whether each cluster MVG should have the same size/volume} +\item{shared_size}{Boolean, whether each cluster MVG should have the same size/volume. Default \code{TRUE}.} -\item{zero_covariance}{Boolean, whether or not to assign covariances of 0 for each MVG} +\item{zero_covariance}{Boolean, whether or not to assign covariances of 0 for each MVG. Default \code{TRUE}.} -\item{shared_orientation}{Boolean, whether each cluster MVG should have the same orientation} +\item{shared_orientation}{Boolean, whether each cluster MVG should have the same orientation. Default \code{TRUE}.} -\item{shared_shape}{Boolean, whether each cluster MVG should have the same shape} +\item{shared_shape}{Boolean, whether each cluster MVG should have the same shape. Default \code{TRUE}.} } \value{ A \code{gm_clust} cluster specification. diff --git a/man/mclust_helper.Rd b/man/mclust_helper.Rd index 68aac2e..1c950eb 100644 --- a/man/mclust_helper.Rd +++ b/man/mclust_helper.Rd @@ -13,21 +13,21 @@ mclust_helper( ) } \arguments{ -\item{circular}{Whether or not to fit circular MVG distributions for each cluster} +\item{circular}{Whether or not to fit circular MVG distributions for each cluster.} -\item{zero_covariance}{Whether or not to assign covariances of 0 for each MVG} +\item{zero_covariance}{Whether or not to assign covariances of 0 for each MVG.} -\item{shared_orientation}{Whether each cluster MVG should have the same orientation} +\item{shared_orientation}{Whether each cluster MVG should have the same orientation.} -\item{shared_shape}{Whether each cluster MVG should have the same shape} +\item{shared_shape}{Whether each cluster MVG should have the same shape.} -\item{shared_size}{Whether each cluster MVG should have the same size/volume} +\item{shared_size}{Whether each cluster MVG should have the same size/volume.} } \value{ string containing mclust model name } \description{ This function returns the mclust model name based on the specified -TRUE/FALSE model arguments +TRUE/FALSE model arguments. } \keyword{internal} From 2fa05fb0a4768c6e12bf77c910305143f4e45408 Mon Sep 17 00:00:00 2001 From: brendad8 <72055001+brendad8@users.noreply.github.com> Date: Fri, 4 Jul 2025 19:26:53 -0700 Subject: [PATCH 44/44] slight update to db_clust param description --- R/db_clust.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/db_clust.R b/R/db_clust.R index 9317d9a..d324755 100644 --- a/R/db_clust.R +++ b/R/db_clust.R @@ -16,7 +16,7 @@ #' @param engine A single character string specifying what computational engine #' to use for fitting. The engine for this model is `"dbscan"`. #' @param radius Positive double, Radius drawn around points to determine core-points and cluster assignments (required). -#' @param min_points Positive integer, Minimum number of points required to form a core-point (required). +#' @param min_points Positive integer, Minimum number of connected points required to form a core-point, including the point itself (required). #' #' #' @details