【问题标题】:How to plot normal distribution curve along with Central Limit theorem如何绘制正态分布曲线以及中心极限定理
【发布时间】:2019-04-04 09:34:01
【问题描述】:

我试图沿着我的中心极限数据分布获得正态分布曲线。

下面是我尝试过的实现。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
import math

# 1000 simulations of die roll
n = 10000

avg = []
for i in range(1,n):#roll dice 10 times for n times
    a = np.random.randint(1,7,10)#roll dice 10 times from 1 to 6 & capturing each event
    avg.append(np.average(a))#find average of those 10 times each time

plt.hist(avg[0:])

zscore = stats.zscore(avg[0:])

mu, sigma = np.mean(avg), np.std(avg)
s = np.random.normal(mu, sigma, 10000)

# Create the bins and histogram
count, bins, ignored = plt.hist(s, 20, normed=True)

# Plot the distribution curve
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (bins - mu)**2 / (2 * sigma**2)))

我得到下图,

你可以在底部看到红色的正态曲线。

谁能告诉我为什么曲线不合适?

【问题讨论】:

  • 您可能需要缩放其中一个。正态分布的最大值高于 1 IIRC,你的情节上升到 2500。
  • 要么将正态分布缩放到最大值(约 2700),要么使用ax.twinx()
  • 你能用代码显示吗?

标签: python numpy matplotlib statistics


【解决方案1】:

你几乎拥有它!首先,看到您在相同的轴上绘制了两个直方图:

plt.hist(avg[0:])

plt.hist(s, 20, normed=True)

因此,您可以在直方图上绘制正态密度,您正确地使用 normed=True 参数对第二个图进行了归一化。但是,您也忘记对第一个直方图进行归一化 (plt.hist(avg[0:]), normed=True)。

我还建议,既然您已经导入了 scipy.stats,那么您不妨使用该模块中的正态分布,而不是自己编写 pdf。

把这一切放在一起,我们有:

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats

# 1000 simulations of die roll
n = 10000

avg = []
for i in range(1,n):
    a = np.random.randint(1,7,10)
    avg.append(np.average(a))

# CHANGED: normalise this histogram too
plt.hist(avg[0:], 20, normed=True)

zscore = stats.zscore(avg[0:])

mu, sigma = np.mean(avg), np.std(avg)
s = np.random.normal(mu, sigma, 10000)

# Create the bins and histogram
count, bins, ignored = plt.hist(s, 20, normed=True)

# Use scipy.stats implementation of the normal pdf
# Plot the distribution curve
x = np.linspace(1.5, 5.5, num=100)
plt.plot(x, stats.norm.pdf(x, mu, sigma))

这给了我以下情节:

编辑

在您询问的 cmets 中:

  1. np.linspace中的1.5和5.5怎么选
  2. 是否可以在非标准化直方图上绘制正常内核?

到地址 q1。首先,我用眼睛选择了 1.5 和 5.5。绘制直方图后,我看到直方图箱的范围在 1.5 到 5.5 之间,所以这是我们想要绘制正态分布的范围。

选择此范围的更程序化方式是:

x = np.linspace(bins.min(), bins.max(), num=100)

至于问题 2,是的,我们可以实现您想要的。但是,您应该知道我们将不再绘制概率密度函数

在绘制直方图时删除normed=True 参数后:

x = np.linspace(bins.min(), bins.max(), num=100)

# Find pdf of normal kernel at mu
max_density = stats.norm.pdf(mu, mu, sigma)
# Calculate how to scale pdf
scale = count.max() / max_density

plt.plot(x, scale * stats.norm.pdf(x, mu, sigma))

这给了我以下情节:

【讨论】:

  • 嗨@Jack,感谢您的帮助,您能解释一下您在 np.linspace(1.5, 5.5, num=100) 中使用 1.5 和 5.5 值的依据是什么
  • 另外,我们是否可以尝试在不对直方图进行归一化的情况下绘制正态曲线,从而使曲线实际上绘制为直方图的原始值
【解决方案2】:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
import math

# 1000 simulations of die roll
n = 10000

avg = []
for i in range(1,n):#roll dice 10 times for n times
    a = np.random.randint(1,7,10)#roll dice 10 times from 1 to 6 & capturing each event
    avg.append(np.average(a))#find average of those 10 times each time

plt.hist(avg[0:],20,normed=True)

zscore = stats.zscore(avg[0:])

mu, sigma = np.mean(avg), np.std(avg)
s = np.random.normal(mu, sigma, 10000)

# Create the bins and histogram
count, bins, ignored = plt.hist(s, 20, normed=True)

# Plot the distribution curve
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (bins - mu)**2 / (2 * sigma**2)))

我刚刚缩小了平均列表直方图。

剧情:-

【讨论】:

  • 您能否详细解释一下,因为即使我注释掉绘制直方图的最后一行,我也无法理解为什么要绘制 2 个直方图
  • @penta 正如评论所暗示的,它绘制的是曲线,而不是直方图。图中的绿色曲线。注释掉最后一行只会删除绿色曲线
【解决方案3】:

逻辑似乎是正确的。

问题在于显示数据。

尝试使用 normed=true 对第一个直方图进行归一化,并为两个直方图设置相同的 bin。像20个垃圾箱。

【讨论】:

    【解决方案4】:

    掷骰子是均匀分布的情况。从 1 到 6 的任何数字出现的概率是 1/6。所以平均值和标准差由下式给出

    现在,CLT 表示,对于足够大的 n 值,即代码中的 10,n 次抛出的平均值的 pdf 将接近均值 3.5 和标准偏差 1.7078/sqrt(10) 的正态分布

    n_bins=50
    pdf_from_hist, bin_edges=np.histogram(np.array(avg), bins=n_bins, density=True)
    bin_mid_pts= np.add(bin_edges[:-1], bin_edges[1:])*0.5
    assert(len(list(pdf_from_hist))  == len(list(bin_mid_pts)))
    expected_std=1.7078/math.sqrt(10)
    expected_mean=3.5
    pk_s=[]
    qk_s=[]
    for i in range(n_bins):
        p=stat.norm.pdf(bin_mid_pts[i], expected_mean, expected_std) 
        q=pdf_from_hist[i]
        if q <= 1.0e-5:
            continue
        pk_s.append(p)
        qk_s.append(q)
    #compute the kl divergence
    kl_div=stat.entropy(pk_s, qk_s)
    print('the pdf of the mean of the 10 throws differ from the corresponding normal dist with a kl divergence of %r' % kl_div)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-06
      • 2019-11-04
      • 1970-01-01
      • 1970-01-01
      • 2012-03-02
      • 2011-10-27
      • 1970-01-01
      • 2017-02-18
      相关资源
      最近更新 更多