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
1---2name: correlation-analysis3description: Measure relationships between variables using correlation coefficients, correlation matrices, and association tests for correlation measurement, relationship analysis, and multicollinearity detection4---5
6# Correlation Analysis
7
8## Overview
9
10Correlation analysis measures the strength and direction of relationships between variables, helping identify which features are related and detect multicollinearity.
11
12## When to Use
13
14- Identifying relationships between numerical variables
15- Detecting multicollinearity before regression modeling
16- Exploratory data analysis to understand feature dependencies
17- Feature selection and dimensionality reduction
18- Validating assumptions about variable relationships
19- Comparing linear and non-linear associations
20
21## Correlation Types
22
23- **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 variables
27- **Mutual Information**: Non-linear dependencies
28
29## Key Concepts
30
31- **Correlation Coefficient**: Ranges from -1 to +1
32- **Positive Correlation**: Variables move together
33- **Negative Correlation**: Variables move oppositely
34- **Multicollinearity**: High correlations between predictors
35
36## Implementation with Python
37
38```python
39import pandas as pd
40import numpy as np
41import matplotlib.pyplot as plt
42import seaborn as sns
43from scipy.stats import pearsonr, spearmanr, kendalltau
44
45# Sample data
46np.random.seed(42)
47n = 200
48age = 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)
52
53df = pd.DataFrame({
54 'age': age,
55 'income': income,
56 'education_years': education_years,
57 'satisfaction': satisfaction,
58 'years_employed': age - education_years - 6
59})
60
61# Pearson correlation (linear)
62corr_matrix = df.corr(method='pearson')
63print("Pearson Correlation Matrix:")
64print(corr_matrix)
65
66# Individual correlation with p-value
67corr_coef, p_value = pearsonr(df['age'], df['income'])
68print(f"\nPearson correlation (age vs income): r={corr_coef:.4f}, p-value={p_value:.4f}")
69
70# Spearman correlation (rank-based)
71spearman_matrix = df.corr(method='spearman')
72print("\nSpearman Correlation Matrix:")
73print(spearman_matrix)
74
75spearman_coef, p_value = spearmanr(df['age'], df['income'])
76print(f"Spearman correlation (age vs income): rho={spearman_coef:.4f}, p-value={p_value:.4f}")
77
78# Kendall tau correlation
79kendall_coef, p_value = kendalltau(df['age'], df['income'])
80print(f"Kendall correlation (age vs income): tau={kendall_coef:.4f}, p-value={p_value:.4f}")
81
82# Correlation heatmap
83fig, axes = plt.subplots(1, 2, figsize=(14, 5))
84
85# Pearson heatmap
86sns.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')
89
90# Spearman heatmap
91sns.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')
94
95plt.tight_layout()
96plt.show()
97
98# Correlation with significance testing
99def correlation_with_pvalue(df):
100 rows, cols = [], []
101 for col1 in df.columns:
102 for col2 in df.columns:
103 if col1 < col2: # Avoid duplicates
104 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)
113
114corr_table = correlation_with_pvalue(df)
115print("\nCorrelation with P-values:")
116print(corr_table)
117
118# Scatter plots with regression lines
119fig, axes = plt.subplots(2, 2, figsize=(12, 10))
120
121pairs = [('age', 'income'), ('age', 'education_years'),
122 ('income', 'satisfaction'), ('education_years', 'years_employed')]
123
124for idx, (var1, var2) in enumerate(pairs):
125 ax = axes[idx // 2, idx % 2]
126 ax.scatter(df[var1], df[var2], alpha=0.5)
127
128 # Add regression line
129 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)
133
134 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)
139
140plt.tight_layout()
141plt.show()
142
143# Multicollinearity detection (VIF)
144from statsmodels.stats.outliers_influence import variance_inflation_factor
145
146X = df[['age', 'education_years', 'years_employed']]
147vif_data = pd.DataFrame()
148vif_data['Variable'] = X.columns
149vif_data['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
150
151print("\nVariance Inflation Factor (VIF):")
152print(vif_data)
153print("\nVIF > 10: High multicollinearity")
154print("VIF > 5: Moderate multicollinearity")
155
156# Partial correlation (controlling for confounding)
157def partial_correlation(df, x, y, control_vars):
158 from scipy.stats import linregress
159
160 # Residuals of x after removing control variables
161 x_residuals = df[x] - np.poly1d(
162 np.polyfit(df[control_vars].values, df[x], deg=1)
163 )(df[control_vars].values)
164
165 # Residuals of y after removing control variables
166 y_residuals = df[y] - np.poly1d(
167 np.polyfit(df[control_vars].values, df[y], deg=1)
168 )(df[control_vars].values)
169
170 return pearsonr(x_residuals, y_residuals)[0]
171
172partial_corr = partial_correlation(df, 'income', 'satisfaction', ['age'])
173print(f"\nPartial correlation (income vs satisfaction, controlling for age): {partial_corr:.4f}")
174
175# Distance correlation (non-linear relationships)
176try:
177 from dcor import distance_correlation
178 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")
182
183# Correlation stability over time
184fig, ax = plt.subplots(figsize=(12, 5))
185
186rolling_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```
193
194## Interpretation Guidelines
195
196- **|r| = 0.0-0.3**: Weak correlation
197- **|r| = 0.3-0.7**: Moderate correlation
198- **|r| = 0.7-1.0**: Strong correlation
199- **p < 0.05**: Statistically significant
200- **High VIF (>10)**: Multicollinearity problem
201
202## Important Notes
203
204- Correlation ≠ Causation
205- Non-linear relationships missed by Pearson
206- Outliers can distort correlations
207- Sample size affects significance
208- Temporal trends can create spurious correlations
209
210## Visualization Strategies
211
212- Heatmaps for overview
213- Scatter plots for relationships
214- Pair plots for multivariate analysis
215- Rolling correlations for time-varying relationships
216
217## Deliverables
218
219- Correlation matrices (Pearson, Spearman)
220- Correlation heatmaps with annotations
221- Statistical significance table
222- Scatter plots with regression lines
223- Multicollinearity assessment (VIF)
224- Partial correlation analysis
225- Relationship interpretation report