【发布时间】:2021-01-15 23:23:30
【问题描述】:
我想从约 10⁷ 整数的总体中抽样约 10⁷ 次,没有替换和权重,每次选择 10 个元素。每次采样后,我都会更改权重。我在以下脚本中计时了两种方法(python3 和 numpy)。这两种方法对我来说似乎都慢得令人痛苦,你有没有加快速度的方法?
import numpy as np
import random
@profile
def test_choices():
population = list(range(10**7))
weights = np.random.uniform(size=10**7)
np_weights = np.array(weights)
def numpy_choice():
np_w = np_weights / sum(np_weights)
c = np.random.choice(population, size=10, replace=False, p=np_w)
def python_choice():
c = []
while len(c) < 10:
c += random.choices(population=population, weights=weights, k=10 - len(c))
c = list(set(c))
for i in range(10**1):
numpy_choice()
python_choice()
add_weight = np.random.uniform()
random_element = random.randint(0, 10**7)
weights[random_element] += add_weight
np_weights[random_element] += add_weight
test_choices()
有计时器结果:
Line # Hits Time Per Hit % Time Line Contents
==============================================================
24 10 20720062.0 2072006.2 56.6 numpy_choice()
25 10 15593925.0 1559392.5 42.6 python_choice()
【问题讨论】:
-
只是为了澄清,您在每个 10 个样本后替换?
-
是的,每个样本的总体都是一样的,所以我在每个 10 个样本后替换。但是每个样本本身是没有替换的(= 一个样本的 10 个元素是唯一的)
-
顺便说一下,
weights和np_weights似乎是同一个数组的副本。另外,您需要population成为列表吗?看来您可以通过使用np.arange来提高效率。部分开销是 numpy 到列表到 numpy 的转换。 -
还有,
@profile是什么? -
是的 np_weights 是一个副本,但是它被 numpy_choice 修改了。 @profile 是线分析器的装饰器。 github.com/rkern/line_profiler
标签: python python-3.x numpy random