如何使用Python的Matplotlib绘制正态分布图
参考:How to plot a normal distribution with Matplotlib in Python
正态分布,也称为高斯分布,是统计学和概率论中最重要的概率分布之一。在数据分析和可视化中,能够准确地绘制正态分布图是一项非常有用的技能。本文将详细介绍如何使用Python的Matplotlib库来绘制正态分布图,包括基本概念、不同类型的正态分布图以及如何自定义图表样式。
1. 正态分布的基本概念
正态分布是一种连续概率分布,其概率密度函数呈钟形曲线。它由两个参数决定:均值(μ)和标准差(σ)。均值决定了分布的中心位置,而标准差则决定了分布的宽度或分散程度。
在开始绘图之前,我们需要导入必要的库:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
# 设置图表样式
plt.style.use('seaborn')
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['font.size'] = 14
print("Welcome to how2matplotlib.com!")
这段代码导入了NumPy用于数值计算,Matplotlib.pyplot用于绘图,以及SciPy的stats模块用于生成正态分布数据。我们还设置了一些基本的图表样式。
2. 绘制标准正态分布
标准正态分布是均值为0,标准差为1的特殊正态分布。让我们从绘制一个标准正态分布开始:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-4, 4, 100)
y = stats.norm.pdf(x, 0, 1)
plt.plot(x, y, 'b-', label='Standard Normal Distribution')
plt.title('Standard Normal Distribution - how2matplotlib.com')
plt.xlabel('X')
plt.ylabel('Probability Density')
plt.legend()
plt.grid(True)
plt.show()
Output:
在这个例子中,我们使用np.linspace()
创建了一个从-4到4的等间距数组,然后使用stats.norm.pdf()
计算了这些x值对应的概率密度。plt.plot()
函数用于绘制曲线,我们还添加了标题、坐标轴标签和图例。
3. 绘制不同参数的正态分布
现在,让我们比较不同均值和标准差的正态分布:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-10, 10, 100)
y1 = stats.norm.pdf(x, 0, 1)
y2 = stats.norm.pdf(x, 0, 2)
y3 = stats.norm.pdf(x, -2, 1.5)
plt.plot(x, y1, 'b-', label='μ=0, σ=1')
plt.plot(x, y2, 'r--', label='μ=0, σ=2')
plt.plot(x, y3, 'g:', label='μ=-2, σ=1.5')
plt.title('Different Normal Distributions - how2matplotlib.com')
plt.xlabel('X')
plt.ylabel('Probability Density')
plt.legend()
plt.grid(True)
plt.show()
Output:
这个例子展示了三种不同参数的正态分布。我们可以清楚地看到,改变均值会移动曲线的位置,而改变标准差会影响曲线的宽度。
4. 使用填充区域突出显示特定范围
在许多应用中,我们可能需要突出显示正态分布的特定区域,例如标准差范围:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-4, 4, 100)
y = stats.norm.pdf(x, 0, 1)
plt.plot(x, y, 'b-', label='Normal Distribution')
plt.fill_between(x, y, where=(x >= -1) & (x <= 1), color='red', alpha=0.3)
plt.fill_between(x, y, where=(x >= -2) & (x <= 2), color='yellow', alpha=0.2)
plt.title('Normal Distribution with Highlighted Ranges - how2matplotlib.com')
plt.xlabel('X')
plt.ylabel('Probability Density')
plt.legend()
plt.text(0, 0.2, '68% within 1σ', ha='center')
plt.text(0, 0.1, '95% within 2σ', ha='center')
plt.grid(True)
plt.show()
Output:
这个例子使用plt.fill_between()
函数来填充特定区域。我们突出显示了一个标准差(68%)和两个标准差(95%)的范围。
5. 绘制累积分布函数(CDF)
除了概率密度函数(PDF),累积分布函数(CDF)也是描述正态分布的重要方式:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-4, 4, 100)
y_pdf = stats.norm.pdf(x, 0, 1)
y_cdf = stats.norm.cdf(x, 0, 1)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 12))
ax1.plot(x, y_pdf, 'b-', label='PDF')
ax1.set_title('Probability Density Function - how2matplotlib.com')
ax1.set_ylabel('Probability Density')
ax1.legend()
ax2.plot(x, y_cdf, 'r-', label='CDF')
ax2.set_title('Cumulative Distribution Function - how2matplotlib.com')
ax2.set_xlabel('X')
ax2.set_ylabel('Cumulative Probability')
ax2.legend()
plt.tight_layout()
plt.show()
Output:
这个例子创建了两个子图,分别显示PDF和CDF。CDF表示随机变量小于或等于某个值的概率。
6. 绘制3D正态分布
我们还可以创建二维正态分布的3D图:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from mpl_toolkits.mplot3d import Axes3D
x = np.linspace(-3, 3, 50)
y = np.linspace(-3, 3, 50)
X, Y = np.meshgrid(x, y)
pos = np.dstack((X, Y))
rv = stats.multivariate_normal([0, 0], [[1, 0], [0, 1]])
Z = rv.pdf(pos)
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap='viridis')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Probability Density')
ax.set_title('3D Normal Distribution - how2matplotlib.com')
plt.colorbar(surf)
plt.show()
Output:
这个例子创建了一个二维正态分布的3D表面图。我们使用np.meshgrid()
创建了x和y坐标网格,然后使用stats.multivariate_normal()
生成二维正态分布数据。
7. 绘制多个正态分布的混合
在某些情况下,我们可能需要绘制多个正态分布的混合:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-10, 10, 200)
y1 = stats.norm.pdf(x, -2, 1.5)
y2 = stats.norm.pdf(x, 2, 2)
y_mix = 0.6 * y1 + 0.4 * y2
plt.plot(x, y1, 'b--', label='Distribution 1')
plt.plot(x, y2, 'r--', label='Distribution 2')
plt.plot(x, y_mix, 'g-', label='Mixture')
plt.fill_between(x, y_mix, alpha=0.3)
plt.title('Mixture of Normal Distributions - how2matplotlib.com')
plt.xlabel('X')
plt.ylabel('Probability Density')
plt.legend()
plt.grid(True)
plt.show()
Output:
这个例子展示了两个不同的正态分布及其混合。混合分布是通过对两个分布的加权和来创建的。
8. 使用直方图和核密度估计
在实际应用中,我们通常会处理样本数据而不是理论分布。让我们看看如何使用直方图和核密度估计来可视化这些数据:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
np.random.seed(42)
data = np.random.normal(0, 1, 1000)
plt.hist(data, bins=30, density=True, alpha=0.7, color='skyblue')
x = np.linspace(-4, 4, 100)
plt.plot(x, stats.norm.pdf(x, 0, 1), 'r-', lw=2, label='Theoretical PDF')
plt.plot(x, stats.gaussian_kde(data)(x), 'g--', lw=2, label='KDE')
plt.title('Histogram, PDF, and KDE - how2matplotlib.com')
plt.xlabel('X')
plt.ylabel('Density')
plt.legend()
plt.grid(True)
plt.show()
Output:
这个例子生成了1000个来自标准正态分布的随机样本。我们使用直方图来显示数据分布,同时绘制了理论PDF和基于数据的核密度估计(KDE)曲线进行比较。
9. 绘制Q-Q图
Q-Q图(Quantile-Quantile plot)是用来比较两个概率分布的图形方法。它可以帮助我们判断数据是否符合正态分布:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
np.random.seed(42)
data = np.random.normal(0, 1, 1000)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 直方图
ax1.hist(data, bins=30, density=True, alpha=0.7, color='skyblue')
x = np.linspace(-4, 4, 100)
ax1.plot(x, stats.norm.pdf(x, 0, 1), 'r-', lw=2)
ax1.set_title('Histogram vs Normal PDF - how2matplotlib.com')
ax1.set_xlabel('X')
ax1.set_ylabel('Density')
# Q-Q图
stats.probplot(data, dist="norm", plot=ax2)
ax2.set_title('Q-Q Plot - how2matplotlib.com')
plt.tight_layout()
plt.show()
Output:
这个例子创建了两个子图:一个是数据的直方图与理论正态分布的对比,另一个是Q-Q图。在Q-Q图中,如果数据点大致落在对角线上,则表明数据符合正态分布。
10. 绘制带有置信区间的正态分布
在某些应用中,我们可能需要显示正态分布的置信区间:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-4, 4, 100)
y = stats.norm.pdf(x, 0, 1)
plt.plot(x, y, 'b-', label='Normal Distribution')
# 95% 置信区间
ci_lower, ci_upper = stats.norm.interval(0.95, loc=0, scale=1)
plt.fill_between(x, y, where=(x >= ci_lower) & (x <= ci_upper), color='red', alpha=0.3, label='95% CI')
plt.title('Normal Distribution with 95% Confidence Interval - how2matplotlib.com')
plt.xlabel('X')
plt.ylabel('Probability Density')
plt.legend()
plt.text(0, 0.1, f'95% CI: [{ci_lower:.2f}, {ci_upper:.2f}]', ha='center')
plt.grid(True)
plt.show()
Output:
这个例子展示了标准正态分布的95%置信区间。我们使用stats.norm.interval()
函数计算置信区间,然后用plt.fill_between()
函数填充这个区域。
11. 绘制正态分布的概率密度函数和累积分布函数的对比
为了更好地理解正态分布的特性,我们可以在同一图中绘制概率密度函数(PDF)和累积分布函数(CDF):
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-4, 4, 100)
pdf = stats.norm.pdf(x, 0, 1)
cdf = stats.norm.cdf(x, 0, 1)
fig, ax1 = plt.subplots(figsize=(10, 6))
ax1.plot(x, pdf, 'b-', label='PDF')
ax1.set_ylabel('Probability Density', color='b')
ax1.tick_params(axis='y', labelcolor='b')
ax2 = ax1.twinx()
ax2.plot(x, cdf, 'r-', label='CDF')
ax2.set_ylabel('Cumulative Probability', color='r')
ax2.tick_params(axis='y', labelcolor='r')
plt.title('PDF and CDF of Normal Distribution - how2matplotlib.com')
plt.xlabel('X')
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
plt.grid(True)
plt.show()
Output:
这个例子使用了双Y轴来同时显示PDF和CDF。这种可视化方法可以帮助我们更好地理解这两个函数之间的关系。
12. 绘制正态分布的分位数函数分位数函数(Quantile Function)是累积分布函数的反函数,它在统计学中也有重要应用。让我们来绘制正态分布的分位数函数:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
p = np.linspace(0.01, 0.99, 100)
q = stats.norm.ppf(p, 0, 1)
plt.plot(p, q, 'b-')
plt.title('Quantile Function of Normal Distribution - how2matplotlib.com')
plt.xlabel('Probability')
plt.ylabel('Quantile')
plt.grid(True)
plt.axhline(y=0, color='r', linestyle='--')
plt.axvline(x=0.5, color='r', linestyle='--')
plt.text(0.5, -3, 'Median', ha='center', va='top')
plt.text(0.01, 0, 'Mean', ha='left', va='center')
plt.show()
Output:
这个例子使用stats.norm.ppf()
函数计算了正态分布的分位数。我们还添加了中位数和均值的标记,以便更好地理解分布的特性。
13. 绘制正态分布的Box-Cox变换
Box-Cox变换是一种常用的数据变换方法,可以帮助使数据更接近正态分布。让我们来可视化这个过程:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
np.random.seed(42)
data = np.random.lognormal(0, 0.5, 1000)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 原始数据
ax1.hist(data, bins=30, density=True, alpha=0.7)
ax1.set_title('Original Data - how2matplotlib.com')
ax1.set_xlabel('X')
ax1.set_ylabel('Density')
# Box-Cox变换后的数据
transformed_data, lambda_param = stats.boxcox(data)
ax2.hist(transformed_data, bins=30, density=True, alpha=0.7)
ax2.set_title(f'Box-Cox Transformed Data (λ={lambda_param:.2f}) - how2matplotlib.com')
ax2.set_xlabel('X')
ax2.set_ylabel('Density')
plt.tight_layout()
plt.show()
Output:
这个例子首先生成了一些对数正态分布的数据,然后使用stats.boxcox()
函数进行Box-Cox变换。我们可以看到变换后的数据更接近正态分布。
14. 绘制正态分布的概率图
概率图是另一种用于检验数据是否符合正态分布的图形方法:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
np.random.seed(42)
data = np.random.normal(0, 1, 1000)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 正态概率图
stats.probplot(data, dist="norm", plot=ax1)
ax1.set_title('Normal Probability Plot - how2matplotlib.com')
# 直方图
ax2.hist(data, bins=30, density=True, alpha=0.7)
x = np.linspace(data.min(), data.max(), 100)
ax2.plot(x, stats.norm.pdf(x, data.mean(), data.std()), 'r-', lw=2)
ax2.set_title('Histogram with Fitted Normal Distribution - how2matplotlib.com')
ax2.set_xlabel('X')
ax2.set_ylabel('Density')
plt.tight_layout()
plt.show()
Output:
这个例子创建了两个子图:一个是正态概率图,另一个是直方图与拟合的正态分布曲线。正态概率图中的点越接近直线,数据就越符合正态分布。
15. 绘制正态分布的标准分数
标准分数(Z-score)表示一个数据点偏离平均值的标准差数量。让我们来可视化这个概念:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-4, 4, 100)
y = stats.norm.pdf(x, 0, 1)
plt.plot(x, y, 'b-', label='Standard Normal Distribution')
plt.fill_between(x, y, where=(x >= -1) & (x <= 1), color='red', alpha=0.3, label='68%')
plt.fill_between(x, y, where=(x >= -2) & (x <= 2), color='yellow', alpha=0.2, label='95%')
plt.fill_between(x, y, where=(x >= -3) & (x <= 3), color='green', alpha=0.1, label='99.7%')
plt.title('Standard Normal Distribution with Z-scores - how2matplotlib.com')
plt.xlabel('Z-score')
plt.ylabel('Probability Density')
plt.legend()
for i in range(1, 4):
plt.axvline(x=i, color='gray', linestyle='--', alpha=0.5)
plt.axvline(x=-i, color='gray', linestyle='--', alpha=0.5)
plt.text(i, 0.01, f'+{i}σ', ha='center')
plt.text(-i, 0.01, f'-{i}σ', ha='center')
plt.grid(True)
plt.show()
Output:
这个例子展示了标准正态分布中不同标准差范围所包含的数据比例,并标注了相应的Z-score。
16. 绘制正态分布的偏度和峰度
偏度和峰度是描述分布形状的重要统计量。让我们来可视化不同偏度和峰度的分布:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-5, 5, 100)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 偏度
y1 = stats.skewnorm.pdf(x, 0, loc=0, scale=1)
y2 = stats.skewnorm.pdf(x, 5, loc=0, scale=1)
y3 = stats.skewnorm.pdf(x, -5, loc=0, scale=1)
ax1.plot(x, y1, 'b-', label='Skewness = 0')
ax1.plot(x, y2, 'r--', label='Positive Skewness')
ax1.plot(x, y3, 'g:', label='Negative Skewness')
ax1.set_title('Skewness - how2matplotlib.com')
ax1.set_xlabel('X')
ax1.set_ylabel('Probability Density')
ax1.legend()
# 峰度
y1 = stats.norm.pdf(x, 0, 1)
y2 = stats.t.pdf(x, 2)
y3 = stats.laplace.pdf(x, 0, 1)
ax2.plot(x, y1, 'b-', label='Normal (Kurtosis = 3)')
ax2.plot(x, y2, 'r--', label='High Kurtosis')
ax2.plot(x, y3, 'g:', label='Low Kurtosis')
ax2.set_title('Kurtosis - how2matplotlib.com')
ax2.set_xlabel('X')
ax2.set_ylabel('Probability Density')
ax2.legend()
plt.tight_layout()
plt.show()
Output:
这个例子展示了不同偏度和峰度的分布。偏度描述分布的不对称性,而峰度描述分布的尖峭程度。
17. 绘制正态分布的置信椭圆
对于二维正态分布,我们可以使用置信椭圆来表示数据的分布:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
np.random.seed(42)
x = np.random.normal(0, 1, 1000)
y = 0.8 * x + np.random.normal(0, 0.5, 1000)
fig, ax = plt.subplots(figsize=(10, 8))
# 散点图
ax.scatter(x, y, alpha=0.5)
# 计算置信椭圆
cov = np.cov(x, y)
lambda_, v = np.linalg.eig(cov)
lambda_ = np.sqrt(lambda_)
for n_std in [1, 2, 3]:
ell = plt.matplotlib.patches.Ellipse(xy=(np.mean(x), np.mean(y)),
width=lambda_[0]*n_std*2, height=lambda_[1]*n_std*2,
angle=np.rad2deg(np.arctan2(*v[:,0][::-1])),
edgecolor='red', fc='None', lw=2, alpha=0.5)
ax.add_artist(ell)
ax.text(ell.center[0], ell.center[1], f'{n_std}σ', ha='center', va='center')
ax.set_title('Confidence Ellipses for Bivariate Normal Distribution - how2matplotlib.com')
ax.set_xlabel('X')
ax.set_ylabel('Y')
plt.grid(True)
plt.show()
Output:
这个例子生成了一个二维正态分布的数据,并绘制了1σ、2σ和3σ的置信椭圆。这些椭圆分别包含了大约68%、95%和99.7%的数据点。
结论
通过本文的详细介绍和丰富的示例,我们深入探讨了如何使用Python的Matplotlib库绘制正态分布图。我们不仅学习了基本的正态分布绘图技巧,还探索了多种高级可视化方法,包括3D图形、混合分布、置信区间、Q-Q图等。这些技能在数据分析、统计学和机器学习等领域都有广泛的应用。
正态分布是统计学中最重要的概率分布之一,掌握其可视化技巧对于理解和解释数据至关重要。通过实践本文中的示例,读者可以加深对正态分布特性的理解,并能够根据具体需求创建各种类型的正态分布图。