使用python / numpy进行时间和内存高效的随机抽样

时间:2016-05-03 08:31:13

标签: python list numpy random out-of-memory

我需要计算单位平方内2个随机均匀分布点之间距离的期望值。这个问题可以通过分析解决,答案大约是0.521405。我想要完成的是使用随机数生成器和带有和没有numpy的Python来提出这个数字。使用以下代码

dist=list()
random.seed()
for each in range(100000000):
    x1=random.random()
    x2=random.random()
    y1=random.random()
    y2=random.random()
    dist.append(math.sqrt((x1-x2)**2+(y1-y2)**2))
print(round(sum(dist)/float(len(dist)),6))

它在我的机器上以125秒迭代 1亿次,但只有4位十进制数字是正确的。 现在,随着numpy我创建了以下代码

dist=list()
start_time = time.time()
np.random.seed()
for each in range(100000000):
    x = np.array((np.random.random(),np.random.random()))
    y = np.array((np.random.random(),np.random.random()))
    dist.append(np.linalg.norm(x-y))
print(round(np.mean(dist),6))

并且需要 1111秒来迭代相同的1亿次次!

由于结果只有4个十进制数字正确,我尝试使用以前的版本将迭代次数增加到10亿,没有numpy。我想,因为每个浮点数都在大多数64位(我使用64位Python)该列表大约需要8 GB。 但是,该程序耗尽了 26GB 的内存,并且在列表 7.9亿件

时出现例外情况

所以我正在寻求你的建议:

  1. 有没有办法利用各种numpy优化,实际上让它更快地运行?
  2. 有没有办法让程序更节省内存?我意识到列表是一种比我的目的更复杂的数据结构
  3. 我是否正确假设为了获得6位十进制数字,我需要接近10 ^ 12的迭代次数? (因为N次测量的标准误差正在减少为1 / sqrt(N))
  4. 提前致谢!

4 个答案:

答案 0 :(得分:4)

要回答前两个子问题,这里有一种方法可以一次性生成所有随机数,然后利用np.einsum替换大部分np.linalg.norm的工作(平衡差异)并沿着行总和),保持代码的其余部分。实现看起来像这样 -

N = 100000 # Edit this to change number of random points
x,y = np.random.random((2,N,2))
diffs = x-y
out = round(np.mean(np.sqrt(np.einsum('ij,ij->i',diffs,diffs))),6)

答案 1 :(得分:2)

至于内存问题,你对浮动的假设需要64位'不太正确。每个float对象(实际上,它是python中的盒装对象)将占用24个字节。您可以使用sys.getsizeof(0.0)进行检查。因此,您的程序应该需要比您估计的空间多3倍的空间,这大约是您实际经历的空间。

答案 2 :(得分:1)

假设您使用的是Python 3,我建议使用此变种而不使用numpy

random.seed()
dist_count = 100000000
dist_sum = 0

for _ in range(dist_count):
    dx = random.random() - random.random()  # x1 - x2
    dy = random.random() - random.random()  # y1 - y2

    dist += math.sqrt( dx*dx + dy*dy )

dist_average = dist_sum / dist_count
print(round(dist_average, 6))

首先,如果我们要计算并总结它们,为什么我们应该将所有距离存储在列表中?将每个随机距离直接添加到整数变量更快。此外,我们已经知道我们创建了多少随机距离,因为这是我们在for-loop范围内指定的距离,因此我们不需要像len(dist)或单独的计数器那样的任何距离。

此外,我们不必为每个坐标指定名称,我们只需动态计算dxdy差异即可。这也有助于我们进行下一步。

将相同的值与自身相乘比将其提高到2的幂(further reading...)要快一些。因此,我们当然会将a**2替换为a*a。现在我们直接存储上述差异变得很有用。

最后,我们将距离总和除以计数并显示结果一次。

答案 3 :(得分:1)

嗯,return_written_record_id在我的笔记本电脑上快一点,13.5秒对post的15.2秒 在记忆方面它可能不会使用10亿,当前版本需要~6G

代码:

hypot