Correlation Analysis
S
# Comprehensive Correlation Analysis for Biomedical Data
#
# This implementation provides multiple correlation analysis methods:
# 1. Pearson correlation (linear relationships, parametric)
# 2. Spearman correlation (monotonic relationships, non-parametric)
# 3. Kendall's tau (robust to outliers, non-parametric)
# 4. Partial correlation (controlling for confounding variables)
# 5. Correlation matrix analysis with multiple testing correction
#
# Applications in biomedical research:
# - Investigating relationships between biomarkers and outcomes
# - Analyzing dose-response relationships in pharmacology
# - Studying associations between physiological measurements
# - Quality control in laboratory measurements
# - Gene expression correlation studies
# - Clinical trial endpoint relationships
#
# Time Complexity: O(n) for pairwise correlations, O(n*p^2) for partial correlations
# Space Complexity: O(p^2) for correlation matrices, O(n) for pairwise analysis
# Comprehensive correlation analysis function
correlation_analysis <- function(x, y = NULL, method = "pearson", conf.level = 0.95,
plot = TRUE, plot_title = "Correlation Analysis") {
#' Comprehensive Correlation Analysis
#'
#' Performs correlation analysis with confidence intervals and significance testing
#'
#' @param x numeric vector or matrix of data
#' @param y numeric vector (if x is a vector) or NULL (if x is a matrix)
#' @param method character: "pearson", "spearman", or "kendall"
#' @param conf.level confidence level for confidence intervals
#' @param plot logical: whether to create visualization
#' @param plot_title character: title for the plot
#' @return list with correlation results
# Input validation
if (is.matrix(x) || is.data.frame(x)) {
if (!is.null(y)) {
warning("y is ignored when x is a matrix or data frame")
}
return(correlation_matrix_analysis(x, method, conf.level, plot, plot_title))
}
if (!is.numeric(x) || !is.numeric(y)) {
stop("Both x and y must be numeric")
}
if (length(x) != length(y)) {
stop("x and y must have the same length")
}
if (!method %in% c("pearson", "spearman", "kendall")) {
stop("method must be 'pearson', 'spearman', or 'kendall'")
}
# Remove missing values
complete_pairs <- complete.cases(x, y)
x_clean <- x[complete_pairs]
y_clean <- y[complete_pairs]
n <- length(x_clean)
if (n < 3) {
stop("Need at least 3 complete pairs for correlation analysis")
}
# Calculate correlation and test
if (method == "pearson") {
result <- pearson_correlation(x_clean, y_clean, conf.level)
} else if (method == "spearman") {
result <- spearman_correlation(x_clean, y_clean, conf.level)
} else { # kendall
result <- kendall_correlation(x_clean, y_clean, conf.level)
}
# Add sample information
result$sample_size <- n
result$missing_pairs <- length(x) - n
# Simple title case function (replace stringr dependency)
title_case <- function(s) paste0(toupper(substr(s, 1, 1)), tolower(substr(s, 2, nchar(s))))
result$method <- paste(title_case(method), "correlation coefficient")
# Create visualization
if (plot) {
create_correlation_plot(x_clean, y_clean, result, plot_title)
}
class(result) <- "biomedical_correlation"
return(result)
}
# Pearson correlation implementation
pearson_correlation <- function(x, y, conf.level = 0.95) {
n <- length(x)
# Calculate Pearson correlation coefficient
r <- cor(x, y, method = "pearson")
# Test statistic and p-value
t_stat <- r * sqrt((n - 2) / (1 - r^2))
df <- n - 2
p_value <- 2 * pt(abs(t_stat), df, lower.tail = FALSE)
# Confidence interval using Fisher's Z transformation
z_r <- 0.5 * log((1 + r) / (1 - r)) # Fisher's Z
se_z <- 1 / sqrt(n - 3)
alpha <- 1 - conf.level
z_critical <- qnorm(1 - alpha/2)
z_lower <- z_r - z_critical * se_z
z_upper <- z_r + z_critical * se_z
# Transform back to correlation scale
ci_lower <- (exp(2 * z_lower) - 1) / (exp(2 * z_lower) + 1)
ci_upper <- (exp(2 * z_upper) - 1) / (exp(2 * z_upper) + 1)
# Effect size interpretation
r_squared <- r^2
return(list(
correlation = r,
t_statistic = t_stat,
p_value = p_value,
degrees_of_freedom = df,
confidence_interval = c(ci_lower, ci_upper),
confidence_level = conf.level,
r_squared = r_squared,
fishers_z = z_r,
assumptions_check = check_pearson_assumptions(x, y)
))
}
# Spearman correlation implementation
spearman_correlation <- function(x, y, conf.level = 0.95) {
n <- length(x)
# Calculate Spearman correlation coefficient
rho <- cor(x, y, method = "spearman")
# Test statistic (approximate for large n)
if (n > 10) {
t_stat <- rho * sqrt((n - 2) / (1 - rho^2))
df <- n - 2
p_value <- 2 * pt(abs(t_stat), df, lower.tail = FALSE)
} else {
# Exact test for small samples (simplified)
warning("Small sample size: p-value may be approximate")
t_stat <- rho * sqrt((n - 2) / (1 - rho^2))
df <- n - 2
p_value <- 2 * pt(abs(t_stat), df, lower.tail = FALSE)
}
# Confidence interval (approximate using Fisher's Z)
z_rho <- 0.5 * log((1 + rho) / (1 - rho))
se_z <- 1.06 / sqrt(n - 3) # Adjusted standard error for Spearman
alpha <- 1 - conf.level
z_critical <- qnorm(1 - alpha/2)
z_lower <- z_rho - z_critical * se_z
z_upper <- z_rho + z_critical * se_z
ci_lower <- (exp(2 * z_lower) - 1) / (exp(2 * z_lower) + 1)
ci_upper <- (exp(2 * z_upper) - 1) / (exp(2 * z_upper) + 1)
return(list(
correlation = rho,
t_statistic = t_stat,
p_value = p_value,
degrees_of_freedom = df,
confidence_interval = c(ci_lower, ci_upper),
confidence_level = conf.level,
rank_based = TRUE
))
}
# Kendall's tau correlation implementation
kendall_correlation <- function(x, y, conf.level = 0.95) {
n <- length(x)
# Calculate Kendall's tau
tau <- cor(x, y, method = "kendall")
# Test statistic for Kendall's tau
var_tau <- 2 * (2*n + 5) / (9 * n * (n - 1))
z_stat <- tau / sqrt(var_tau)
p_value <- 2 * pnorm(abs(z_stat), lower.tail = FALSE)
# Confidence interval (approximate)
alpha <- 1 - conf.level
z_critical <- qnorm(1 - alpha/2)
ci_lower <- tau - z_critical * sqrt(var_tau)
ci_upper <- tau + z_critical * sqrt(var_tau)
# Ensure CI is within [-1, 1]
ci_lower <- max(ci_lower, -1)
ci_upper <- min(ci_upper, 1)
return(list(
correlation = tau,
z_statistic = z_stat,
p_value = p_value,
confidence_interval = c(ci_lower, ci_upper),
confidence_level = conf.level,
robust = TRUE
))
}
# Check assumptions for Pearson correlation
check_pearson_assumptions <- function(x, y) {
n <- length(x)
# 1. Normality test (Shapiro-Wilk for n <= 5000)
if (n <= 5000) {
shapiro_x <- shapiro.test(x)
shapiro_y <- shapiro.test(y)
normality_x <- shapiro_x$p.value > 0.05
normality_y <- shapiro_y$p.value > 0.05
} else {
# Use Kolmogorov-Smirnov for large samples
ks_x <- ks.test(x, "pnorm", mean(x), sd(x))
ks_y <- ks.test(y, "pnorm", mean(y), sd(y))
normality_x <- ks_x$p.value > 0.05
normality_y <- ks_y$p.value > 0.05
}
# 2. Linearity check (correlation between x and y vs. x and y^2)
linear_corr <- abs(cor(x, y))
nonlinear_corr <- abs(cor(x, y^2))
linearity <- linear_corr > nonlinear_corr
# 3. Homoscedasticity check (Breusch-Pagan-like test)
residuals <- y - predict(lm(y ~ x))
bp_stat <- cor(x, abs(residuals))^2
homoscedasticity <- bp_stat < 0.1 # Rough threshold
# 4. Outlier detection (using IQR method)
outliers_x <- detect_outliers(x)
outliers_y <- detect_outliers(y)
no_outliers <- length(outliers_x) == 0 && length(outliers_y) == 0
return(list(
normality_x = normality_x,
normality_y = normality_y,
linearity = linearity,
homoscedasticity = homoscedasticity,
no_outliers = no_outliers,
outliers_x = outliers_x,
outliers_y = outliers_y,
overall_suitable = normality_x && normality_y && linearity && homoscedasticity && no_outliers
))
}
# Outlier detection using IQR method
detect_outliers <- function(x) {
Q1 <- quantile(x, 0.25)
Q3 <- quantile(x, 0.75)
IQR <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR
outlier_indices <- which(x < lower_bound | x > upper_bound)
return(outlier_indices)
}
# Correlation matrix analysis
correlation_matrix_analysis <- function(data, method = "pearson", conf.level = 0.95,
plot = TRUE, plot_title = "Correlation Matrix") {
# Convert to matrix if data frame
if (is.data.frame(data)) {
numeric_cols <- sapply(data, is.numeric)
if (!all(numeric_cols)) {
warning("Non-numeric columns removed from analysis")
data <- data[, numeric_cols, drop = FALSE]
}
data <- as.matrix(data)
}
# Remove rows with missing values
complete_rows <- complete.cases(data)
data_clean <- data[complete_rows, , drop = FALSE]
n <- nrow(data_clean)
p <- ncol(data_clean)
if (n < 3) stop("Need at least 3 complete observations")
if (p < 2) stop("Need at least 2 variables")
# Calculate correlation matrix
cor_matrix <- cor(data_clean, method = method)
# Calculate p-values for all pairs
p_matrix <- matrix(1, nrow = p, ncol = p)
colnames(p_matrix) <- rownames(p_matrix) <- colnames(data_clean)
for (i in 1:(p-1)) {
for (j in (i+1):p) {
if (method == "pearson") {
test_result <- cor.test(data_clean[, i], data_clean[, j], method = "pearson")
} else if (method == "spearman") {
test_result <- cor.test(data_clean[, i], data_clean[, j], method = "spearman")
} else {
test_result <- cor.test(data_clean[, i], data_clean[, j], method = "kendall")
}
p_matrix[i, j] <- p_matrix[j, i] <- test_result$p.value
}
}
# Multiple testing correction
p_values_upper <- p_matrix[upper.tri(p_matrix)]
p_adjusted_bonferroni <- p.adjust(p_values_upper, method = "bonferroni")
p_adjusted_fdr <- p.adjust(p_values_upper, method = "fdr")
# Create adjusted p-value matrices
p_bonferroni <- p_fdr <- matrix(1, nrow = p, ncol = p)
colnames(p_bonferroni) <- rownames(p_bonferroni) <- colnames(data_clean)
colnames(p_fdr) <- rownames(p_fdr) <- colnames(data_clean)
counter <- 1
for (i in 1:(p-1)) {
for (j in (i+1):p) {
p_bonferroni[i, j] <- p_bonferroni[j, i] <- p_adjusted_bonferroni[counter]
p_fdr[i, j] <- p_fdr[j, i] <- p_adjusted_fdr[counter]
counter <- counter + 1
}
}
# Create visualization
if (plot) {
create_correlation_matrix_plot(cor_matrix, p_matrix, data_clean, plot_title)
}
# Simple title case function
title_case <- function(s) paste0(toupper(substr(s, 1, 1)), tolower(substr(s, 2, nchar(s))))
result <- list(
correlation_matrix = cor_matrix,
p_values = p_matrix,
p_values_bonferroni = p_bonferroni,
p_values_fdr = p_fdr,
sample_size = n,
variables = p,
method = paste(title_case(method), "correlation matrix"),
missing_rows = nrow(data) - n,
significant_pairs_uncorrected = sum(p_matrix < 0.05 & upper.tri(p_matrix)),
significant_pairs_bonferroni = sum(p_bonferroni < 0.05 & upper.tri(p_bonferroni)),
significant_pairs_fdr = sum(p_fdr < 0.05 & upper.tri(p_fdr))
)
class(result) <- "biomedical_correlation_matrix"
return(result)
}
# Create correlation plot for two variables
create_correlation_plot <- function(x, y, result, main_title) {
par(mfrow = c(2, 2), mar = c(4, 4, 3, 2))
# 1. Scatter plot with regression line
plot(x, y, pch = 19, col = "darkblue", cex = 1.2,
main = paste(main_title, "\nScatter Plot"),
xlab = "X Variable", ylab = "Y Variable")
# Add regression line
if ("assumptions_check" %in% names(result) && result$assumptions_check$linearity) {
abline(lm(y ~ x), col = "red", lwd = 2)
} else {
# Add lowess smoother for non-linear relationships
lines(lowess(x, y), col = "red", lwd = 2)
}
# Add correlation info
legend("topleft",
c(paste("r =", round(result$correlation, 3)),
paste("p =", round(result$p_value, 4))),
bty = "n", cex = 1.1)
# 2. Residuals plot (if Pearson)
if ("assumptions_check" %in% names(result)) {
fitted_values <- predict(lm(y ~ x))
residuals <- y - fitted_values
plot(fitted_values, residuals, pch = 19, col = "darkgreen",
main = "Residuals vs Fitted", xlab = "Fitted Values", ylab = "Residuals")
abline(h = 0, col = "red", lwd = 2, lty = 2)
# Add lowess line to check for patterns
lines(lowess(fitted_values, residuals), col = "blue", lwd = 2)
} else {
# For non-parametric methods, show rank plot
plot(rank(x), rank(y), pch = 19, col = "darkgreen",
main = "Rank Plot", xlab = "Rank of X", ylab = "Rank of Y")
abline(lm(rank(y) ~ rank(x)), col = "red", lwd = 2)
}
# 3. Q-Q plots for normality (if Pearson)
if ("assumptions_check" %in% names(result)) {
qqnorm(x, main = "Q-Q Plot X", pch = 19, col = "blue")
qqline(x, col = "red", lwd = 2)
} else {
# Histogram for non-parametric
hist(x, main = "Distribution of X", xlab = "X Values",
col = "lightblue", probability = TRUE)
lines(density(x), col = "red", lwd = 2)
}
# 4. Test summary
plot(1, 1, type = "n", xlim = c(0, 10), ylim = c(0, 10),
main = "Correlation Summary", xlab = "", ylab = "", axes = FALSE)
text(5, 9.5, strsplit(result$method, " correlation")[[1]][1], cex = 1.2, font = 2)
text(5, 8.7, paste("Correlation:", round(result$correlation, 4)), cex = 1.1)
text(5, 8.1, paste("p-value:", round(result$p_value, 6)), cex = 1.1)
if ("degrees_of_freedom" %in% names(result)) {
text(5, 7.5, paste("df:", result$degrees_of_freedom), cex = 1.1)
}
text(5, 6.9, paste("Sample size:", result$sample_size), cex = 1.1)
# Confidence interval
ci_text <- paste(result$confidence_level * 100, "% CI: [",
round(result$confidence_interval[1], 3), ", ",
round(result$confidence_interval[2], 3), "]", sep = "")
text(5, 6.3, ci_text, cex = 1)
# Effect size
if ("r_squared" %in% names(result)) {
text(5, 5.7, paste("R-squared:", round(result$r_squared, 4)), cex = 1)
}
# Significance
sig_level <- ifelse(result$p_value < 0.001, "***",
ifelse(result$p_value < 0.01, "**",
ifelse(result$p_value < 0.05, "*", "ns")))
text(5, 5.1, paste("Significance:", sig_level), cex = 1.1,
col = ifelse(sig_level == "ns", "red", "darkgreen"))
# Interpretation
r_abs <- abs(result$correlation)
magnitude <- if (r_abs < 0.1) "negligible"
else if (r_abs < 0.3) "small"
else if (r_abs < 0.5) "medium"
else if (r_abs < 0.7) "large"
else "very large"
text(5, 4.3, paste("Effect size:", magnitude), cex = 1)
# Assumptions check (if available)
if ("assumptions_check" %in% names(result)) {
assumptions_ok <- result$assumptions_check$overall_suitable
text(5, 3.5, paste("Assumptions met:", assumptions_ok), cex = 1,
col = ifelse(assumptions_ok, "darkgreen", "orange"))
}
par(mfrow = c(1, 1))
}
# Create correlation matrix visualization
create_correlation_matrix_plot <- function(cor_matrix, p_matrix, data, main_title) {
p <- ncol(cor_matrix)
par(mfrow = c(2, 2), mar = c(5, 5, 3, 2))
# 1. Correlation heatmap
image(1:p, 1:p, cor_matrix, col = colorRampPalette(c("blue", "white", "red"))(20),
main = paste(main_title, "\nCorrelation Matrix"),
xlab = "", ylab = "", axes = FALSE, zlim = c(-1, 1))
axis(1, at = 1:p, labels = colnames(cor_matrix), las = 2, cex.axis = 0.8)
axis(2, at = 1:p, labels = colnames(cor_matrix), las = 2, cex.axis = 0.8)
# Add correlation values
for (i in 1:p) {
for (j in 1:p) {
if (i != j) {
text(j, i, round(cor_matrix[i, j], 2), cex = 0.8,
col = ifelse(abs(cor_matrix[i, j]) > 0.5, "white", "black"))
}
}
}
# 2. P-value heatmap
log_p <- -log10(p_matrix + 1e-16) # Add small constant to avoid log(0)
image(1:p, 1:p, log_p, col = heat.colors(20),
main = "Significance (-log10 p-values)",
xlab = "", ylab = "", axes = FALSE)
axis(1, at = 1:p, labels = colnames(p_matrix), las = 2, cex.axis = 0.8)
axis(2, at = 1:p, labels = colnames(p_matrix), las = 2, cex.axis = 0.8)
# Add significance markers
for (i in 1:p) {
for (j in 1:p) {
if (i != j) {
sig_marker <- if (p_matrix[i, j] < 0.001) "***"
else if (p_matrix[i, j] < 0.01) "**"
else if (p_matrix[i, j] < 0.05) "*"
else ""
text(j, i, sig_marker, cex = 1.2, font = 2, col = "darkred")
}
}
}
# 3. Scatterplot matrix (subset if too many variables)
if (p <= 5) {
pairs(data, pch = 19, col = "darkblue", cex = 0.8, main = "Scatterplot Matrix")
} else {
# Show first 4 variables
pairs(data[, 1:4], pch = 19, col = "darkblue", cex = 0.8,
main = "Scatterplot Matrix (First 4 Variables)")
}
# 4. Summary statistics
plot(1, 1, type = "n", xlim = c(0, 10), ylim = c(0, 10),
main = "Matrix Summary", xlab = "", ylab = "", axes = FALSE)
text(5, 9.5, "Correlation Matrix Analysis", cex = 1.2, font = 2)
text(5, 8.7, paste("Variables:", p), cex = 1.1)
text(5, 8.1, paste("Sample size:", nrow(data)), cex = 1.1)
# Count significant correlations
sig_uncorrected <- sum(p_matrix < 0.05 & upper.tri(p_matrix))
total_pairs <- p * (p - 1) / 2
text(5, 7.5, paste("Significant pairs (α=0.05):", sig_uncorrected, "/", total_pairs), cex = 1)
text(5, 6.9, paste("Proportion significant:", round(sig_uncorrected/total_pairs, 3)), cex = 1)
# Strongest correlations
cor_upper <- cor_matrix[upper.tri(cor_matrix)]
max_cor <- max(abs(cor_upper))
text(5, 6.3, paste("Strongest correlation:", round(max_cor, 3)), cex = 1)
# Average absolute correlation
avg_cor <- mean(abs(cor_upper))
text(5, 5.7, paste("Average |correlation|:", round(avg_cor, 3)), cex = 1)
par(mfrow = c(1, 1))
}
# Print methods
print.biomedical_correlation <- function(x, ...) {
cat("\n", x$method, "\n")
cat(rep("=", nchar(x$method) + 2), "\n", sep = "")
cat("Sample size:", x$sample_size, "\n")
if (x$missing_pairs > 0) {
cat("Missing pairs removed:", x$missing_pairs, "\n")
}
cat("Correlation coefficient:", x$correlation, "\n")
if ("t_statistic" %in% names(x)) {
cat("t-statistic:", x$t_statistic, "\n")
cat("Degrees of freedom:", x$degrees_of_freedom, "\n")
} else if ("z_statistic" %in% names(x)) {
cat("z-statistic:", x$z_statistic, "\n")
}
cat("p-value:", x$p_value, "\n")
cat(x$confidence_level * 100, "% Confidence interval: [",
x$confidence_interval[1], ", ", x$confidence_interval[2], "]\n", sep = "")
if ("r_squared" %in% names(x)) {
cat("R-squared:", x$r_squared, "\n")
}
# Interpretation
if (x$p_value < 0.05) {
cat("\nConclusion: Significant correlation detected\n")
} else {
cat("\nConclusion: No significant correlation detected\n")
}
# Effect size interpretation
r_abs <- abs(x$correlation)
magnitude <- if (r_abs < 0.1) "negligible"
else if (r_abs < 0.3) "small"
else if (r_abs < 0.5) "medium"
else if (r_abs < 0.7) "large"
else "very large"
cat("Effect size:", magnitude, "\n")
# Assumptions (if available)
if ("assumptions_check" %in% names(x)) {
cat("\nAssumptions check:\n")
cat("- Normality (X):", x$assumptions_check$normality_x, "\n")
cat("- Normality (Y):", x$assumptions_check$normality_y, "\n")
cat("- Linearity:", x$assumptions_check$linearity, "\n")
cat("- Homoscedasticity:", x$assumptions_check$homoscedasticity, "\n")
cat("- No outliers:", x$assumptions_check$no_outliers, "\n")
cat("- Overall suitable for Pearson:", x$assumptions_check$overall_suitable, "\n")
}
}
print.biomedical_correlation_matrix <- function(x, ...) {
cat("\n", x$method, "\n")
cat(rep("=", nchar(x$method) + 2), "\n", sep = "")
cat("Variables:", x$variables, "\n")
cat("Sample size:", x$sample_size, "\n")
if (x$missing_rows > 0) {
cat("Rows with missing data removed:", x$missing_rows, "\n")
}
total_pairs <- x$variables * (x$variables - 1) / 2
cat("Total variable pairs:", total_pairs, "\n")
cat("\nSignificant correlations (α = 0.05):\n")
cat("- Uncorrected:", x$significant_pairs_uncorrected, "/", total_pairs,
"(", round(x$significant_pairs_uncorrected/total_pairs*100, 1), "%)\n")
cat("- Bonferroni corrected:", x$significant_pairs_bonferroni, "/", total_pairs,
"(", round(x$significant_pairs_bonferroni/total_pairs*100, 1), "%)\n")
cat("- FDR corrected:", x$significant_pairs_fdr, "/", total_pairs,
"(", round(x$significant_pairs_fdr/total_pairs*100, 1), "%)\n")
cat("\nCorrelation matrix:\n")
print(round(x$correlation_matrix, 3))
}
# Demonstration function
demonstrate_correlation_analysis <- function() {
cat("=== Comprehensive Correlation Analysis for Biomedical Data ===\n\n")
set.seed(123)
# Example 1: Pearson correlation (linear relationship)
cat("1. PEARSON CORRELATION: Blood Pressure vs Age\n")
cat("Research Question: Is there a linear relationship between age and systolic BP?\n\n")
age <- runif(50, 25, 75)
systolic_bp <- 90 + 1.2 * age + rnorm(50, 0, 8) # Linear relationship with noise
pearson_result <- correlation_analysis(age, systolic_bp, method = "pearson",
plot_title = "Age vs Systolic BP")
print(pearson_result)
cat("\n", rep("=", 60), "\n\n")
# Example 2: Spearman correlation (monotonic but non-linear)
cat("2. SPEARMAN CORRELATION: Dose vs Response (Non-linear)\n")
cat("Research Question: Is there a monotonic relationship between drug dose and response?\n\n")
dose <- seq(0, 100, length.out = 40)
response <- 10 * log(dose + 1) + rnorm(40, 0, 3) # Log relationship
spearman_result <- correlation_analysis(dose, response, method = "spearman",
plot_title = "Drug Dose vs Response")
print(spearman_result)
cat("\n", rep("=", 60), "\n\n")
# Example 3: Correlation matrix analysis
cat("3. CORRELATION MATRIX: Multiple Biomarkers\n")
cat("Research Question: How are different biomarkers correlated?\n\n")
n <- 100
biomarker_data <- data.frame(
Cholesterol = rnorm(n, 200, 30),
BMI = rnorm(n, 25, 4),
Blood_Pressure = rnorm(n, 120, 15),
Heart_Rate = rnorm(n, 75, 10)
)
# Create some realistic correlations
biomarker_data$Blood_Pressure <- biomarker_data$Blood_Pressure +
0.3 * biomarker_data$BMI + 0.2 * biomarker_data$Cholesterol/10
biomarker_data$Heart_Rate <- biomarker_data$Heart_Rate +
0.4 * biomarker_data$BMI - 0.1 * biomarker_data$Blood_Pressure
cat("Biomarker correlation matrix analysis:\n")
matrix_result <- correlation_analysis(biomarker_data, method = "pearson",
plot_title = "Biomarker Correlations")
print(matrix_result)
cat("\n", rep("=", 60), "\n\n")
# Example 4: Robust correlation with outliers
cat("4. ROBUST CORRELATION: Kendall's Tau with Outliers\n")
cat("Research Question: How does outlier presence affect correlation methods?\n\n")
x_clean <- rnorm(30, 50, 10)
y_clean <- 2 * x_clean + rnorm(30, 0, 5)
# Add outliers
x_outliers <- c(x_clean, c(100, 10))
y_outliers <- c(y_clean, c(20, 150))
cat("Pearson (sensitive to outliers):\n")
pearson_outliers <- correlation_analysis(x_outliers, y_outliers, method = "pearson",
plot = FALSE)
cat("r =", round(pearson_outliers$correlation, 3),
", p =", round(pearson_outliers$p_value, 4), "\n")
cat("\nKendall's tau (robust to outliers):\n")
kendall_outliers <- correlation_analysis(x_outliers, y_outliers, method = "kendall",
plot = FALSE)
cat("τ =", round(kendall_outliers$correlation, 3),
", p =", round(kendall_outliers$p_value, 4), "\n")
cat("\nWithout outliers:\n")
clean_result <- correlation_analysis(x_clean, y_clean, method = "pearson", plot = FALSE)
cat("r =", round(clean_result$correlation, 3),
", p =", round(clean_result$p_value, 4), "\n")
cat("\n", rep("=", 60), "\n\n")
# Example 5: Power analysis for correlations
cat("5. POWER ANALYSIS: Sample Size Requirements\n")
cat("Demonstrating power for detecting different correlation strengths\n\n")
correlation_strengths <- c(0.1, 0.3, 0.5, 0.7)
sample_sizes <- c(20, 50, 100, 200)
power_matrix <- matrix(NA, nrow = length(sample_sizes), ncol = length(correlation_strengths))
rownames(power_matrix) <- paste("n =", sample_sizes)
colnames(power_matrix) <- paste("ρ =", correlation_strengths)
for (i in seq_along(sample_sizes)) {
for (j in seq_along(correlation_strengths)) {
n <- sample_sizes[i]
true_r <- correlation_strengths[j]
# Monte Carlo power simulation
power <- mean(replicate(1000, {
x <- rnorm(n)
y <- true_r * x + sqrt(1 - true_r^2) * rnorm(n)
test_result <- cor.test(x, y)
test_result$p.value < 0.05
}))
power_matrix[i, j] <- power
}
}
cat("Statistical Power Analysis (1000 simulations each):\n")
print(round(power_matrix, 3))
cat("\nGuidelines:\n")
cat("- Small correlations (r = 0.1) require very large samples\n")
cat("- Medium correlations (r = 0.3-0.5) need moderate to large samples\n")
cat("- Large correlations (r ≥ 0.7) detectable with smaller samples\n")
cat("- Aim for power ≥ 0.80 (80%) in study planning\n")
cat("- Consider effect size interpretation alongside statistical significance\n")
}
# Run demonstration if script is executed directly
if (sys.nframe() == 0) {
demonstrate_correlation_analysis()
}