2017-10-15 58 views
-1

我想從itertools.product的結果構建一個numpy數組。我的第一種方法是簡單的:從itertools構建一個大的numpy數組產品

from itertools import product 
import numpy as np 

max_init = 6 
init_values = range(1, max_init + 1) 
repetitions = 12 

result = np.array(list(product(init_values, repeat=repetitions))) 

此代碼可以很好地用於「小」 repetitions(如< = 4),但與「大」的值(> = 12)它完全豬存儲器和崩潰。我認爲構建這個列表就是吃所有RAM的東西,所以我搜索瞭如何直接使用數組。我發現Numpy equivalent of itertools.productUsing numpy to build an array of all combinations of two arrays

所以,我測試了以下選擇:

備選#1:

results = np.empty((max_init**repetitions, repetitions)) 
for i, row in enumerate(product(init_values, repeat=repetitions)): 
    result[:][i] = row 

備選#2:

init_values_args = [init_values] * repetitions 
results = np.array(np.meshgrid(*init_values_args)).T.reshape(-1, repetitions) 

備選#3:

results = np.indices([sides] * num_dice).reshape(num_dice, -1).T + 1 

#1是非常緩慢的。我沒有足夠的耐心讓它完成(在2017年MacBook Pro上處理幾分鐘後)。 #2 and #3直到python解釋器崩潰,像最初的方法一樣,吃掉所有的內存。

之後,我認爲我可以以不同的方式表達相同的信息,這對我仍然有用:一個dict其中鍵將是所有可能的(排序的)組合,並且值將是這些組合。所以,我想:

替代#4:

from collections import Counter 

def sorted_product(iterable, repeat=1): 
    for el in product(iterable, repeat=repeat): 
     yield tuple(sorted(el)) 

def count_product(repetitions=1, max_init=6): 
    init_values = range(1, max_init + 1) 
    sp = sorted_product(init_values, repeat=repetitions) 
    counted_sp = Counter(sp) 
    return np.array(list(counted_sp.values())), \ 
     np.array(list(counted_sp.keys())) 

cnt, values = count(repetitions=repetitions, max_init=max_init) 

而行counted_sp = Counter(sp),從而觸發得到發電機的所有值,也就是我的需要太慢(也花了好幾分鐘,我取消了)。

是否有另一種方式來生成相同的數據(或包含相同信息的不同數據結構),但沒有提到的太慢或使用太多內存的缺點? PS:我測試了以上所有的實現對我的測試與一個小的repetitions,並通過了所有的測試,所以他們給出一致的結果。


我希望編輯這個問題是擴展它的最好方法。否則,讓我知道,我會在我應該的地方編輯帖子。

在閱讀下面的前兩個答案並思考它之後,我同意我從錯誤的角度接近問題。我不應該用「暴力」的方法來使用概率,而應該使用它。

我的意圖是,稍後,對於每個組合: - 計算有多少個值低於閾值X. - 計算有多少值等於或超過閾值X並低於閾值Y. - 計算有多少值超過閾值Y. 並對具有相同計數的組合進行分組。

作爲說明性實例: 如果我輥6下側的12個骰子,什麼是具有M個骰子具有值< 3,N骰子具有值> = 3和< 4,和P骰子具有值的概率> 5,所有可能的M,N和P組合?

所以,我認爲我會在幾天內完成這個問題,而我將採用這種新方法。感謝您的所有反饋和您的時間!

+0

可能想看看這個:https://stackoverflow.com/a/11146645/4909087 –

+2

爲什麼你想這樣做?假設你可以成功創建np.array,你會怎麼做? –

回答

2

list(product(range(1,7), repeats=12))所做的數字元組是6 ** 12,2176,782,336。無論是對於大多數計算機來說可能太大的列表或數組。

In [119]: len(list(product(range(1,7),repeat=12))) 
.... 
MemoryError: 

試圖讓該大小直接的數組:

In [129]: A = np.ones((6**12,12),int) 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-129-e833a9e859e0> in <module>() 
----> 1 A = np.ones((6**12,12),int) 

/usr/local/lib/python3.5/dist-packages/numpy/core/numeric.py in ones(shape, dtype, order) 
    190 
    191  """ 
--> 192  a = empty(shape, dtype, order) 
    193  multiarray.copyto(a, 1, casting='unsafe') 
    194  return a 

ValueError: Maximum allowed dimension exceeded 

陣列存儲器的大小,每個項目

In [130]: 4*12*6**12 
Out[130]: 104,485,552,128 

100GB≠4個字節

爲什麼你需要生成7個數字的2B組合?


因此,與您的櫃檯從36減少項目

In [138]: sp = sorted_product(range(1,7), 2) 
In [139]: counter=Counter(sp) 
In [140]: counter 
Out[140]: 
Counter({(1, 1): 1, 
     (1, 2): 2, 
     (1, 3): 2, 
     (1, 4): 2, 
     (1, 5): 2, 
     (1, 6): 2, 
     (2, 2): 1, 
     (2, 3): 2, 
     (2, 4): 2, 
     (2, 5): 2, 
     (2, 6): 2, 
     (3, 3): 1, 
     (3, 4): 2, 
     (3, 5): 2, 
     (3, 6): 2, 
     (4, 4): 1, 
     (4, 5): 2, 
     (4, 6): 2, 
     (5, 5): 1, 
     (5, 6): 2, 
     (6, 6): 1}) 

數21(2重複)。把它推廣到更多的重複(組合?排列?)應該不難,它仍然會推動時間和/或內存邊界。使用mgrid


一個變種上meshgrid

In [175]: n=7; A=np.mgrid[[slice(1,7)]*n].reshape(n,-1).T 
In [176]: A.shape 
Out[176]: (279936, 7) 
In [177]: B=np.array(list(product(range(1,7),repeat=7))) 
In [178]: B.shape 
Out[178]: (279936, 7) 
In [179]: A[:10] 
Out[179]: 
array([[1, 1, 1, 1, 1, 1, 1], 
     [1, 1, 1, 1, 1, 1, 2], 
     [1, 1, 1, 1, 1, 1, 3], 
     [1, 1, 1, 1, 1, 1, 4], 
     [1, 1, 1, 1, 1, 1, 5], 
     [1, 1, 1, 1, 1, 1, 6], 
     [1, 1, 1, 1, 1, 2, 1], 
     [1, 1, 1, 1, 1, 2, 2], 
     [1, 1, 1, 1, 1, 2, 3], 
     [1, 1, 1, 1, 1, 2, 4]]) 
In [180]: B[:10] 
Out[180]: 
array([[1, 1, 1, 1, 1, 1, 1], 
     [1, 1, 1, 1, 1, 1, 2], 
     [1, 1, 1, 1, 1, 1, 3], 
     [1, 1, 1, 1, 1, 1, 4], 
     [1, 1, 1, 1, 1, 1, 5], 
     [1, 1, 1, 1, 1, 1, 6], 
     [1, 1, 1, 1, 1, 2, 1], 
     [1, 1, 1, 1, 1, 2, 2], 
     [1, 1, 1, 1, 1, 2, 3], 
     [1, 1, 1, 1, 1, 2, 4]]) 
In [181]: np.allclose(A,B) 

mgrid是相當快一點:

In [182]: timeit B=np.array(list(product(range(1,7),repeat=7))) 
317 ms ± 3.58 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 
In [183]: timeit A=np.mgrid[[slice(1,7)]*n].reshape(n,-1).T 
13.9 ms ± 242 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 

但是,是的,它會具有相同的總內存使用和限制。

當n = 10,

ValueError: array is too big; `arr.size * arr.dtype.itemsize` is larger than the maximum possible size. 
0

正確的答案是:不。無論您想要對所有這些組合進行什麼操作,都要調整您的方法,以便一次生成一個並立即使用它們,而不必存儲它們,或者更好地找到一種方法在不檢查每個組合的情況下完成工作。您當前的解決方案適用於玩具問題,但不適用於較大的參數。解釋你在做什麼,也許這裏有人可以提供幫助。