Correlation Analysis
Overview
Correlation analysis measures the strength and direction of relationships between variables, helping identify which features are related and detect multicollinearity.
When to Use
- Identifying relationships between numerical variables
- Detecting multicollinearity before regression modeling
- Exploratory data analysis to understand feature dependencies
- Feature selection and dimensionality reduction
- Validating assumptions about variable relationships
- Comparing linear and non-linear associations
Correlation Types
- Pearson: Linear correlation (continuous variables)
- Spearman: Rank-based correlation (ordinal/non-linear)
- Kendall: Rank correlation (robust alternative)
- Cramér's V: Association for categorical variables
- Mutual Information: Non-linear dependencies
Key Concepts
- Correlation Coefficient: Ranges from -1 to +1
- Positive Correlation: Variables move together
- Negative Correlation: Variables move oppositely
- Multicollinearity: High correlations between predictors
Implementation with Python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import pearsonr, spearmanr, kendalltau
# Sample data
np.random.seed(42)
n = 200
age = np.random.uniform(20, 70, n)
income = age * 2000 + np.random.normal(0, 10000, n)
education_years = age / 2 + np.random.normal(0, 3, n)
satisfaction = income / 50000 + np.random.normal(0, 0.5, n)
df = pd.DataFrame({
'age': age,
'income': income,
'education_years': education_years,
'satisfaction': satisfaction,
'years_employed': age - education_years - 6
})
# Pearson correlation (linear)
corr_matrix = df.corr(method='pearson')
print("Pearson Correlation Matrix:")
print(corr_matrix)
# Individual correlation with p-value
corr_coef, p_value = pearsonr(df['age'], df['income'])
print(f"\nPearson correlation (age vs income): r={corr_coef:.4f}, p-value={p_value:.4f}")
# Spearman correlation (rank-based)
spearman_matrix = df.corr(method='spearman')
print("\nSpearman Correlation Matrix:")
print(spearman_matrix)
spearman_coef, p_value = spearmanr(df['age'], df['income'])
print(f"Spearman correlation (age vs income): rho={spearman_coef:.4f}, p-value={p_value:.4f}")
# Kendall tau correlation
kendall_coef, p_value = kendalltau(df['age'], df['income'])
print(f"Kendall correlation (age vs income): tau={kendall_coef:.4f}, p-value={p_value:.4f}")
# Correlation heatmap
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Pearson heatmap
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0,
square=True, ax=axes[0], vmin=-1, vmax=1)
axes[0].set_title('Pearson Correlation Heatmap')
# Spearman heatmap
sns.heatmap(spearman_matrix, annot=True, cmap='coolwarm', center=0,
square=True, ax=axes[1], vmin=-1, vmax=1)
axes[1].set_title('Spearman Correlation Heatmap')
plt.tight_layout()
plt.show()
# Correlation with significance testing
def correlation_with_pvalue(df):
rows, cols = [], []
for col1 in df.columns:
for col2 in df.columns:
if col1 < col2: # Avoid duplicates
r, p = pearsonr(df[col1], df[col2])
rows.append({
'Variable 1': col1,
'Variable 2': col2,
'Correlation': r,
'P-value': p,
'Significant': 'Yes' if p < 0.05 else 'No'
})
return pd.DataFrame(rows)
corr_table = correlation_with_pvalue(df)
print("\nCorrelation with P-values:")
print(corr_table)
# Scatter plots with regression lines
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
pairs = [('age', 'income'), ('age', 'education_years'),
('income', 'satisfaction'), ('education_years', 'years_employed')]
for idx, (var1, var2) in enumerate(pairs):
ax = axes[idx // 2, idx % 2]
ax.scatter(df[var1], df[var2], alpha=0.5)
# Add regression line
z = np.polyfit(df[var1], df[var2], 1)
p = np.poly1d(z)
x_line = np.linspace(df[var1].min(), df[var1].max(), 100)
ax.plot(x_line, p(x_line), "r--", linewidth=2)
r, p_val = pearsonr(df[var1], df[var2])
ax.set_title(f'{var1} vs {var2}\nr={r:.4f}, p={p_val:.4f}')
ax.set_xlabel(var1)
ax.set_ylabel(var2)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# Multicollinearity detection (VIF)
from statsmodels.stats.outliers_influence import variance_inflation_factor
X = df[['age', 'education_years', 'years_employed']]
vif_data = pd.DataFrame()
vif_data['Variable'] = X.columns
vif_data['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
print("\nVariance Inflation Factor (VIF):")
print(vif_data)
print("\nVIF > 10: High multicollinearity")
print("VIF > 5: Moderate multicollinearity")
# Partial correlation (controlling for confounding)
def partial_correlation(df, x, y, control_vars):
from scipy.stats import linregress
# Residuals of x after removing control variables
x_residuals = df[x] - np.poly1d(
np.polyfit(df[control_vars].values, df[x], deg=1)
)(df[control_vars].values)
# Residuals of y after removing control variables
y_residuals = df[y] - np.poly1d(
np.polyfit(df[control_vars].values, df[y], deg=1)
)(df[control_vars].values)
return pearsonr(x_residuals, y_residuals)[0]
partial_corr = partial_correlation(df, 'income', 'satisfaction', ['age'])
print(f"\nPartial correlation (income vs satisfaction, controlling for age): {partial_corr:.4f}")
# Distance correlation (non-linear relationships)
try:
from dcor import distance_correlation
dist_corr = distance_correlation(df['age'], df['income'])
print(f"Distance correlation (age vs income): {dist_corr:.4f}")
except ImportError:
print("dcor library not installed for distance correlation")
# Correlation stability over time
fig, ax = plt.subplots(figsize=(12, 5))
rolling_corr = df['age'].rolling(window=50).corr(df['income'])
ax.plot(rolling_corr.index, rolling_corr.values)
ax.set_title('Rolling Correlation (age vs income, window=50)')
ax.set_ylabel('Correlation Coefficient')
ax.grid(True, alpha=0.3)
plt.show()
Interpretation Guidelines
- |r| = 0.0-0.3: Weak correlation
- |r| = 0.3-0.7: Moderate correlation
- |r| = 0.7-1.0: Strong correlation
- p < 0.05: Statistically significant
- High VIF (>10): Multicollinearity problem
Important Notes
- Correlation ≠ Causation
- Non-linear relationships missed by Pearson
- Outliers can distort correlations
- Sample size affects significance
- Temporal trends can create spurious correlations
Visualization Strategies
- Heatmaps for overview
- Scatter plots for relationships
- Pair plots for multivariate analysis
- Rolling correlations for time-varying relationships
Deliverables
- Correlation matrices (Pearson, Spearman)
- Correlation heatmaps with annotations
- Statistical significance table
- Scatter plots with regression lines
- Multicollinearity assessment (VIF)
- Partial correlation analysis
- Relationship interpretation report
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: correlation-analysis3description: Measure relationships between variables using correlation coefficients, correlation matrices, and association tests for correlation measurement, relationship analysis, and multicollinearity detection Use when this capability is needed.4---56# Correlation Analysis78## Overview910Correlation analysis measures the strength and direction of relationships between variables, helping identify which features are related and detect multicollinearity.1112## When to Use1314- Identifying relationships between numerical variables15- Detecting multicollinearity before regression modeling16- Exploratory data analysis to understand feature dependencies17- Feature selection and dimensionality reduction18- Validating assumptions about variable relationships19- Comparing linear and non-linear associations2021## Correlation Types2223- **Pearson**: Linear correlation (continuous variables)24- **Spearman**: Rank-based correlation (ordinal/non-linear)25- **Kendall**: Rank correlation (robust alternative)26- **Cramér's V**: Association for categorical variables27- **Mutual Information**: Non-linear dependencies2829## Key Concepts3031- **Correlation Coefficient**: Ranges from -1 to +132- **Positive Correlation**: Variables move together33- **Negative Correlation**: Variables move oppositely34- **Multicollinearity**: High correlations between predictors3536## Implementation with Python3738```python39import pandas as pd40import numpy as np41import matplotlib.pyplot as plt42import seaborn as sns43from scipy.stats import pearsonr, spearmanr, kendalltau4445# Sample data46np.random.seed(42)47n = 20048age = np.random.uniform(20, 70, n)49income = age * 2000 + np.random.normal(0, 10000, n)50education_years = age / 2 + np.random.normal(0, 3, n)51satisfaction = income / 50000 + np.random.normal(0, 0.5, n)5253df = pd.DataFrame({54 'age': age,55 'income': income,56 'education_years': education_years,57 'satisfaction': satisfaction,58 'years_employed': age - education_years - 659})6061# Pearson correlation (linear)62corr_matrix = df.corr(method='pearson')63print("Pearson Correlation Matrix:")64print(corr_matrix)6566# Individual correlation with p-value67corr_coef, p_value = pearsonr(df['age'], df['income'])68print(f"\nPearson correlation (age vs income): r={corr_coef:.4f}, p-value={p_value:.4f}")6970# Spearman correlation (rank-based)71spearman_matrix = df.corr(method='spearman')72print("\nSpearman Correlation Matrix:")73print(spearman_matrix)7475spearman_coef, p_value = spearmanr(df['age'], df['income'])76print(f"Spearman correlation (age vs income): rho={spearman_coef:.4f}, p-value={p_value:.4f}")7778# Kendall tau correlation79kendall_coef, p_value = kendalltau(df['age'], df['income'])80print(f"Kendall correlation (age vs income): tau={kendall_coef:.4f}, p-value={p_value:.4f}")8182# Correlation heatmap83fig, axes = plt.subplots(1, 2, figsize=(14, 5))8485# Pearson heatmap86sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0,87 square=True, ax=axes[0], vmin=-1, vmax=1)88axes[0].set_title('Pearson Correlation Heatmap')8990# Spearman heatmap91sns.heatmap(spearman_matrix, annot=True, cmap='coolwarm', center=0,92 square=True, ax=axes[1], vmin=-1, vmax=1)93axes[1].set_title('Spearman Correlation Heatmap')9495plt.tight_layout()96plt.show()9798# Correlation with significance testing99def correlation_with_pvalue(df):100 rows, cols = [], []101 for col1 in df.columns:102 for col2 in df.columns:103 if col1 < col2: # Avoid duplicates104 r, p = pearsonr(df[col1], df[col2])105 rows.append({106 'Variable 1': col1,107 'Variable 2': col2,108 'Correlation': r,109 'P-value': p,110 'Significant': 'Yes' if p < 0.05 else 'No'111 })112 return pd.DataFrame(rows)113114corr_table = correlation_with_pvalue(df)115print("\nCorrelation with P-values:")116print(corr_table)117118# Scatter plots with regression lines119fig, axes = plt.subplots(2, 2, figsize=(12, 10))120121pairs = [('age', 'income'), ('age', 'education_years'),122 ('income', 'satisfaction'), ('education_years', 'years_employed')]123124for idx, (var1, var2) in enumerate(pairs):125 ax = axes[idx // 2, idx % 2]126 ax.scatter(df[var1], df[var2], alpha=0.5)127128 # Add regression line129 z = np.polyfit(df[var1], df[var2], 1)130 p = np.poly1d(z)131 x_line = np.linspace(df[var1].min(), df[var1].max(), 100)132 ax.plot(x_line, p(x_line), "r--", linewidth=2)133134 r, p_val = pearsonr(df[var1], df[var2])135 ax.set_title(f'{var1} vs {var2}\nr={r:.4f}, p={p_val:.4f}')136 ax.set_xlabel(var1)137 ax.set_ylabel(var2)138 ax.grid(True, alpha=0.3)139140plt.tight_layout()141plt.show()142143# Multicollinearity detection (VIF)144from statsmodels.stats.outliers_influence import variance_inflation_factor145146X = df[['age', 'education_years', 'years_employed']]147vif_data = pd.DataFrame()148vif_data['Variable'] = X.columns149vif_data['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]150151print("\nVariance Inflation Factor (VIF):")152print(vif_data)153print("\nVIF > 10: High multicollinearity")154print("VIF > 5: Moderate multicollinearity")155156# Partial correlation (controlling for confounding)157def partial_correlation(df, x, y, control_vars):158 from scipy.stats import linregress159160 # Residuals of x after removing control variables161 x_residuals = df[x] - np.poly1d(162 np.polyfit(df[control_vars].values, df[x], deg=1)163 )(df[control_vars].values)164165 # Residuals of y after removing control variables166 y_residuals = df[y] - np.poly1d(167 np.polyfit(df[control_vars].values, df[y], deg=1)168 )(df[control_vars].values)169170 return pearsonr(x_residuals, y_residuals)[0]171172partial_corr = partial_correlation(df, 'income', 'satisfaction', ['age'])173print(f"\nPartial correlation (income vs satisfaction, controlling for age): {partial_corr:.4f}")174175# Distance correlation (non-linear relationships)176try:177 from dcor import distance_correlation178 dist_corr = distance_correlation(df['age'], df['income'])179 print(f"Distance correlation (age vs income): {dist_corr:.4f}")180except ImportError:181 print("dcor library not installed for distance correlation")182183# Correlation stability over time184fig, ax = plt.subplots(figsize=(12, 5))185186rolling_corr = df['age'].rolling(window=50).corr(df['income'])187ax.plot(rolling_corr.index, rolling_corr.values)188ax.set_title('Rolling Correlation (age vs income, window=50)')189ax.set_ylabel('Correlation Coefficient')190ax.grid(True, alpha=0.3)191plt.show()192```193194## Interpretation Guidelines195196- **|r| = 0.0-0.3**: Weak correlation197- **|r| = 0.3-0.7**: Moderate correlation198- **|r| = 0.7-1.0**: Strong correlation199- **p < 0.05**: Statistically significant200- **High VIF (>10)**: Multicollinearity problem201202## Important Notes203204- Correlation ≠ Causation205- Non-linear relationships missed by Pearson206- Outliers can distort correlations207- Sample size affects significance208- Temporal trends can create spurious correlations209210## Visualization Strategies211212- Heatmaps for overview213- Scatter plots for relationships214- Pair plots for multivariate analysis215- Rolling correlations for time-varying relationships216217## Deliverables218219- Correlation matrices (Pearson, Spearman)220- Correlation heatmaps with annotations221- Statistical significance table222- Scatter plots with regression lines223- Multicollinearity assessment (VIF)224- Partial correlation analysis225- Relationship interpretation report226227---228> Converted and distributed by [TomeVault](https://tomevault.io/claim/aj-geddes) — claim your Tome and manage your conversions.229<!-- tomevault:4.0:skill_md:2026-04-11 -->