## ----include = FALSE---------------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "##", fig.width = 7, fig.height = 5, warning = FALSE, message = FALSE ) ## ----setup-------------------------------------------------------------------- library(DistributionalDDA) ## ----load-data---------------------------------------------------------------- data("age") str(age) ## ----explore-data------------------------------------------------------------- # Number of observations nrow(age$data) # The age midpoints age$ages # First few rows of the data head(age$data[, 1:7]) # Check that distributions sum to 1 summary(rowSums(age$distributions)) ## ----plot-raw, fig.height=6--------------------------------------------------- # Plot all distributions with transparency, plus the mean matplot(age$ages, t(age$distributions), type = "l", lty = 1, col = adjustcolor("gray", alpha.f = 0.4), xlab = "Age", ylab = "Proportion", main = "All Age Distributions with Mean") # Add the mean distribution meanDist <- colMeans(age$distributions) lines(age$ages, meanDist, col = "black", lwd = 3) legend("topright", c("Individual", "Mean"), col = c("gray", "black"), lwd = c(1, 3)) ## ----plot-by-sex, fig.height=6------------------------------------------------ # Separate by sex maleIdx <- which(age$data$sex == "male") femaleIdx <- which(age$data$sex == "female") # Plot all distributions colored by sex matplot(age$ages, t(age$distributions[maleIdx, ]), type = "l", lty = 1, col = adjustcolor("blue", alpha.f = 0.3), ylim = c(0, 0.1), xlab = "Age", ylab = "Proportion", main = "Age Distributions by Sex") matlines(age$ages, t(age$distributions[femaleIdx, ]), lty = 1, col = adjustcolor("red", alpha.f = 0.3)) # Add means for each sex lines(age$ages, colMeans(age$distributions[maleIdx, ]), col = "blue", lwd = 3) lines(age$ages, colMeans(age$distributions[femaleIdx, ]), col = "red", lwd = 3) legend("topright", c("Male", "Female"), col = c("blue", "red"), lwd = 3) ## ----create-basis------------------------------------------------------------- # Reference measure: Uniform on [0, 100] rmAge <- ReferenceMeasureUniform(0, 100) # Create the Bayes space B2Age <- BayesSpace(rmAge) B2Age # Create a basis with 7 dimensions # (this provides a good balance between flexibility and parsimony) basisAge <- BayesSpaceBasis(B2Age, nbasis = 7) basisAge ## ----convert-to-bdata--------------------------------------------------------- # Define the histogram breaks # Note: The last bin (90-100) is 10 years wide, others are 5 years breaks <- c(0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 100) # Create density histograms from the proportions ageHist <- BDataDensityHistograms(age$distributions, breaks = breaks, basis = basisAge) class(ageHist) dim(ageHist) # Convert to continuous densities ageDensities <- as.BDataDensities(ageHist) # Convert to spline representation (needed for PCA) ageSplines <- as.BDataSplines(ageDensities) class(ageSplines) dim(ageSplines) ## ----plot-bdata, fig.height=6------------------------------------------------- # Plot all distributions as PDFs with transparency plot(ageSplines, as = "PDF", col = adjustcolor("gray", alpha.f = 0.4), main = "All Age Distributions (as PDFs) with Mean") # Add the mean distribution meanAge <- mean(ageSplines) plot(meanAge, as = "PDF", add = TRUE, col = "black", lwd = 3) legend("topright", c("Individual", "Mean"), col = c("gray", "black"), lwd = c(1, 3)) ## ----plot-bdata-sex, fig.height=6--------------------------------------------- # Plot by sex with transparency maleSplines <- BDataSplines(unclass(ageSplines)[maleIdx, ], basis = basisAge) femaleSplines <- BDataSplines(unclass(ageSplines)[femaleIdx, ], basis = basisAge) plot(maleSplines, as = "PDF", col = adjustcolor("blue", alpha.f = 0.3), main = "Age Distributions by Sex (as PDFs)") plot(femaleSplines, as = "PDF", col = adjustcolor("red", alpha.f = 0.3), add = TRUE) # Add sex-specific means plot(mean(maleSplines), as = "PDF", add = TRUE, col = "blue", lwd = 3) plot(mean(femaleSplines), as = "PDF", add = TRUE, col = "red", lwd = 3) legend("topright", c("Male", "Female"), col = c("blue", "red"), lwd = 3) ## ----run-pca------------------------------------------------------------------ pcaAge <- princomp(ageSplines) pcaAge ## ----pca-summary-------------------------------------------------------------- summary(pcaAge) ## ----screeplot---------------------------------------------------------------- plot(pcaAge, type = "screeplot") ## ----variance-plot------------------------------------------------------------ plot(pcaAge, type = "variance") ## ----score-plot, fig.height=6------------------------------------------------- # Basic score plot plot(pcaAge, type = "scores") ## ----scores-by-sex, fig.height=6---------------------------------------------- # Create color vector sexColors <- ifelse(age$data$sex == "male", "blue", "red") # Score plot colored by sex plot(pcaAge, type = "scores", col = sexColors) legend("topright", c("Male", "Female"), col = c("blue", "red"), pch = 19) ## ----scores-with-labels, fig.height=6----------------------------------------- # Use row names as labels (commune codes) plot(pcaAge, type = "scores", labels = TRUE, col = sexColors, cex = 0.7) ## ----loadings-plot, fig.height=6---------------------------------------------- # Use colorblind-friendly colors: black (mean), blue (PC1), orange (PC2) cbPalette <- c("black", "blue", "orange") plot(pcaAge, type = "loadings", npcs = 2, col = cbPalette) ## ----loadings-scaled, fig.height=6-------------------------------------------- # Show +/- 2 standard deviations from mean plot(pcaAge, type = "loadings", npcs = 2, scale.sdev = 2, col = cbPalette) ## ----loadings-clr, fig.height=6----------------------------------------------- # Centered log-ratio (CLR) representation plot(pcaAge, type = "loadings", npcs = 2, as = "clr", col = cbPalette) ## ----covariance, fig.height=6------------------------------------------------- plot(pcaAge, type = "covariance") ## ----reconstruction, fig.height=6--------------------------------------------- # Reconstruct using only 2 PCs with transparency sexColorsTransp <- ifelse(age$data$sex == "male", adjustcolor("blue", alpha.f = 0.3), adjustcolor("red", alpha.f = 0.3)) plot(pcaAge, type = "reconstruction", npcs = 2, col = sexColorsTransp) ## ----boxplot------------------------------------------------------------------ plot(pcaAge, type = "boxplot", npcs = 4) ## ----biplot, fig.height=6----------------------------------------------------- biplot(pcaAge) ## ----grouped-pca-------------------------------------------------------------- pcaGrouped <- princomp(ageSplines, group = age$data$sex) pcaGrouped ## ----grouped-screeplot, fig.width=10------------------------------------------ plot(pcaGrouped, type = "screeplot") ## ----grouped-loadings, fig.width=10------------------------------------------- plot(pcaGrouped, type = "loadings", npcs = 2) ## ----grouped-scores, fig.width=10--------------------------------------------- plot(pcaGrouped, type = "scores") ## ----multivariate-pca--------------------------------------------------------- pcaMulti <- princomp(ageSplines, group = age$data$sex, multivariate = TRUE) pcaMulti ## ----multi-screeplot---------------------------------------------------------- plot(pcaMulti, type = "screeplot") ## ----multi-scores------------------------------------------------------------- plot(pcaMulti, type = "scores") ## ----multi-eigenfunctions, fig.width=10, fig.height=6------------------------- plot(pcaMulti, type = "eigenfunctions", npcs = 2) ## ----predict-example---------------------------------------------------------- # Suppose we have the first 5 observations as "training" data # and want to project observations 6-10 as "new" data # Create a subset as new BDataSplines (subsetting keeps the class) newAgeSplines <- BDataSplines(unclass(ageSplines)[6:10, ], basis = basisAge) # The pcaAge model was fit on all data, but let's demonstrate predict(): newScores <- predict(pcaAge, newAgeSplines) print(newScores[, 1:3]) # Show first 3 PCs # Compare with the actual scores actualScores <- pcaAge$scores[6:10, 1:3] print(actualScores) # They should be identical (since we used the same data) ## ----workflow-summary, eval=FALSE--------------------------------------------- # # 1. Load data # data("age") # # # 2. Create Bayes space and basis # rmAge <- ReferenceMeasureUniform(0, 100) # basisAge <- BayesSpaceBasis(BayesSpace(rmAge), nbasis = 7) # # # 3. Convert to BData (adapt based on your data format) # breaks <- c(0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, # 55, 60, 65, 70, 75, 80, 85, 90, 100) # ageSplines <- # BDataDensityHistograms(age$distributions, # breaks = breaks, # basis = basisAge) |> # as.BataDensities() |> # as.BDataSplines() # pipe |> instead of nesting # # # 4. Run PCA # pcaResult <- princomp(ageSplines) # # # 5. Explore results # summary(pcaResult) # Variance explained # plot(pcaResult, type = "screeplot") # How many components? # plot(pcaResult, type = "loadings", npcs = 2) # What do components mean? # plot(pcaResult, type = "scores", col = myColors) # Where are my observations? # # # 6. Optional: Separate grouped analysis (compare groups) # pcaGrouped <- princomp(ageSplines, group = age$data$sex) # plot(pcaGrouped, type = "loadings", npcs = 2) # Compare groups # # # 7. Optional: Multivariate SFPCA (joint analysis, requires paired data) # pcaMulti <- princomp(ageSplines, group = age$data$sex, multivariate = TRUE) # plot(pcaMulti, type = "eigenfunctions", npcs = 2) # Cross-group covariation ## ----session-info------------------------------------------------------------- sessionInfo()