2011-01-16 4 views
3

入力リストには10​​0万を超える数字を使用できます。小さな「繰り返し」を使って次のコードを実行すると、その罰金がかかります。Python 3.1 - 大きなリストのサンプリング中のメモリエラー

def sample(x): 
    length = 1000000 
    new_array = random.sample((list(x)),length) 
    return (new_array) 

def repeat_sample(x):  
    i = 0 
    repeats = 100 
    list_of_samples = [] 
    for i in range(repeats): 
     list_of_samples.append(sample(x)) 
    return(list_of_samples) 

repeat_sample(large_array) 

しかしながら、例えば上記100のような高反復を使用して、MemoryErrorもたらします。トレースバックは以下の通りです。

Traceback (most recent call last): 
    File "C:\Python31\rnd.py", line 221, in <module> 
    STORED_REPEAT_SAMPLE = repeat_sample(STORED_ARRAY) 
    File "C:\Python31\rnd.py", line 129, in repeat_sample 
    list_of_samples.append(sample(x)) 
    File "C:\Python31\rnd.py", line 121, in sample 
    new_array = random.sample((list(x)),length) 
    File "C:\Python31\lib\random.py", line 309, in sample 
    result = [None] * k 
MemoryError 

私はメモリが不足していると想定しています。私はこの問題を回避する方法を知らない。

ありがとうございました!

+0

をより多くのメモリを取得しますか? – SilentGhost

+0

アルゴリズムを変更しますか?どのサンプルが使用されていますか?それぞれのサンプルの後で、ビットで少しずつ行うことはできませんか? – TryPyPy

+0

システムを再構成して仮想メモリを増やすことができます。これは通常、ハードディスクの空き容量が増えることを意味します。 – martineau

答えて

5

のは、あなたが各サンプルに行う処理は、その平均値を算出しているとしましょう。

def mean(samplelists): 
    means = [] 
    n = float(len(samplelists[0])) 
    for sample in samplelists: 
     mean = sum(sample)/n 
     means.append(mean) 
    return means 

calc_means(repeat_sample(large_array)) 

これは、メモリ内のすべてのリストを保持して汗をかくようにします。

def mean(sample, n): 
    n = float(n) 
    mean = sum(sample)/n 
    return mean 

def sample(x): 
    length = 1000000 
    new_array = random.sample(x, length) 
    return new_array 

def repeat_means(x):  
    repeats = 100 
    list_of_means = [] 
    for i in range(repeats): 
     list_of_means.append(mean(sample(x))) 
    return list_of_means  

repeat_means(large_array) 

をしかし、それはあなたが唯一のこれまでの結果のリストを構築してそれをすべて行うことができます...まだ十分ではありません:あなたはこのように、それははるかに軽く得ることができます

import random 

def sampling_mean(population, k, times): 
    # Part of this is lifted straight from random.py 
    _int = int 
    _random = random.random 

    n = len(population) 
    kf = float(k) 
    result = [] 

    if not 0 <= k <= n: 
     raise ValueError, "sample larger than population" 

    for t in range(times): 
     selected = set() 
     sum_ = 0 
     selected_add = selected.add 

     for i in xrange(k): 
      j = _int(_random() * n) 
      while j in selected: 
       j = _int(_random() * n) 
      selected_add(j) 
      sum_ += population[j] 

     mean = sum_/kf 
     result.append(mean) 
    return result 

sampling_mean(x, 1000000, 100) 

今、あなたのことができますアルゴリズムはこのように合理化されますか?

+0

これは完璧です。はい、私はそのような計算を実行するために作成していました。有難うございます! – jimy

0

あなたがすることができる唯一の改善はするようにコードを変更することです:それはあなたが現実の世界では、任意の長さのリストを作成することができないこと、しかし、事実は変わりません

list_of_samples = [random.sample(x, length) for _ in range(repeats)] 

4

2つの答え:

  1. あなたは古いマシンを使用している場合を除き、それはあなたが実際にメモリ不足とは考えにくいです。 MemoryErrorは、おそらく32ビットのPythonビルドを使用しており、2GB以上のメモリを割り当てることができないためです。

  2. あなたのアプローチは間違っています。サンプルのリストを作成する代わりに、ランダムサンプルジェネレーターを使用する必要があります。

+0

ああ32ビットについて見ています。乾杯。 – jimy

0

アレイオブジェクトhttp://docs.python.org/py3k/library/array.htmlを使用できます。それはリストよりもはるかにメモリ有効にする必要がありますが、おそらく少し使用することは困難です。私のコメントに拡大

1

random.sampleの発電機のバージョンは()も役立つだろう:

from random import random 
from math import ceil as _ceil, log as _log 

def xsample(population, k): 
    """A generator version of random.sample""" 
    n = len(population) 
    if not 0 <= k <= n: 
     raise ValueError("sample larger than population") 
    _int = int 
    setsize = 21  # size of a small set minus size of an empty list 
    if k > 5: 
     setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets 
    if n <= setsize or hasattr(population, "keys"): 
     # An n-length list is smaller than a k-length set, or this is a 
     # mapping type so the other algorithm wouldn't work. 
     pool = list(population) 
     for i in range(k):   # invariant: non-selected at [0,n-i) 
      j = _int(random() * (n-i)) 
      yield pool[j] 
      pool[j] = pool[n-i-1] # move non-selected item into vacancy 
    else: 
     try: 
      selected = set() 
      selected_add = selected.add 
      for i in range(k): 
       j = _int(random() * n) 
       while j in selected: 
        j = _int(random() * n) 
       selected_add(j) 
       yield population[j] 
     except (TypeError, KeyError): # handle (at least) sets 
      if isinstance(population, list): 
       raise 
      for x in sample(tuple(population), k): 
       yield x 
+0

OPはpy3kを使用しています。 – SilentGhost

+0

ああ、申し訳ありません、修正されました。 –

関連する問題