2016-09-22 4 views
0

私はrandom.sampleを使用して、入力負荷に応じて非常に大きな範囲をサンプリングします。時には、サンプル自体が非常に大きく、リストであるため、多くのメモリを占有します。pythonはリストからリストの代わりにリスト生成器を返すためにinbuiltがあります。

アプリケーションが必ずしもリストのすべての値を使用するとは限りません。 random.sampleがリスト自体の代わりにリストジェネレータを返すことができれば嬉しいです。

今は大きな入力範囲を等しいサイズのバケットに分割するラッパーがあり、randintを使用して各n/sample_sizeバケットの乱数を選択します。

私の場合、入力は連続ですが、このラッパー関数を使ってrandom.sampleをジェネレータとしてシミュレートしましたが、最終的にいくつかの要素をスキップするため、この機能は本当に複製されません。

import random 

def sample(n, k): 
    """Generate random sorted k-sample of range(n).""" 
    for i in range(n): 
     if random.randrange(n - i) < k: 
      yield i 
      k -= 1 

番号を通過:あなたは(私はそれがランダムでなければならないか、並べ替えることができるかどうか尋ねていた)問題ではないため、これはオプションであるかもしれないとコメントしているので

import random 
def samplegen(start, end, sample_size): 
    bktlen = (end - start)/sample_size 
    for i in xrange(sample_size): #this skips the last modulo elements 
     st = start + (i * bktlen) 
     yield random.randrange(st, st + bktlen) 
+3

ジェネレータとして 'random.sample'を実行するには、すでに使用しているアイテムを追跡して、再度使用しないようにする必要があります。これは、リストを返すだけのメモリを使用します。 – kindall

+0

@kindallだから、入力範囲をバケットに分割し、各バケットから1つの番号だけを選択し、バケットの数はサンプルサイズに基づいています。私は入力がxrange(0,1000000)のような連続した数値であることを言及すべきでした – user881300

+0

@ user881300 'xrange(0、1000000)'の 'random.sample'はどのように問題になりますか?それは大きくありません。 –

答えて

2

各サンプルを確率で
numberOfNumbersStillNeeded/numberOfNumbersStillLeftで示します。

デモ: -

>>> for _ in range(5): 
     print(list(sample(100, 10))) 

[7, 16, 41, 50, 55, 56, 61, 76, 89, 96] 
[5, 13, 24, 28, 34, 35, 40, 64, 80, 95] 
[9, 18, 19, 36, 38, 39, 61, 73, 84, 85] 
[23, 24, 26, 28, 40, 53, 62, 76, 77, 91] 
[2, 12, 21, 41, 60, 68, 70, 72, 90, 91] 
1

なぜ、次のようなものではないセットseenだけ​​のサイズに必ずしも、kの機能に育つ:

import random 

def sample(population, k): 
    seen = set() 

    for _ in range(k): 
     element = random.randrange(population) 
     while element in seen: 
      element = random.randrange(population) 

     yield element 
     seen.add(element) 

for n in sample(1000000, 10): 
    print(n) 

別のアプローチかもしれませんオリジナルのバケツのデザインで作業することができますが、インデックス自体が無作為にサンプリングされた不均一なバケットを使用してください:

import random 

def samplegen(start, end, sample_size): 
    random_bucket_indices = random.sample(range(start, end), sample_size) 
    sorted_bucket_indices = sorted(random_bucket_indices) + [end + 1] 
    for index in random_bucket_indices: 
     yield random.randrange(index, sorted_bucket_indices[sorted_bucket_indices.index(index) + 1]) 
+0

'while要素が見られました:pass'は永遠に実行されます(実行されている場合)。私はあなたがそのループで 'element 'の割り当てを繰り返すと思います。 – Blckknght

+0

@cdlane @Blckknghtで述べた問題とは別に、 'random.sample'で生成されたリストが使用する' o(k) 'メモリを使用しますが、返された' list'は呼び出しが取得されてから長時間存在しますセットはすぐに清掃されます。 – user881300

+0

私は、このセットが、 'O(k)'ではないかもしれない 'O(生成された要素の数)'スペースを使用するので、これはまだ有効なアプローチ(実装が正しい場合)ほとんどのサンプルを反復することなく、早期に終了します。最悪の場合には 'O(k)'スペースを使いますが、それは 'random.sample'と同じなので大きな欠点ではありません。 – Blckknght

関連する問題