--- title: "A real-data audit of Palmer penguin morphology" author: "Shaowen Ye" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{A real-data audit of Palmer penguin morphology} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} has_tutorial_dependencies <- requireNamespace("palmerpenguins", quietly = TRUE) && requireNamespace("ggplot2", quietly = TRUE) knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = has_tutorial_dependencies ) ``` ## Purpose and inferential boundary This tutorial uses an openly licensed, familiar dataset to show the complete workflow on real observations. It does not claim that penguin species are latent SOM classes or that morphology alone defines species. The four morphological variables are used for unsupervised training. Species is retained only as an external label and is inspected after the ensemble and consensus partition have been constructed. The data are distributed by the [`palmerpenguins`](https://allisonhorst.github.io/palmerpenguins/) package under CC0. Measurements were collected for Adelie, Chinstrap, and Gentoo penguins in the Palmer Archipelago from 2007 to 2009. The original data publication and source citations are provided by the data package. If the optional tutorial dependencies are unavailable, the code is displayed but not evaluated when the vignette is built. ## Build a design-explicit data object ```{r prepare-data} library(SOMevidence) raw <- palmerpenguins::penguins variables <- c( "bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g" ) keep <- stats::complete.cases(raw[, c(variables, "species", "year")]) penguins <- raw[keep, , drop = FALSE] sample_ids <- sprintf("penguin_%03d", seq_len(nrow(penguins))) morphology <- som_data( x = penguins[, variables], id = sample_ids, time = penguins$year, domain = factor(penguins$year), external_label = stats::setNames(as.character(penguins$species), sample_ids) ) morphology ``` Stable row identifiers make later joins auditable. Sampling year is declared as a transfer domain. Species is stored in metadata and never enters the SOM input matrix. ## Prespecify the transfer design and ensemble budget Each split below leaves out one sampling year. The map and every preprocessing quantity are fitted using the other years; observations from the held-out year are assessment data. This demonstration uses a small budget so that the vignette remains quick to build. A substantive analysis should justify its grids, seeds, iterations, candidate `k`, and transfer domains before fitting. ```{r design} year_splits <- som_resamples( morphology, method = "leave_domain_out", domain = "domain" ) spec <- som_spec( grids = list(c(4, 3), c(5, 4)), seeds = c(41, 42), rlen = 50, k = 2:4 ) year_splits expand_som_spec(spec) ``` ## Fit once and retain separate evidence streams ```{r workflow} workflow <- run_som_workflow( morphology, spec, year_splits, preprocess = som_preprocess(center = TRUE, scale = TRUE), cross_models = c("kmeans", "ward") ) workflow ``` The representation audit, partition audit, consensus summaries, cross-model comparison, and transfer audit answer different questions. They should not be collapsed into a single rank. ```{r summaries} workflow$audit$grid_summary workflow$partitions$stability workflow$consensus$k3$cluster_summary workflow$cross_comparison$summary transfer <- audit_transfer(workflow$ensemble) transfer$metrics successful_ids <- vapply( Filter(function(fit) isTRUE(fit$success), workflow$ensemble$fits), `[[`, character(1), "id" ) representation <- audit_som_representation( workflow$ensemble, pairs = data.frame( fit_a = successful_ids[[1]], fit_b = successful_ids[[2]] ), neighbourhood_size = 10 ) representation$pairwise ``` ```{r evidence-plots, fig.width = 7, fig.height = 4, out.width = "90%"} plot(workflow$audit) plot(workflow$partitions) plot(transfer) ``` Quantization and topographic errors concern the SOM representation. ARI and AMI between SOM and reference partitions concern agreement under a shared analysis design. Held-year distance and occupancy diagnostics concern transfer. None of these quantities is classification accuracy. The experimental topology comparison is likewise descriptive and applies only to the prespecified fit pair and jointly mapped observations shown above. ## Inspect external labels only after consensus For illustration, inspect `k = 3` because the dataset contains three recorded species. This is a prespecified teaching choice, not evidence that `k = 3` is the optimal unsupervised partition. ```{r external-labels} consensus_k3 <- workflow$consensus$k3 external <- evaluate_external_labels(consensus_k3) external external$contingency external$composition ``` The resulting ARI, AMI, and contingency table describe agreement between one consensus partition and the recorded species labels among evaluable samples. They do not establish that the partition is biologically correct, and they do not validate the package. The example instead demonstrates how labels can be kept outside training and introduced transparently at the interpretation stage. ## Reproducibility record Archive the package version, software environment, input provenance, and exact analysis choices with any reported result. ```{r reproducibility} packageVersion("SOMevidence") packageVersion("palmerpenguins") sessionInfo() ```