python - 如何从随机加权的矩阵中选择元素
问题描述
我对python很陌生,并且在随机性方面存在一些问题。
我正在寻找与Mathematica 中的RandomChoice类似的东西。我创建了一个维度矩阵,假设为 10x3,随机数大于 0。让我们将每行的总和称为 s_i for i=0,...,9
后来我想用加权概率 s_ij/s_i 为每一行选择 3 个元素中的 2 个(不重复)所以我需要这样的东西,但有加权概率
n=10
aa=np.random.uniform(1000, 2500, (n,3))
print(aa)
help=[0,1,2]
dd=np.zeros((n,2))
for i in range(n):
cc=random.sample(help,2)
dd[i,0]=aa[i,cc[0]]
dd[i,1]=aa[i,cc[1]]
print(dd)
在这里,速度也是一个重要因素,因为我将在 Montecarlo 方法中使用它(这就是我从 Mathematica 切换到 Python 的原因),我想,上面的代码可以大大改进
提前感谢任何提示/帮助
编辑:我现在有以下内容,它正在工作,但对我来说看起来不像好神
#pre-defined lists
nn=3
aa=np.random.uniform(1000, 2500, (nn,3))
help1=[0,1,2]
help2=aa.sum(axis=1)
#now I create a weigthed prob list and fill it
help3=np.zeros((nn,3))
for i in range(nn):
help3[i,0]=aa[i,0]/help2[i]
help3[i,1]=aa[i,1]/help2[i]
help3[i,2]=aa[i,2]/help2[i]
#every timestep when I have to choose 2 out of 3
help5=np.zeros((nn,2))
for i in range(nn):
#cc=random.sample(help1,2)
help4=np.random.choice(help1, 2, replace=False, p=[help3[i,0], help3[i,1], help3[i,2]])
help5[i,0]=aa[i,cc[0]]
help5[i,1]=aa[i,cc[1]]
print(help5)
解决方案
正如评论中指出的,np.random.choice
接受一个权重参数,所以你可以简单地在循环中使用它:
import numpy as np
# Make input data
np.random.seed(0)
n = 10
aa = np.random.uniform(1000, 2500, (n, 3))
s = np.random.rand(n, 3)
# Normalize weights
s_norm = s / s.sum(1, keepdims=True)
# Output array
out = np.empty((n, 2), dtype=aa.dtype)
# Sample iteratively
for i in range(n):
out[i] = aa[i, np.random.choice(3, size=2, replace=False, p=s_norm[i])]
但是,这并不是最有效的处理方式,因为通常使用矢量化操作比循环快得多。不幸的是,我认为没有任何方法可以同时从多个分类分布中进行采样(请参阅NumPy 问题 #15201)。但是,由于您总是希望从三个元素中获取两个元素,因此您可以对要删除的元素进行采样(使用倒置概率),然后保留另外两个。这个片段做了这样的事情:
import numpy as np
# Make input data
np.random.seed(0)
n = 10
aa = np.random.uniform(1000, 2500, (n, 3))
s = np.random.rand(n, 3)
print(s)
# [[0.26455561 0.77423369 0.45615033]
# [0.56843395 0.0187898 0.6176355 ]
# [0.61209572 0.616934 0.94374808]
# [0.6818203 0.3595079 0.43703195]
# [0.6976312 0.06022547 0.66676672]
# [0.67063787 0.21038256 0.1289263 ]
# [0.31542835 0.36371077 0.57019677]
# [0.43860151 0.98837384 0.10204481]
# [0.20887676 0.16130952 0.65310833]
# [0.2532916 0.46631077 0.24442559]]
# Invert weights
si = 1 / s
# Normalize
si_norm = si / si.sum(1, keepdims=True)
# Accumulate
si_cum = np.cumsum(si_norm, axis=1)
# Sample according to inverted probabilities
t = np.random.rand(n, 1)
idx = np.argmax(t < si_cum, axis=1)
# Get non-sampled indices
r = np.arange(3)
m = r != idx[:, np.newaxis]
choice = np.broadcast_to(r, m.shape)[m].reshape(n, -1)
print(choice)
# [[1 2]
# [0 2]
# [0 2]
# [1 2]
# [0 2]
# [0 2]
# [0 1]
# [1 2]
# [0 2]
# [1 2]]
# Get corresponding data
out = np.take_along_axis(aa, choice, 1)
这样做的一个可能的缺点是所选元素将始终按顺序排列(也就是说,对于给定的行,您可能会得到索引对(0, 1)
, (0, 2)
or (1, 2)
,但不是(1, 0)
, (2, 0)
or (2, 1)
)。
当然,如果你真的只需要几个样本,那么循环可能是最方便和可维护的解决方案,第二个只有在你需要更大规模地执行此操作时才有用。
推荐阅读
- amazon-web-services - 使用 AWS 的 Terraform
- laravel - Jetstream 安装失败:无法解析为可安装的软件包集
- python - 未能部署 Heroku 应用程序。错误:命令出错,退出状态为 1:/app/.heroku/python/bin/python -u -c 'import sys, setuptools, tokenize;
- python - python中列表字典的概率
- regex - 如果我尝试将它与 $1、$2 等反向引用一起使用,则字符串在 RewriteRule 中重复 20 次。诡异的。为什么?
- vba - VBA:为什么 For Each 循环比 For 循环快?
- c++ - 2D 矢量调整大小需要对象的默认构造函数
- excel - 获取 Gmail 中收件箱邮件的链接
- reactjs - 是否反应原生模板支持而不使用像反应 js 那样的打字稿?
- python - 如何在不使用 PyInputPlus 的情况下将计时器添加到 Python 循环(无异步或线程)