使用Numpy和Matplotlib绘制正态分布图
参考:Normal Distribution Plot using Numpy and Matplotlib
正态分布,也称为高斯分布,是统计学和概率论中最重要的概率分布之一。它在自然科学、社会科学和工程领域中有广泛的应用。本文将详细介绍如何使用Python的Numpy和Matplotlib库来绘制正态分布图,包括基本概念、数据生成、图形绘制以及各种自定义选项。
1. 正态分布的基本概念
正态分布是一种连续型概率分布,其概率密度函数呈钟形曲线。它由两个参数决定:均值μ(决定分布的中心位置)和标准差σ(决定分布的宽度)。正态分布的概率密度函数为:
f(x) = (1 / (σ * √(2π))) * e^(-(x-μ)^2 / (2σ^2))
其中,e是自然对数的底数,π是圆周率。
在Python中,我们可以使用Numpy库来生成符合正态分布的随机数,并使用Matplotlib库来绘制分布图。
2. 环境准备
在开始之前,我们需要确保已经安装了必要的Python库。可以使用以下命令安装:
pip install numpy matplotlib
安装完成后,我们就可以开始编写代码了。
3. 基本正态分布图
让我们从最简单的正态分布图开始。我们将使用Numpy生成随机数,然后用Matplotlib绘制直方图和密度曲线。
import numpy as np
import matplotlib.pyplot as plt
# 生成随机数
mu, sigma = 0, 1 # 均值和标准差
s = np.random.normal(mu, sigma, 1000)
# 绘制直方图
count, bins, ignored = plt.hist(s, 30, density=True)
# 绘制密度曲线
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *
np.exp( - (bins - mu)**2 / (2 * sigma**2) ),
linewidth=2, color='r')
plt.title('Normal Distribution Plot - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()
Output:
在这个例子中,我们首先使用np.random.normal()
函数生成1000个符合正态分布的随机数。然后,我们使用plt.hist()
函数绘制直方图,并使用plt.plot()
函数绘制理论密度曲线。最后,我们添加标题和轴标签,并显示图形。
4. 自定义正态分布图
我们可以通过调整各种参数来自定义正态分布图的外观。以下是一些常见的自定义选项:
4.1 调整均值和标准差
我们可以通过改变均值和标准差来改变分布的形状和位置。
import numpy as np
import matplotlib.pyplot as plt
mu, sigma = 5, 2 # 新的均值和标准差
s = np.random.normal(mu, sigma, 1000)
count, bins, ignored = plt.hist(s, 30, density=True, alpha=0.7)
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *
np.exp( - (bins - mu)**2 / (2 * sigma**2) ),
linewidth=2, color='r')
plt.title('Custom Normal Distribution - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()
Output:
在这个例子中,我们将均值设为5,标准差设为2。这会使分布向右移动,并变得更宽。
4.2 调整直方图的外观
我们可以通过调整直方图的参数来改变其外观,例如改变柱子的颜色、透明度等。
import numpy as np
import matplotlib.pyplot as plt
mu, sigma = 0, 1
s = np.random.normal(mu, sigma, 1000)
plt.hist(s, 30, density=True, alpha=0.7, color='skyblue', edgecolor='black')
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *
np.exp( - (bins - mu)**2 / (2 * sigma**2) ),
linewidth=2, color='r')
plt.title('Customized Histogram - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()
在这个例子中,我们将直方图的颜色设为天蓝色,边缘设为黑色,并调整了透明度。
4.3 添加网格线
添加网格线可以帮助读者更好地理解数据。
import numpy as np
import matplotlib.pyplot as plt
mu, sigma = 0, 1
s = np.random.normal(mu, sigma, 1000)
count, bins, ignored = plt.hist(s, 30, density=True)
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *
np.exp( - (bins - mu)**2 / (2 * sigma**2) ),
linewidth=2, color='r')
plt.title('Normal Distribution with Grid - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.grid(True, linestyle='--', alpha=0.7)
plt.show()
Output:
这个例子中,我们使用plt.grid()
函数添加了网格线,并设置了线型和透明度。
4.4 自定义坐标轴范围
有时我们可能需要调整坐标轴的范围以更好地展示数据。
import numpy as np
import matplotlib.pyplot as plt
mu, sigma = 0, 1
s = np.random.normal(mu, sigma, 1000)
count, bins, ignored = plt.hist(s, 30, density=True)
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *
np.exp( - (bins - mu)**2 / (2 * sigma**2) ),
linewidth=2, color='r')
plt.title('Normal Distribution with Custom Axis Range - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.xlim(-4, 4)
plt.ylim(0, 0.5)
plt.show()
Output:
在这个例子中,我们使用plt.xlim()
和plt.ylim()
函数分别设置了x轴和y轴的范围。
5. 多个正态分布的比较
有时我们可能需要在同一张图上比较多个正态分布。
import numpy as np
import matplotlib.pyplot as plt
mu1, sigma1 = 0, 1
mu2, sigma2 = 2, 1.5
s1 = np.random.normal(mu1, sigma1, 1000)
s2 = np.random.normal(mu2, sigma2, 1000)
plt.hist(s1, 30, density=True, alpha=0.7, color='skyblue', label='Distribution 1')
plt.hist(s2, 30, density=True, alpha=0.7, color='salmon', label='Distribution 2')
plt.plot(bins, 1/(sigma1 * np.sqrt(2 * np.pi)) *
np.exp( - (bins - mu1)**2 / (2 * sigma1**2) ),
linewidth=2, color='blue')
plt.plot(bins, 1/(sigma2 * np.sqrt(2 * np.pi)) *
np.exp( - (bins - mu2)**2 / (2 * sigma2**2) ),
linewidth=2, color='red')
plt.title('Comparison of Two Normal Distributions - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.legend()
plt.show()
在这个例子中,我们生成了两个不同参数的正态分布,并用不同的颜色在同一张图上绘制它们的直方图和密度曲线。
6. 3D正态分布图
我们还可以绘制3D的正态分布图,这对于理解二维正态分布特别有帮助。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def multivariate_normal(x, y, x0, y0, sigmax, sigmay):
return np.exp(-((x-x0)**2/(2*sigmax**2) + (y-y0)**2/(2*sigmay**2)))
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = multivariate_normal(X, Y, 0, 0, 1, 1)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
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.show()
Output:
这个例子中,我们定义了一个二维正态分布函数,然后使用plot_surface()
函数绘制了3D表面图。
7. 正态分布的累积分布函数(CDF)
除了概率密度函数,我们还可以绘制正态分布的累积分布函数(CDF)。
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
x = np.linspace(-3, 3, 100)
y = norm.cdf(x)
plt.plot(x, y, 'b-', linewidth=2)
plt.title('Cumulative Distribution Function - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Cumulative Probability')
plt.grid(True)
plt.show()
Output:
在这个例子中,我们使用SciPy库的norm.cdf()
函数计算了正态分布的累积分布函数,并绘制了图形。
8. Q-Q图(Quantile-Quantile Plot)
Q-Q图是用来比较两个概率分布的图形方法。它经常被用来检验数据是否符合正态分布。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
# 生成正态分布数据
np.random.seed(1234)
data = np.random.normal(0, 1, 1000)
# 创建Q-Q图
fig, ax = plt.subplots(figsize=(8, 4))
stats.probplot(data, dist="norm", plot=ax)
ax.set_title("Q-Q plot - how2matplotlib.com")
plt.show()
Output:
在这个例子中,我们使用SciPy的stats.probplot()
函数创建了Q-Q图。如果数据点大致落在一条直线上,则表明数据近似服从正态分布。
9. 正态分布的置信区间
在统计推断中,置信区间是一个非常重要的概念。我们可以在正态分布图上显示置信区间。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
mu, sigma = 0, 1
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
y = stats.norm.pdf(x, mu, sigma)
fig, ax = plt.subplots()
ax.plot(x, y, 'b-', linewidth=2)
# 95% 置信区间
ci = stats.norm.interval(0.95, loc=mu, scale=sigma)
ax.fill_between(x, y, where=(x >= ci[0]) & (x <= ci[1]), color='skyblue', alpha=0.5)
ax.set_title('Normal Distribution with 95% Confidence Interval - how2matplotlib.com')
ax.set_xlabel('Value')
ax.set_ylabel('Probability Density')
plt.show()
Output:
在这个例子中,我们使用stats.norm.interval()
函数计算了95%的置信区间,并用fill_between()
函数在图上标出了这个区间。
10. 正态分布的概率密度函数(PDF)和累积分布函数(CDF)的对比
为了更好地理解正态分布,我们可以在同一张图上绘制PDF和CDF。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
mu, sigma = 0, 1
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
y_pdf = stats.norm.pdf(x, mu, sigma)
y_cdf = stats.norm.cdf(x, mu, sigma)
fig, ax1 = plt.subplots()
ax1.plot(x, y_pdf, 'b-', linewidth=2, label='PDF')
ax1.set_ylabel('Probability Density', color='b')
ax1.tick_params(axis='y', labelcolor='b')
ax2 = ax1.twinx()
ax2.plot(x, y_cdf, 'r-', linewidth=2, label='CDF')
ax2.set_ylabel('Cumulative Probability', color='r')
ax2.tick_params(axis='y', labelcolor='r')
plt.title('PDF vs CDF of Normal Distribution - how2matplotlib.com')
plt.xlabel('Value')
fig.legend(loc="upper right", bbox_to_anchor=(1,1), bbox_transform=ax1.transAxes)
plt.show()
Output:
在这个例子中,我们使用了双Y轴来同时显示PDF和CDF。这样可以直观地看出PDF和CDF之间的关系。
11. 正态分布的标准化
标准化是将任何正态分布转换为标准正态分布(均值为0,标准差为1)的过程。我们可以通过图形来展示这个过程。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
mu, sigma = 2, 1.5
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
y = stats.normfig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 10))
# 原始分布
ax1.plot(x, y.pdf(x, mu, sigma), 'b-', linewidth=2, label='Original')
ax1.set_title('Original Normal Distribution - how2matplotlib.com')
ax1.set_xlabel('Value')
ax1.set_ylabel('Probability Density')
ax1.legend()
# 标准化后的分布
x_std = (x - mu) / sigma
ax2.plot(x_std, y.pdf(x_std, 0, 1), 'r-', linewidth=2, label='Standardized')
ax2.set_title('Standardized Normal Distribution - how2matplotlib.com')
ax2.set_xlabel('Value')
ax2.set_ylabel('Probability Density')
ax2.legend()
plt.tight_layout()
plt.show()
这个例子展示了原始的正态分布和标准化后的正态分布。标准化后,分布的形状保持不变,但均值变为0,标准差变为1。
12. 正态分布的叠加
多个正态分布的叠加也是正态分布。我们可以通过图形来展示这一点。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np.linspace(-10, 10, 1000)
# 定义三个不同的正态分布
y1 = stats.norm.pdf(x, -2, 1)
y2 = stats.norm.pdf(x, 0, 2)
y3 = stats.norm.pdf(x, 3, 1.5)
# 叠加这些分布
y_sum = y1 + y2 + y3
plt.figure(figsize=(10, 6))
plt.plot(x, y1, 'r--', label='Distribution 1')
plt.plot(x, y2, 'g--', label='Distribution 2')
plt.plot(x, y3, 'b--', label='Distribution 3')
plt.plot(x, y_sum, 'k-', linewidth=2, label='Sum')
plt.title('Sum of Normal Distributions - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Probability Density')
plt.legend()
plt.grid(True)
plt.show()
Output:
这个例子展示了三个不同的正态分布及其叠加结果。可以看到,叠加后的分布仍然呈现出钟形曲线的特征。
13. 正态分布的截断
在某些情况下,我们可能需要处理截断的正态分布,即只考虑某个范围内的值。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
mu, sigma = 0, 1
lower, upper = -1, 1
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 1000)
y = stats.truncnorm.pdf(x, (lower-mu)/sigma, (upper-mu)/sigma, loc=mu, scale=sigma)
plt.figure(figsize=(10, 6))
plt.plot(x, y, 'b-', linewidth=2)
plt.fill_between(x, y, where=((x >= lower) & (x <= upper)), color='skyblue', alpha=0.5)
plt.title('Truncated Normal Distribution - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Probability Density')
plt.axvline(lower, color='r', linestyle='--')
plt.axvline(upper, color='r', linestyle='--')
plt.show()
Output:
这个例子展示了一个在[-1, 1]范围内截断的标准正态分布。截断区域用浅蓝色填充,截断点用红色虚线标出。
14. 正态分布的参数估计
在实际应用中,我们经常需要从样本数据中估计正态分布的参数。我们可以使用直方图和拟合的正态分布曲线来可视化这个过程。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
# 生成样本数据
np.random.seed(0)
data = np.random.normal(loc=5, scale=2, size=1000)
# 估计参数
mu_est, sigma_est = stats.norm.fit(data)
# 绘图
x = np.linspace(min(data), max(data), 100)
y = stats.norm.pdf(x, mu_est, sigma_est)
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, density=True, alpha=0.7, color='skyblue')
plt.plot(x, y, 'r-', linewidth=2)
plt.title(f'Estimated Normal Distribution (μ={mu_est:.2f}, σ={sigma_est:.2f}) - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()
Output:
这个例子首先生成了一些样本数据,然后使用stats.norm.fit()
函数估计了正态分布的参数。最后,我们绘制了数据的直方图和拟合的正态分布曲线。
15. 正态分布的概率计算
正态分布的一个重要应用是计算某个区间内的概率。我们可以通过图形直观地展示这一过程。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
mu, sigma = 0, 1
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 1000)
y = stats.norm.pdf(x, mu, sigma)
# 计算概率
a, b = -1, 1
prob = stats.norm.cdf(b, mu, sigma) - stats.norm.cdf(a, mu, sigma)
plt.figure(figsize=(10, 6))
plt.plot(x, y, 'b-', linewidth=2)
plt.fill_between(x, y, where=((x >= a) & (x <= b)), color='skyblue', alpha=0.5)
plt.title(f'Probability between {a} and {b}: {prob:.4f} - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Probability Density')
plt.axvline(a, color='r', linestyle='--')
plt.axvline(b, color='r', linestyle='--')
plt.show()
Output:
这个例子计算并展示了标准正态分布在[-1, 1]区间内的概率。填充区域表示概率,红色虚线表示区间边界。
结论
正态分布是统计学中最重要的概率分布之一,它在自然科学、社会科学和工程领域中有广泛的应用。通过使用Python的Numpy和Matplotlib库,我们可以方便地生成正态分布数据并绘制各种类型的图表,包括概率密度函数(PDF)、累积分布函数(CDF)、Q-Q图等。这些图表帮助我们更好地理解和分析正态分布的特性。
在实际应用中,我们可能需要处理不同参数的正态分布、多个正态分布的比较、截断正态分布等情况。通过本文介绍的各种绘图技巧,我们可以灵活地处理这些情况,并生成清晰、直观的可视化结果。
此外,正态分布的参数估计、概率计算等操作也可以通过图形化的方式直观地展示出来,这对于教学和数据分析都非常有帮助。
总的来说,掌握使用Numpy和Matplotlib绘制正态分布图的技巧,对于数据科学家、统计学家和其他需要处理概率分布的专业人士来说都是非常有价值的技能。通过实践本文中的示例,读者可以深入理解正态分布的特性,并能够根据具体需求创建各种类型的正态分布图。