Skewness and Kurtosis Analysis
- Skewness measures the asymmetry of the distribution
- Kurtosis measures the "tailedness" of the distribution
- For a perfect normal distribution: skewness = 0, kurtosis = 3 (excess kurtosis = 0)
Interpretation Guidelines
Skewness
- -0.5 to +0.5: Fairly symmetrical (approximately normal) ✓
- -1 to -0.5 or +0.5 to +1: Moderately skewed
- < -1 or > +1: Highly skewed ✗
- Positive skew: Right tail is longer (mean > median)
- Negative skew: Left tail is longer (mean < median)
Excess Kurtosis (Fisher=True, normal = 0)
- -0.5 to +0.5: Approximately normal ✓
- > +0.5: Heavy tails, more outliers than normal (leptokurtic)
- < -0.5: Light tails, fewer outliers than normal (platykurtic)
Pearson's Kurtosis (Fisher=False, normal = 3)
- 2.5 to 3.5: Approximately normal ✓
- > 3.5: Heavy tails (leptokurtic)
- < 2.5: Light tails (platykurtic)
Python Example
# Example: Skewness and Kurtosis Analysis for Normality (scipy.stats.skew, kurtosis)
from scipy.stats import skew, kurtosis
import numpy as np
import matplotlib.pyplot as plt
def interpret_skew_kurt(skewness, kurtosis_value, excess_kurtosis):
print(f"Skewness: {skewness:.4f}")
print(f"Kurtosis (Pearson): {kurtosis_value:.4f}")
print(f"Excess Kurtosis: {excess_kurtosis:.4f}")
if abs(skewness) < 0.5:
print(' - Skewness: Fairly symmetrical ✓')
elif abs(skewness) < 1:
print(' - Skewness: Moderately skewed')
else:
print(' - Skewness: Highly skewed ✗')
if abs(kurtosis_value) < 0.5:
print(' - Kurtosis: Normal tailedness ✓')
elif kurtosis_value > 0.5:
print(' - Kurtosis: Heavy tails (leptokurtic)')
else:
print(' - Kurtosis: Light tails (platykurtic)')
if abs(excess_kurtosis) < 0.5:
print(f" - Excess Kurtosis ({excess_kurtosis:.2f}): Normal tailedness ✓")
elif excess_kurtosis > 0.5:
print(f" - Excess Kurtosis ({excess_kurtosis:.2f}): Heavy tails (leptokurtic)")
else:
print(f" - Excess Kurtosis ({excess_kurtosis:.2f}): Light tails (platykurtic)")
# Generate sample data: normal and non-normal
data_normal = np.random.normal(loc=0, scale=1, size=1000)
data_non_normal = np.random.exponential(scale=2, size=1000)
# Plot histograms for visual inspection
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].hist(data_normal, bins=30, color='skyblue', edgecolor='black')
axes[0].set_title('Normal Data Histogram')
axes[1].hist(data_non_normal, bins=30, color='salmon', edgecolor='black')
axes[1].set_title('Non-Normal Data Histogram')
plt.tight_layout()
plt.show()
# Calculate skewness and kurtosis for normal data
skewness_norm = skew(data_normal)
kurt_norm = kurtosis(data_normal, fisher=False) # Pearson's kurtosis (normal = 3)
excess_kurt_norm = kurtosis(data_normal, fisher=True) # Excess kurtosis (normal = 0)
print('Normal Data:')
print(f' Skewness: {skewness_norm:.4f}')
print(f' Kurtosis (Pearson): {kurt_norm:.4f}')
print(f' Excess Kurtosis: {excess_kurt_norm:.4f}')
interpret_skew_kurt(skewness_norm, kurt_norm, excess_kurt_norm)
# Calculate skewness and kurtosis for non-normal data
skewness_non_norm = skew(data_non_normal)
kurt_non_norm = kurtosis(data_non_normal, fisher=False)
excess_kurt_non_norm = kurtosis(data_non_normal, fisher=True)
print('\nNon-Normal Data:')
print(f' Skewness: {skewness_non_norm:.4f}')
print(f' Kurtosis (Pearson): {kurt_non_norm:.4f}')
print(f' Excess Kurtosis: {excess_kurt_non_norm:.4f}')
interpret_skew_kurt(skewness_non_norm, kurt_non_norm, excess_kurt_non_norm)
Output
Normal Data:
Skewness: 0.1169
Kurtosis (Pearson): 3.4115
Excess Kurtosis: 0.4115
Skewness: 0.1169
Kurtosis (Pearson): 3.4115
Excess Kurtosis: 0.4115
- Skewness: Fairly symmetrical ✓
- Kurtosis: Heavy tails (leptokurtic)
- Excess Kurtosis (0.41): Normal tailedness ✓
Non-Normal Data:
Skewness: 1.8222
Kurtosis (Pearson): 7.3808
Excess Kurtosis: 4.3808
Skewness: 1.8222
Kurtosis (Pearson): 7.3808
Excess Kurtosis: 4.3808
- Skewness: Highly skewed ✗
- Kurtosis: Heavy tails (leptokurtic)
- Excess Kurtosis (4.38): Heavy tails (leptokurtic)
