【发布时间】:2020-11-04 07:47:30
【问题描述】:
我正在尝试生成一个合成地震数据库,其中震级 ($M$) 在 $[M, M+\delta_M]$ 范围内的事件数 ($N$) 如下:
$\log_{10}(N) = a - bM$
其中 $a$ 和 $b$ 是常量。
我正在尝试使用 random 模块在 Python 中执行此操作。我知道我可以(或者至少我认为我可以 - 因为我还没有尝试过)使用 random.expovariate 但我认为我可以使用 random.random 进行如下转换:
-math.log10(random.random()))
我对 2,000,000 个样本运行此程序,然后将这些样本分箱到 0.1 个箱中并以对数刻度绘制。
红线表示用于生成合成样本的理论分布。
我不担心 x=4.5 以上的变化。这是由于点数少和自然随机性所致。我要问的是 x=0 附近点的非常小的(在这个比例下)变化。我从理论(蓝点)绘制了合成点的变化:
随着 x 的减少,事件的数量呈指数增长,因此与理论的变化应该减少 - 而不是增加。而 x=0 处的点则相反。
为了尝试找出我的问题所在,我编写了生成从 0 到 1 的数字的代码,步骤非常精细。然后每个数字都经过上述功能。结果(上图中的蓝点)是纯线性的,与理论值完全匹配。这说明我的转换函数和代码都没有问题。
所以上图中的 twp 点集之间的唯一区别是蓝色点是由对随机函数的 2,000,000 次调用生成的(然后将结果转换为幅度并分箱),而对于红色点我已经在 0 和 1 之间采取 2,000,000 步均匀(然后将结果转换为幅度并使用相同的代码进行分箱)。
所以我认为这与随机数生成器有关?
如果有任何指点,将不胜感激。谢谢。
[添加]
按照@Arty 的建议,将调用从random.random 更改为random.uniform(0,1),错误现在是对称分布的并且具有预期的大小。已在图中添加了 +- 1 个标准差。
显然random() 和uniform(0,1) 的做法略有不同。
我使用random.random、random.uniform(0,1)、np.random.random 和np.random.uniform(0, 1) 减少了我的代码并计算了合成数据,获得了 2,000,000 分。
对结果进行分箱并绘制观察到的数字与预期数字之间的差异(如下)。
还添加了 +-1 标准偏差限制。这些数字都是对称分布的,并且大小正确,表明所有随机生成器都工作正常。
我的结论是,在更改/优化代码的某个地方,我引入了一个现在已经丢失的问题。我非常想找到那个错误,所以我不会再犯了!
令我惊讶的是,我原来的错误代码能够正确执行,以至于它生成了一个看起来真实的合成,只有难以检测的轻微异常。
感谢大家的帮助,并向那些我不同意我说问题不在于随机数生成器的人道歉!
【问题讨论】:
-
您能否提供一个minimal reproducible example,说明您是如何执行生成、累积和分箱的?我认为两个最可能的原因是非正规数(在 0 附近提供更大范围的可能值;我还没有考虑到足以确定这是一个真正的可能性)或分箱中的错误,但这将有助于查看代码。
-
你能用你的代码测试np.random.uniform(0, 1)的随机性吗?它使用不同的算法和代码进行生成。有趣的是它是否会给出与
random.random()相同的结果。如果您提供执行此图表和测量的完整代码,也很好。 -
@RustyC 好的。但请注意,这很可能是一个统计问题——包括各种随机分布的特征。即使将您的比较作为 uniform 样本,您也已经引入了偏差,这可能不是您真正想要的。您的分箱偏向统一,但数据偏向小值(即,分箱中的数据不居中且不统一)。 Stack Overflow 适合找出为什么
random.random会偏离均匀分布,但不会在均匀分布不适合问题时警告您。 -
我看不出
random.uniform(0,1)会如何影响事情,它只会评估0 + 1 * random.random()所以应该会慢一点 -
@RustyC 你说“显然 random() 和 uniform(0,1) 做的事情略有不同。”但我已经链接到 CPython 代码,我们可以看到它没有做任何不同的事情