如何在Python中高效生成随机斜率和截距的直线?

9 投票
1 回答
3471 浏览
提问于 2025-04-18 18:01

考虑一个非常简单的蒙特卡洛模拟,用来表示一条直线 y = m * x + b,比如说为了可视化参数 mb 不确定性对结果的影响。这里的 mb 都是从正态分布中随机抽取的。假如我来自MATLAB的背景,我会这样写:

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(start=0, stop=5, step=0.1)

n_data = len(x)
n_rnd = 1000

m = np.random.normal(loc=1, scale=0.3, size=n_rnd) 
b = np.random.normal(loc=5, scale=0.3, size=n_rnd)

y = np.zeros((n_data, n_rnd))  # pre-allocate y

for realization in xrange(n_rnd):
    y[:,realization] = m[realization] * x + b[realization]

plt.plot(x, y, "k", alpha=0.05);

蒙特卡洛模拟直线

这样确实能得到想要的结果,但我感觉应该有更“Pythonic”的写法。难道我想错了吗?如果没有,能不能给我一些更高效的代码示例?

举个例子,我想要的效果是:在MATLAB中可以很容易地用 bsxfun() 来实现,而不需要使用循环。在Python中有没有类似的东西,或者说是否有相关的库可以使用?

1 个回答

9

你可以使用 numpy数组的广播功能,一步就创建你的 y 数组,下面是示例。

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(start=0, stop=5, step=0.1)

n_data = len(x)
n_rnd = 1000

m = np.random.normal(loc=1, scale=0.3, size=n_rnd) 
b = np.random.normal(loc=5, scale=0.3, size=n_rnd)

y = m * x[:, np.newaxis] + b

for val in y.transpose():
    plt.plot(x, val, alpha=0.05)

# Or without the iteration:
# plt.plot(x, y, alpha=0.05)

plt.show()

x[:, np.newaxis] 这个操作会把 x 变成一个形状为 (50, 1) 的列向量,而不是 (50,) 这样的形状,这样广播功能就能正常工作了。

接着,你可以直接遍历这个numpy数组(而不是遍历它的索引),不过你需要先转置这个数组(用 y.transpose()),否则在每次循环中你会得到每1000个随机数对应的x值。

撰写回答