Pearson Correlation (r)
The definitive measure of Linear Association. Pearson's r quantifies the strength and direction of the straight-line relationship between two continuous variables.
What is it?
Pearson Correlation Coefficient (r) measures the strength and direction of the linear relationship between two continuous variables.
When to use it
- Two Variables: Both variables must be continuous (interval or ratio).
- Linearity: The true relationship must be reasonably straight.
- No Extremes: Outliers can severely distort the slope.
Core Idea
It measures how tightly the coordinates cluster around a straight line of best fit, scaled from -1.00 (perfect negative) to +1.00 (perfect positive):
A value of 0 indicates zero linear association. Values close to ±1 mean knowing the score of X allows highly accurate linear predictions of Y.
Hypotheses
How it works
- Compute deviation of each coordinate from its mean (dx, dy).
- Sum the cross-products of deviations (SS_xy).
- Divide by the geometric mean of individual sum of squares.
- Test significance using a t-statistic with df = N - 2.
Assumptions
Important Note
⚠️ Correlation is NOT causation! Two variables can be perfectly correlated due to a third confounding factor (spurious association) or coincidental trends.
Quick Example
| Subject | Study Hours (X) | Test Score (Y) |
|---|---|---|
| S1 | 2.0 | 45 |
| S2 | 8.0 | 85 |
| S3 | 5.0 | 62 |
Pearson Correlation Live Laboratory
Slide the correlation coefficient to see how coordinate scatter shifts and drives the t-statistic.
| Metric | Value |
|---|---|
| Sample Correlation (r) | 0.5000 |
| Degrees of Freedom (df) | 18 |
| t-statistic | 2.449 |
| p-value | 0.0157 |
Hypotheses
Pragmatic null and alternative hypotheses defined in mathematical notation.
H₀: ρ = 0 (no linear correlation between variables)
Hₐ: ρ ≠ 0 (linear correlation exists)
Tests linear association between two continuous variables. Can be one-tailed if direction predicted a priori. Parametric test assuming bivariate normality. ρ (rho) represents population correlation; r is sample estimate.
Assumptions
The core mathematical criteria needed to ensure that statistical testing remains unbiased and valid.
Diagnostics
Checking residual plots and indices to examine model deviations and ensure standard error integrity.
- Scatterplot with regression line to assess linearity
- Q-Q plots for both variables to check normality
- Examine 95% confidence interval for r
- Check for outliers using scatterplot and Cook's distance
- Report r² (coefficient of determination) to quantify variance explained
- Residual plots (residuals vs fitted) to check linearity and homoscedasticity
- Compare with Spearman correlation as sensitivity check
- Bootstrap confidence intervals if normality violated
- Sensitivity analysis: report r with and without outliers
- Power analysis to ensure adequate sample size
- Mahalanobis distance to identify bivariate outliers
- Histograms or density plots for both variables
- Report both r and r² with interpretation
Applied Minds
Review concrete study examples, data layout guidelines, and copy executable syntax scripts.
Height and Weight in Adults (Classic Linear Relationship)
Research question: Is there a linear association between height and weight in adults? Design: Cross-sectional sample of 100 adults (age 25-55, 50% male/female). Measure height (cm) and weight (kg). Hypothesis: Positive linear correlation - taller individuals weigh more on average. Expect moderate-to-strong correlation (r = 0.60-0.75 based on literature).
# Pearson Correlation: Height and Weight
# Classic example of linear association between continuous variables
library(tidyverse)
library(ggplot2)
library(car) # For Q-Q plots and outlier diagnostics
library(psych) # For describe and corr.test
library(DescTools) # For CIs
# Simulate realistic data (or load: data <- read.csv("height_weight.csv"))
set.seed(2025)
n <- 100
# Height: normal distribution, mean=170cm (mix male/female), SD=10cm
height <- rnorm(n, mean=170, sd=10)
# Weight: linearly related to height with noise
# True relationship: weight ≈ -100 + 1.0*height + error
weight <- -100 + 1.0 * height + rnorm(n, mean=0, sd=5)
data <- data.frame(
subject_id = 1:n,
height = height,
weight = weight
)
head(data, 10)
psych::describe(data[, c("height", "weight")])
# === STEP 1: Check Assumptions ===
cat("\n=== Assumption Checks ===\n")
# 1. Linearity: Scatterplot with regression line
ggplot(data, aes(x=height, y=weight)) +
geom_point(alpha=0.6, size=2.5) +
geom_smooth(method="lm", color="blue", se=TRUE, linewidth=1) +
geom_smooth(method="loess", color="red", se=FALSE, linetype="dashed") +
labs(title="Height vs Weight: Linearity Check",
subtitle="Blue=linear fit, Red=loess smooth(should overlap if linear)",
x="Height(cm)",
y="Weight(kg)") +
theme_classic(base_size=12)
cat("Check: Linear(blue) and loess(red) lines should be similar.\n")
# 2. Normality: Q-Q plots
par(mfrow=c(1, 2))
qqPlot(data$height, main="Q-Q Plot: Height", ylab="Height(cm)")
qqPlot(data$weight, main="Q-Q Plot: Weight", ylab="Weight(kg)")
par(mfrow=c(1, 1))
# Shapiro-Wilk test (formal test, but use with caution - sensitive to large n)
shapiro_height <- shapiro.test(data$height)
shapiro_weight <- shapiro.test(data$weight)
cat(sprintf("\nShapiro-Wilk normality tests:\n"))
cat(sprintf(" Height: W=%.3f, p=%.3f %s\n",
shapiro_height$statistic, shapiro_height$p.value,
ifelse(shapiro_height$p.value > 0.05, "(normal)", "(non-normal)")))
cat(sprintf(" Weight: W=%.3f, p=%.3f %s\n",
shapiro_weight$statistic, shapiro_weight$p.value,
ifelse(shapiro_weight$p.value > 0.05, "(normal)", "(non-normal)")))
# 3. Outliers: Cook's distance and influence
model <- lm(weight ~ height, data=data)
cooks_d <- cooks.distance(model)
outlier_threshold <- 4 / n
outliers <- which(cooks_d > outlier_threshold)
cat(sprintf("\nOutliers(Cook's D > %.3f): %d cases\n",
outlier_threshold, length(outliers)))
if (length(outliers) > 0) {
cat("Outlier IDs:", outliers, "\n")
print(data[outliers, ])
}
# Scatterplot with outliers highlighted
data$outlier <- cooks_d > outlier_threshold
ggplot(data, aes(x=height, y=weight, color=outlier)) +
geom_point(size=3, alpha=0.7) +
scale_color_manual(values=c("FALSE"="black", "TRUE"="red")) +
labs(title="Outlier Detection: Cook's Distance",
subtitle=sprintf("%d outliers(red points)", length(outliers))) +
theme_classic()
# 4. Homoscedasticity: Residual plot
data$residuals <- residuals(model)
data$fitted <- fitted(model)
ggplot(data, aes(x=fitted, y=residuals)) +
geom_point(alpha=0.6) +
geom_hline(yintercept=0, color="red", linetype="dashed") +
geom_smooth(se=FALSE, color="blue") +
labs(title="Residuals vs Fitted: Homoscedasticity Check",
subtitle="Should show random scatter around zero",
x="Fitted Values",
y="Residuals") +
theme_classic()
# === STEP 2: Compute Pearson Correlation ===
cat("\n=== Pearson Correlation Results ===\n")
# Method 1: Base R cor.test
result <- cor.test(data$height, data$weight,
method="pearson",
alternative="two.sided")
print(result)
cat(sprintf("\nr = %.3f\n", result$estimate))
cat(sprintf("95%% CI: [%.3f, %.3f]\n", result$conf.int[1], result$conf.int[2]))
cat(sprintf("t(%d) = %.2f, p %s\n",
result$parameter,
result$statistic,
ifelse(result$p.value < 0.001, "< .001",
sprintf("= %.4f", result$p.value))))
# r-squared (proportion of variance explained)
r_squared <- result$estimate^2
cat(sprintf("\nr² = %.3f (%.1f%% of variance in weight explained by height)\n",
r_squared, r_squared * 100))
# === STEP 3: Effect Size Interpretation ===
cat("\n=== Effect Size Guidelines(Cohen, 1988) ===\n")
cat("r = 0.10: small, r = 0.30: medium, r = 0.50: large\n\n")
r_val <- result$estimate
if (abs(r_val) < 0.10) {
strength <- "negligible"
} else if (abs(r_val) < 0.30) {
strength <- "small"
} else if (abs(r_val) < 0.50) {
strength <- "medium"
} else {
strength <- "large"
}
direction <- ifelse(r_val > 0, "positive", "negative")
cat(sprintf("Observed effect: %s(%s association)\n", strength, direction))
# === STEP 4: Bootstrap Confidence Interval (alternative to parametric CI) ===
cat("\n=== Bootstrap 95% CI(n=1000 resamples) ===\n")
set.seed(2025)
boot_r <- replicate(1000, {
indices <- sample(1:n, n, replace=TRUE)
cor(data$height[indices], data$weight[indices])
})
boot_ci <- quantile(boot_r, c(0.025, 0.975))
cat(sprintf("Bootstrap CI: [%.3f, %.3f]\n", boot_ci[1], boot_ci[2]))
cat("Compare with parametric CI - should be similar if normality holds.\n")
# === STEP 5: Compare with Spearman (robustness check) ===
spearman_result <- cor.test(data$height, data$weight, method="spearman")
cat(sprintf("\nSpearman's ρ = %.3f (p %s)\n",
spearman_result$estimate,
ifelse(spearman_result$p.value < 0.001, "< .001",
sprintf("= %.4f", spearman_result$p.value))))
cat("Note: Pearson and Spearman should be similar if linearity holds.\n")
cat(sprintf("Difference: %.3f (large differences suggest non-linearity/outliers)\n",
abs(r_val - spearman_result$estimate)))
# === STEP 6: Sensitivity Analysis - Remove Outliers ===
if (length(outliers) > 0) {
cat("\n=== Sensitivity Analysis: Excluding Outliers ===\n")
data_clean <- data[!data$outlier, ]
r_clean <- cor.test(data_clean$height, data_clean$weight, method="pearson")$estimate
cat(sprintf("r without outliers = %.3f (original r = %.3f)\n", r_clean, r_val))
cat(sprintf("Difference = %.3f (>0.10 suggests outliers influential)\n",
abs(r_clean - r_val)))
} else {
cat("\nNo outliers to remove - sensitivity analysis not needed.\n")
}
# === STEP 7: Visualize Correlation Strength ===
ggplot(data[!data$outlier, ], aes(x=height, y=weight)) +
geom_point(alpha=0.5, size=2) +
geom_smooth(method="lm", color="blue", fill="lightblue") +
labs(title=sprintf("Height-Weight Correlation: r = %.2f", r_val),
subtitle=sprintf("r² = %.2f: %.0f%% variance explained",
r_squared, r_squared*100),
x="Height(cm)",
y="Weight(kg)") +
annotate("text", x=min(data$height)+5, y=max(data$weight)-5,
label=sprintf("r = %.2f***\n95%% CI [%.2f, %.2f]",
r_val, result$conf.int[1], result$conf.int[2]),
hjust=0, size=5) +
theme_classic(base_size=12)
# === APA-Style Reporting ===
cat("\n=== APA-Style Report ===\n")
cat(sprintf(
"A Pearson product-moment correlation was computed to assess the linear
relationship between height and weight in a sample of %d adults. Preliminary
analyses showed the relationship was linear with both variables approximately
normally distributed(Shapiro-Wilk p > .05), and no influential outliers were
detected(Cook's D < %.2f). There was a %s, significant positive correlation
between height and weight, r(%d) = %.2f, 95%% CI [%.2f, %.2f], p < .001.
Height explained %.0f%% of the variance in weight(r² = %.2f). These findings
indicate that taller individuals tend to weigh more, consistent with
anthropometric research. The large effect size suggests height is a strong
predictor of weight in this population.\n",
n, 4/n, strength, result$parameter, r_val,
result$conf.int[1], result$conf.int[2],
r_squared * 100, r_squared
))r = 0.72, p < .001, 95% CI [0.62, 0.80] (large positive correlation). Height explains 52% of variance in weight (r² = 0.52). Strong linear relationship: each 1 SD increase in height (10 cm) associated with 0.72 SD increase in weight (≈5 kg). Assumptions met: linear relationship (loess matches linear fit), bivariate normality (Q-Q plots linear), no outliers (Cook's D < 0.04), homoscedasticity (residuals random). Pearson (r=0.72) and Spearman (ρ=0.71) similar, confirming linearity. Effect size interpretation: r=0.72 is large (Cohen benchmark: 0.50), indicating height is strong predictor of weight. Bootstrap CI [0.61, 0.79] overlaps parametric CI, validating normality assumption.
Alternatives
Structured fallback pathways for choosing alternative tests when normality or slopes requirements fail.
- Spearman Correlation — Captures non-linear but monotonic relationships.
- Polynomial Mapping — Model the 'Curved Truth' using squared terms.
- Bootstrap Confidence Intervals — Generate robust p-values using 1,000 resamples.
- Spearman's Rho — The robust rank-based alternative.
- Winsorization — Cap extreme values at the 5th/95th percentiles.
- Robust Correlation — Use biweight midcorrelation to neutralize noise.
Post-hoc
Group mean comparisons and correction controls (e.g. Tukey HSD, Bonferroni) to protect against Family-Wise Error Rates.
- Compare Pearson r with Spearman rs (robustness to non-normality)
- Bootstrap confidence intervals for r
- Examine influence of outliers (with/without extreme values)
- Compare correlations across subgroups using Fisher's z-transformation
- Test correlation difference from a specific value (not just zero)
Pearson correlation is a bivariate test. Traditional post-hoc tests are not applicable.
Effect Size
Understanding effect sizes (e.g., Cohen's d, Partial Eta-Squared) and clinical impact benchmarks.
Cohen (1988): 0.10=small, 0.30=medium, 0.50=large. Direction: positive (+) or negative (-)
Proportion of variance in Y explained by X. r²=0.25 means 25% variance explained. Always report alongside r
Effect size depends on context. In psychology, r=0.30 often considered meaningful. In physics, r=0.90+ expected. Consider both statistical and practical significance
0.2
0.5
0.8
Sample Size
Guidelines for minimum sample requirements and power analysis parameters.
The 'Stability Threshold': A minimum of 25 participants is required to ensure the 'r' coefficient isn't hijacked by a single bivariate outlier.
| Effect Size | Parameters | Required n |
|---|---|---|
| Small Effect | r = .10 (Small) | n ≈ 782 |
| Medium Effect | r = .30 (Medium) | n ≈ 82 |
| Large Effect | r = .50 (Large) | n ≈ 26 |
The 'Shared Variance' Audit: Remember that r = .30 only explains 9% of the variance (r²). If you need to explain at least 25% of the story, you must seek a large effect (r = .50) or increase your N to capture more subtle signals.
Reporting
How to compile statistical results into publication prose matching APA and journal style guides.
A Pearson product-moment correlation was conducted to assess the linear relationship between Variable X and Variable Y in sample description. Preliminary analyses showed the relationship was linear (scatterplot inspection) with both variables approximately normally distributed (mention Q-Q plots or Shapiro-Wilk results), and no/X influential outliers detected (Cook's D < threshold or removed). There was a significant/non-significant direction: positive/negative correlation between X and Y, r(df) = value, 95% CI [lower, upper], p = or < p-value. Variable X explained r²×100% of the variance in Variable Y. Interpretation in context with effect size label: small/medium/large per Cohen, 1988.
- Pearson r value
- 95% confidence interval
- t-statistic and degrees of freedom (df = n-2)
- p-value
- r² (coefficient of determination)
- Sample size
- Statement about assumption checks (linearity, normality, outliers)
Manuscript Lab
Copy standard summary tables and forensic reporting grids to outline analysis details.
| Variable | 1. BMI | 2. Systolic BP | 3. Cholesterol | M (SD) |
|---|---|---|---|---|
| 1. BMI | — | — | — | 28.4 (5.2) |
| 2. Systolic BP | .45** [.33, .56] | — | — | 134.2 (15.1) |
| 3. Cholesterol | .28** [.14, .41] | .38** [.25, .50] | — | 195.8 (35.4) |
The Connection Strength. Ranges from -1 to +1. 0 indicates no linear relationship.
The Precision Window. The range of plausible values for the true population correlation.
Significance Flag. Indicates the probability of observing this correlation by chance is less than 1%.
Command Center
Syntax libraries and function parameters for executing calculations in stats packages.
# 1. Execute Correlation Matrix with CIs
correlation::correlation(df, p_adjust = 'bonferroni')
# 2. Visualize Linear Trends
ggplot(df, aes(x=bmi, y=sys_bp)) +
geom_point() +
geom_smooth(method='lm')Don't just report r. Report r² to reveal the 'Variance Explained'—the true measure of predictive power.
# Linearity and Outlier Audit
performance::check_model(lm(sys_bp ~ bmi, data=df))
# Bayesian Correlation Strength
bayestestR::correlationBF(df$bmi, df$sys_bp)Common Mistakes
Analytical caveats and corrections to maintain modeling integrity.
References
Scholarly lineage and citation keys grounding the statistical framework.