如何在直方图上绘制匹配的钟形曲线?

3
我的代码到目前为止,我非常新于编程并一直在尝试。
在这里,我应用Box-Muller变换来近似两个高斯正态分布,从一个随机均匀采样开始。然后,我为它们创建了一个直方图。
现在,我想将获得的直方图与“真实情况”进行比较:一个标准的钟形曲线。如何绘制这样的曲线以匹配直方图?
import numpy as np
import matplotlib.pyplot as plt

N = 10000
z1 = np.random.uniform(0, 1.0, N)
z2 = np.random.uniform(0, 1.0, N)

R_sq = -2 * np.log(z1)
theta = 2 * np.pi * z2
z1 = np.sqrt(R_sq) * np.cos(theta)
z2 = np.sqrt(R_sq) * np.sin(theta)

fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)
ax.hist(z1, bins=40, range=(-4, 4), color='red')
plt.title("Histgram")
plt.xlabel("z1")
plt.ylabel("frequency")
ax2 = fig.add_subplot(2, 1, 2)
ax2.hist(z2, bins=40, range=(-4, 4), color='blue')
plt.xlabel("z2")
plt.show()

请说明发生了什么事情,包括任何错误信息。同时,请告诉我您得到了什么结果以及您期望的结果是什么。谢谢。 - Mark Setchell
代码运行良好,生成了一个正态分布直方图的良好图像。我只是不知道如何拟合高斯曲线。 - Krits
1个回答

3
为了获得“核密度估计”,scipy.stats.gaussian_kde计算一个函数来拟合数据。
如果只需要绘制高斯正态曲线,则使用 [scipy.stats.norm]。将均值减去并除以标准偏差,可以适应给定数据的位置。
这两个曲线都将被绘制成曲线下面积总和为一。 要将它们调整到直方图的大小,需要将这些曲线缩放为数据长度乘以bin宽度。 或者,可以通过添加参数hist(..., density=True)来缩放直方图,使这些曲线保持缩放为1。
在演示代码中,数据被篡改以说明kde和高斯正态之间的差异。
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats

x = np.linspace(-4,4,1000)
N = 10000
z1 = np.random.randint(1, 3, N) * np.random.uniform(0, .4, N)
z2 = np.random.uniform(0, 1, N)

R_sq = -2 * np.log(z1)
theta = 2 * np.pi * z2
z1 = np.sqrt(R_sq) * np.cos(theta)
z2 = np.sqrt(R_sq) * np.sin(theta)

fig = plt.figure(figsize=(12,4))
for ind_subplot, zi, col in zip((1, 2), (z1, z2), ('crimson', 'dodgerblue')):
    ax = fig.add_subplot(1, 2, ind_subplot)
    ax.hist(zi, bins=40, range=(-4, 4), color=col, label='histogram')
    ax.set_xlabel("z"+str(ind_subplot))
    ax.set_ylabel("frequency")

    binwidth = 8 / 40
    scale_factor = len(zi) * binwidth

    gaussian_kde_zi = stats.gaussian_kde(z1)
    ax.plot(x, gaussian_kde_zi(x)*scale_factor, color='springgreen', linewidth=3, label='kde')

    std_zi = np.std(zi)
    mean_zi = np.mean(zi)
    ax.plot(x, stats.norm.pdf((x-mean_zi)/std_zi)*scale_factor, color='black', linewidth=2, label='normal')
    ax.legend()

plt.show()

resulting plot

原始值z1和z2非常类似于正态分布,因此黑线(数据的高斯正态分布)和绿线(KDE)非常相似。

当前代码首先计算数据的真实平均值和真实标准差。由于您想模仿完美的高斯正态分布,因此应与具有零平均值和标准偏差为一的曲线进行比较。您会看到它们在图中几乎完全相同。

original distribution


我仍然不清楚某些行的作用。但我会查一下。另外,您是否更改了第一个z1和z2的值以显示kde和正常分布之间的更大差异?无论如何,非常感谢。 - Krits
是的,我只是改变了z1/z2来展示曲线之间的差异。在原始版本中,曲线几乎重合。这是合理的,因为你正在尝试模拟正态分布。绿线是一个平滑函数,试图适应直方图。黑线将是完美的高斯正态分布。 - JohanC
请参阅有关KDE的这篇有趣文章 - JohanC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接