【问题标题】:Why the result always is around 2.87为什么结果总是在 2.87 左右
【发布时间】:2019-06-07 08:16:00
【问题描述】:

我有以下代码

result=0
loop_n=10000
for i in range(loop_n):
    result+=np.random.rand(3,4,10).std()
result=result/loop_n
print(result)

据我了解,如果我多次运行,结果应该是不同的,因为结果来自随机,但实际上结果总是在 0.287 左右

这背后有什么理论吗?

【问题讨论】:

  • 顺便说一句:最后一行打算表达什么?它只会在 python 控制台中打印,否则你需要print()。还包括所有导入
  • 我只是想了解python是如何计算标准的
  • 或许更好的问题应该是“为什么期望值为 0.287”
  • @RoMa numpy 来自uniform distribution 的样本。 unifrom 分布的标准差公式为sqrt((b-a)**2/12),其中ba 是分布的下限和上限。对于01,这是0.288

标签: python numpy math random


【解决方案1】:

这只是证明np.random.rand 是一个很好的uniform 随机生成器。您有 10000 个遵循同一定律的分布标准差的观测值。标准差是方差的平方根,所以理论(概率)标准差是(max - min) / sqrt(12)。您有一个相当大的样本量,因此 观察到的 估计量将接近理论标准偏差 1/sqrt(12),约为 0.28867513459481287。但它现在变成了一个数学问题:-)


假设在 [0,1] 上均匀分布,概率(理论)均值 E(X) 是 x 在段 [0-1] 上的积分,即 0.5。根据定义,方差是 E((X-E(X))2) 可以计算为段 [-0.5,0.5] 上 x2 的积分及其平方根给出了上面写的结果。

【讨论】:

  • 抱歉用英文写了数学,但是SO不支持轻松写数学符号...
【解决方案2】:

1。为什么变化如此之小?

这就是大数定律。如果您经常从随机变量中抽样,您期望得到对真实均值的良好估计。

https://en.wikipedia.org/wiki/Law_of_large_numbers

2。为什么是 0.287?

rand 返回 0 和 1 之间均匀分布的数字,因此真实均值是 1/2,真实方差 是整数[-1/2..1/2] x^2 dx,您可以检查它是否为 1/12。 std 是 ~0.289 的平方根。

3。为什么不完全是 sqrt(1/12) ~ 0.289?

但是等等,这有点不对劲。为什么?因为numpy 返回的样本 var/std 是对真实事物的有偏估计,所以它系统地低估了它们。当您以相对较小的批次进行采样时,N=120 会产生微小但一致的差异。一旦我们插入校正 N/(N-1)(std 的平方),我们就会得到更好的匹配。您可以通过将关键字 ddof=1 传递给 std 在代码中尝试此操作。

4。但修正后的结果似乎有点太小了?

没错。校正因子N/(N-1)var 产生一个无偏估计量,但不是为std 产生一个无偏估计量,主要是因为先取平均值然后取sqrt 与取sqrt 然后取平均值不同。

您可以通过使用 var(仍然带有参数 ddof=1)而不是 std 并在取平均值后取 sqrt 来检查这一点:

loop_n=1000000
result=0
print_at = 1
for i in range(1, loop_n+1):
    result+=np.random.rand(3,4,10).var(ddof=1)
    if i == print_at:
        print(math.sqrt(result/i))
        print_at *= 10

print("...")
print(math.sqrt(1/12))

示例运行:

0.28103387158480164
0.2952158859220745
0.2902562660869275
0.28882685146952614
0.2887019908636715
0.2886783761564752
0.2886714244895549
...
0.28867513459481287

【讨论】:

    【解决方案3】:

    让我们看看你在做什么:

    • 在每个步骤中,您让np 生成 120 个介于 0 和 1 之间的随机值并获得它们的标准差。它总是在 0.2887 左右,有时更多,有时更少。说明见下文。
    • 您将所有这些标准偏差相加,然后除以它们的计数。从本质上讲,您会得到它们的平均值。
    • 因为你有这么多,他们越来越接近0.2887的预期值。

    解释:

    如果您在 Python 控制台中执行 while 1: np.random.rand(3,4,10).std(),您会看到发出很多数字(直到您按下 Ctrl-C),它们有时是 .266,有时是 .297,等等。

    但它们是什么意思?好吧,标准差是(非常粗略地说)一组值与其平均值的距离的平均值。

    • 如果取[.5, .5, .5],则平均值为.5,标准为0
    • 但是对于[0, .5, 1],平均值也是.5,但标准是.408248
    • 使用np.f64([.0, .1, .2, .3, .4, .5, .6, .7, .8, .9, 1]).std(),您将获得.316
    • 使用np.random.rand(300,300,300).std(),您得到的结果与您所做的大致相同:总是在.2887 附近。 为什么期望值正好是.2887 源于标准差的定义。本质上,它源于np.random.rand() 产生的预期均匀分布。

    【讨论】:

      【解决方案4】:

      numpy 函数 rand 从均匀分布 [0, 1) 中抽取一个随机数,这意味着有相同的概率得到 0 到 1 之间的任何数字。您的代码从该分布中抽取 120 个随机数并计算使用公式估计标准差

      std = sqrt(mean(abs(x - x.mean())**2))
      

      然后,您的代码会计算标准差估计值的平均值,这将使估计值收敛到理论值。

      为了计算理论值,我们可以将variance(x) = 1/12 用于均匀分布中的随机变量X。这意味着std(x) = sqrt(1/12) = 0.2887,与模拟结果接近。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-06
        • 2010-11-03
        • 2018-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多