Matlab转Python:有限随机变量生成代码转换及random.uniform报错问题排查
解决Matlab有限(s,p)随机变量采样代码转Python的问题
问题背景
你想要把Matlab中生成有限(s,p)随机变量样本的代码转换成Python,但自己写的代码运行时出现了uniform() missing 1 required positional argument: 'b'错误,先来看看原Matlab代码和你写的Python代码:
原Matlab代码
function x=finiterv(s,p,m) % returns m samples % of finite (s,p) rv %s=s(:);p=p(:); r=rand(m,1); cdf=cumsum(p); x=s(1+count(cdf,r));
你编写的Python代码(带错误)
def infinterv(s,p,m): #return m samples #of finite (s,p) rv r=random.uniform((m,1)) cdf=p.cumsum(axis=0) x=s(1+count(cdf,))
错误原因分析
你遇到的报错核心是随机数生成函数用错了:
- Matlab的
rand(m,1)是生成一个m行1列的数组,其中每个元素都是0到1之间的均匀分布随机数; - 而Python的
random.uniform(a, b)是生成单个在[a,b]区间的随机数,你传了(m,1)作为第一个参数,缺少了第二个必填的b参数,自然会报错。
另外,Python里也没有Matlab那种count(cdf, r)的用法,这部分也需要替换成合适的函数。
正确的Python实现(基于Numpy,和原Matlab逻辑一致)
推荐用Numpy来实现,因为它的数组操作和Matlab的矩阵操作逻辑最接近,代码如下:
import numpy as np def finiterv(s, p, m): # 返回有限(s,p)随机变量的m个样本 # s: 随机变量的取值数组 # p: 对应取值的概率数组,和s长度一致 # m: 生成的样本数量 s = np.asarray(s).flatten() # 转成一维数组,对应Matlab的s(:) p = np.asarray(p).flatten() # 转成一维数组,对应Matlab的p(:) # 生成m个0-1之间的均匀随机数,对应Matlab的rand(m,1) r = np.random.rand(m, 1) # 计算累积分布函数,对应Matlab的cumsum(p) cdf = np.cumsum(p) # 找到每个随机数r在cdf中的位置,对应Matlab的count(cdf,r) # searchsorted返回第一个大于r的索引,正好是我们需要的位置 indices = np.searchsorted(cdf, r, side='right') # 取出对应的s值,因为Python是0索引,不需要+1(Matlab是1索引所以原代码+1) x = s[indices] return x
代码细节解释
- 数组格式统一:用
np.asarray().flatten()把输入的s和p转成一维数组,对应Matlab里s=s(:)和p=p(:)的操作,确保后续计算不会出维度问题; - 随机数生成:
np.random.rand(m,1)完美对应Matlab的rand(m,1),生成m个0到1的随机数数组; - 累积分布计算:
np.cumsum(p)和Matlab的cumsum(p)完全一致,生成概率的累积数组; - 索引匹配:
np.searchsorted(cdf, r, side='right')的作用是,对于每个r值,找到它在cdf数组中应该插入的位置(保证插入后数组仍有序),这个位置正好对应原Matlab中count(cdf,r)的结果——因为count是统计cdf中小于r的元素个数,而searchsorted返回的索引就是这个个数,又因为Python是0索引,所以直接用这个索引取s的值即可,不需要像Matlab那样+1。
测试示例
比如你可以这样调用测试:
s = [1, 2, 3] p = [0.2, 0.3, 0.5] samples = finiterv(s, p, 10) print(samples)
运行后会得到10个符合概率分布的样本。
内容的提问来源于stack exchange,提问作者leetster
相关产品推荐
相关产品推荐

