English 中文(简体)
有效内存、高效随机数字迭代器,不替换
原标题:memory efficient random number iterator without replacement

我觉得这个应该很容易,但是经过无数次的搜索和尝试之后,我还是无法找到答案。基本上,我有很多项目要随机抽样,无需替换。在这种情况下,它们是2D阵列中的单元格。我用来缩小阵列的解决方案并不翻译,因为它需要在记忆阵列中进行打乱。如果我要抽查的数字很小,我也可以随机抽查项目,并保留我尝试过的数值清单。不幸的是,我经常要对所有细胞中的非常大比例进行抽样,无论数量多。

我所要创建的是一个迭代器,它使用一些迭代器、缩水和/或随机组合,产生下一个随机单元格(x和y 指数)。另一个可能的解决办法是创建一个迭代器,在 0 和 (x_count * y_count) 之间产生下一个随机数字(不替换),而我可以将数字映射回单元格位置。这两个数字似乎都不容易完成。

谢谢你的帮忙!

这是我目前的解决办法。

import numpy as np
import itertools as itr
import random as rdm

#works great
x_count = 10
y_count = 5

#good luck!
#x_count = 10000
#y_count = 20000

x_indices = np.arange(x_count)
y_indices = np.arange(y_count)

cell_indices = itr.product(x_indices, y_indices)
list_cell_indices = list(cell_indices)
rdm.shuffle(list_cell_indices)

for i in range(25):
    print list_cell_indices[i]

因此,根据目前的反应和我试图翻译的Perl, 我对此一无所知, 我的理解是,我能做的最好的就是:

import numpy as np
import itertools as itr
import random as rdm

x_count = 10000
y_count = 5000

sample_count = 10000
keep_probability = 0.01


tried_cells = set()
kept_cells = set()

while len(kept_cells) < sample_count:
    x = rdm.randint(0, x_count)
    y = rdm.randint(0, y_count)

    if (x, y) in tried_cells:
        pass
    else:
        tried_cells.add((x, y))
        keep = rdm.random() < keep_probability
        if keep:
            kept_cells.add((x,y))


print "worked"

在大多数情况下,所使用的处理时间和内存并不那么糟糕。 也许我可以检查一下平均单元格的保存概率和抽样数,然后对困难案例出错。

最佳回答

如何使用此方法 。 我首先创建 x* y 数组并将其重塑为 2 - D 。 然后, 了解每个单元格可以用一个单整数来识别, 然后从 0 到 (x *y) 获得样本 。

import numpy

x_count = 10000
y_count = 20000

x_indices = numpy.arange(x_count)
y_indices = numpy.arange(y_count)

large_table = numpy.arange(y_count * x_count).reshape(y_count, x_count)
print large_table

def get_random_item(sample_size):
    from random import sample
    for i in sample(xrange(y_count * x_count), sample_size):
        y,x = divmod(i, y_count)
        yield (x,y)

for x,y in get_random_item(10):
    print  %12i   x: %5i y: %5i  % (large_table[x][y],  x,y)

返回 :

(首先模拟您通过产品创建的现有 2D 数组)

[[        0         1         2 ...,      9997      9998      9999]
 [    10000     10001     10002 ...,     19997     19998     19999]
 [    20000     20001     20002 ...,     29997     29998     29999]
 ..., 
 [199970000 199970001 199970002 ..., 199979997 199979998 199979999]
 [199980000 199980001 199980002 ..., 199989997 199989998 199989999]
 [199990000 199990001 199990002 ..., 199999997 199999998 199999999]]

然后,它返回 2 位坐标,该坐标可以通过数组 [x [y] 直接转换成单元格内容

   154080675   x: 15408 y:   675
   186978188   x: 18697 y:  8188
   157506087   x: 15750 y:  6087
   168859259   x: 16885 y:  9259
    29775768   x:  2977 y:  5768
    94167866   x:  9416 y:  7866
    15978144   x:  1597 y:  8144
    91964007   x:  9196 y:  4007
   163462830   x: 16346 y:  2830
    62613129   x:  6261 y:  3129

(b) 说明它用于随机抽样,而无需替换,这一方法符合咨询意见。 这是特别快速和对大量人口取样有效的地方:样本(xrange(100000),60)。 在python < a href="http://docs.python.org/library/random.html" rel="nofollow">random 页面上发现的。

我注意到,虽然我使用“随机”项目()作为生成器,但底部样本()仍然在生成完整的列表,因此内存使用仍然是 y*x + 样本_ 大小,但运行速度相当快。

问题回答

我认为,完全不可能在没有替换 < em> 的情况下对一个序列进行抽样 < em > 进行取样,而不使用大量辅助储存,用于接近 < code> R * C < /code > 的样本大小。 虽然有聪明的方法可以减少小样本大小的储存量,但如果你期望取样量超过三分之一左右,你最好仅仅建立一个单独的清单。 random.sample 是这方面的一个自然选择;坦率地说,我将直接通过一个平坦版的2 - dimpy阵列。 (在这种情况下,不需要索引,随机取样插件并将其转换为坐标,一个 la < href="https://stackoverflow.com/a/10728868/577088 > hexfarrot s 解决方案,这是一条合理的方法。 )

>>> a = numpy.arange(25).reshape((5, 5))
>>> random.sample(a.ravel(), 5)
[0, 13, 8, 18, 4]

如果您查看 < a href=" http://hg. python. org/cpython/ file/2.7/Lib/random. py#l290" rel= "nofollow noreferr"\\code> code> random. sample , 你会看到,对于较小的样本大小, 它已经大致做了上面的 perl 代码 : 在一个集中跟踪先前选中的项目, 丢弃已经在集中的选择 。 对于更大的样本大小, 它创建了一个输入的副本 -- 其内存效率大于一个集的值, 因为设置占用的空间比每个存储的项目列表要多 -- 并且略微修改 < href=" http://en.wikipedia. org/wiki/ Fisher% E280% 93Yates_shutffle" rel= " nofoln noferrr" > fisher -Yates shaffle shuffle , 它有 < a > a, 它有 < decocodement > as_ regidufle < redufle < redufle < a/ all > all > all > a.

基本上,我的赌注是,你不会比 random.sample 做得更好,滚动你自己,除非你在c.中编码。

however -- 我确实发现了这一点,你可能会发现这一点很有意思:numpy.random.choice 。这似乎以C速度随机采样或不以C速度替换。抓捕吗? 它与Numpy 1. 1.7是新的!

您已经使用 O( N=R*C) 内存, 所以您最好使用 O( N) 内存来替换您的代名词。 复制所有元素, 并随机排序它们, 就像您对单维案例所做的那样 。 如果您要访问每个元素, 这仅仅是合理的事情, 您认为这是您的情况 。

(用于记录: 否则, 记忆不是一个坏问题, 因为您只需要“ 记住” 之前的位置。 这样您就可以保留您已经访问过的指数列表。 如果您真的计划访问每个元素, 这样做是不好的, 因为拒绝抽样如果执行一个不断增长的黑名单, 执行时间会很长 。 ( 您也可以用一个越来越小的白名单来实施它, 这相当于第一个解决方案 。) < / em > 。 () < /em >

您已经说过, 您的测试对您网格中的大多数单元格都可能失败。 如果是这样的话, 随机抽样检查单元格可能不是个好主意, 因为您将很难追踪您已经检查过的单元格, 而没有使用很多内存 。

相反,你最好把测试应用到整个网格中, 从通过该网格的人中选择一个随机元素。

此函数返回一个通过测试的随机元素( 如果全部失败, 则无) 。 它使用很少的内存 。

def findRandomElementThatPasses(iterable, testFunc):
    value = None
    passed = 0

    for element in iterable:
        if testFunc(element):
            passed += 1
            if random.random() > 1.0/passed:
                value = element

    return value

你用类似的名字称呼它:

e = findRandomElementThatPasses((x,y) for x in xrange(X_SIZE)
                                      for y in xrange(Y_SIZE),
                                someFunctionTakingAnXYTuple)

如果您正在使用 Python 3, 请使用范围, 而不是 xrange 。

在perl你可以做这样的事情:

# how many you got and need
$xmax = 10000000;
$ymax = 10000000;
$sampleSize = 10000;

# build hash, dictionary in python
$cells = {};
$count = 0;
while($count < $sampleSize) {
  $x = rand($xmax);
  $y = rand($ymax);
  if(! $cells->{$x}->{$y}) {
    $cells->{$x}->{$y}++;
    $count++;
  }
}
# now grab the stuff
foreach ($x keys %{$cells}) {
  foreach ($y keys %{$cells->{$x}}) {
    getSample($x, $y);
  }
}

没有重复的, 相当随机的, 不太硬的记忆。





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...