2012-11-11 76 views
3

是否有創建任意長numpy數組的有效方法,其中每個維度由n從長度列表中抽取的元素> = n?列表中的每個元素只能爲每個維度繪製一次。例如,如果我有列表l = ['cat', 'mescaline', 'popcorn'],我希望能夠,例如通過鍵入類似於np.random.pick_random(l, (3, 2), replace=false)之類的內容,創建一個數組array([['cat', 'popcorn'], ['cat', 'popcorn'], ['mescaline', 'cat']])使用列表中的隨機元素創建numpy數組

謝謝。

+0

污垢是否有毛病簡單明顯進口隨機; random.shuffle()? –

+0

我不知道爲什麼它必須是'numpy'?一般numpy是用於數值類型的計算,因此它的名字是數字python的縮寫,並且它支持其他類型...... pythons擁有'random.sample'可能更適合這個'[random.sample(['cat' ,'mescaline','爆米花'],number_of_members)的索引在xrange(number_of_arrays)]'... –

+0

@ samy-vilar原因是我想避免慢循環。我將用它來進行蒙特卡洛模擬,所以我需要相當大的數組。 – Aae

回答

7

即使世界幾個這樣的方式,每個人都有自己的優點/缺點,以下四個地方只是 從我的頭頂......

  • 蟒蛇自己random.sample ,雖然它可能不是最快...
  • numpy.random.permutation再簡單但它創建了我們必須切片的副本,ouch
  • numpy.random.shuffle因爲它洗牌到位,速度更快,但我們仍需要切片。
  • numpy.random.sample是最快的,但它只能在區間0到1,所以我們必須 正常化它,並將其轉換爲整數來獲得隨機指數,在最後我們還是 要切片,注正火到我們想要的大小不會產生均勻的隨機分佈。

這是一些基準。

import timeit 
from matplotlib import pyplot as plt 

setup = \ 
""" 
import numpy 
import random 

number_of_members = 20 
values = range(50) 
""" 

number_of_repetitions = 20 
array_sizes = (10, 200) 

python_random_times = [timeit.timeit(stmt = "[random.sample(values, number_of_members) for index in xrange({0})]".format(array_size), 
            setup = setup,      
            number = number_of_repetitions) 
             for array_size in xrange(*array_sizes)] 

numpy_permutation_times = [timeit.timeit(stmt = "[numpy.random.permutation(values)[:number_of_members] for index in xrange({0})]".format(array_size), 
           setup = setup, 
           number = number_of_repetitions) 
            for array_size in xrange(*array_sizes)] 

numpy_shuffle_times = [timeit.timeit(stmt = \ 
           """ 
           random_arrays = [] 
           for index in xrange({0}): 
            numpy.random.shuffle(values) 
            random_arrays.append(values[:number_of_members]) 
           """.format(array_size), 
           setup = setup, 
           number = number_of_repetitions) 
            for array_size in xrange(*array_sizes)]                  

numpy_sample_times = [timeit.timeit(stmt = \ 
            """ 
            values = numpy.asarray(values) 
            random_arrays = [values[indices][:number_of_members] 
               for indices in (numpy.random.sample(({0}, len(values))) * len(values)).astype(int)] 
            """.format(array_size), 
            setup = setup, 
            number = number_of_repetitions) 
             for array_size in xrange(*array_sizes)]                                    

line_0 = plt.plot(xrange(*array_sizes), 
          python_random_times, 
          color = 'black', 
          label = 'random.sample') 

line_1 = plt.plot(xrange(*array_sizes), 
     numpy_permutation_times, 
     color = 'red', 
     label = 'numpy.random.permutations' 
     ) 

line_2 = plt.plot(xrange(*array_sizes), 
        numpy_shuffle_times, 
        color = 'yellow', 
        label = 'numpy.shuffle') 

line_3 = plt.plot(xrange(*array_sizes), 
        numpy_sample_times, 
        color = 'green', 
        label = 'numpy.random.sample') 

plt.xlabel('Number of Arrays') 
plt.ylabel('Time in (s) for %i rep' % number_of_repetitions) 
plt.title('Different ways to sample.') 
plt.legend() 

plt.show() 

和結果:

enter image description here

所以看起來numpy.random.permutation是最差的,並不奇怪,蟒蛇自己random.sample拿着它自己的,所以它看起來像numpy.random.shuffle之間的緊密的賽程和numpy.random.samplenumpy.random.sample衝出來,所以要麼應該足夠,即使numpy.random.sample有更高的內存佔用我仍然喜歡它,因爲我真的不需要構建陣列我只需要隨機ind冰...

$ uname -a 
Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; root:xnu-1504.15.3~1/RELEASE_I386 i386 

$ python --version 
Python 2.6.1 

$ python -c "import numpy; print numpy.__version__" 
1.6.1 

UPDATE

可惜numpy.random.sample借鑑人口獨特的元素,所以你會得到repitation,所以才堅持洗牌一樣快。

更新2

如果你想保持numpy的範圍內充分利用它的一些內置的功能,就像這些值轉換爲numpy的陣列。

import numpy as np 
values = ['cat', 'popcorn', 'mescaline'] 
number_of_members = 2 
N = 1000000 
random_arrays = np.asarray([values] * N) 
_ = [np.random.shuffle(array) for array in random_arrays] 
subset = random_arrays[:, :number_of_members] 

注意到,N這裏是因爲這樣你會得到置換的重複次數,由排列我的意思是值的順序排列內不重複的值,因爲從根本上那裏有任何置換的有限數量相當大給出有限集合,如果只計算整個集合然後它的n !,如果只選擇k個元素它的n!/(n - k)!即使情況並非如此,這意味着我們的集合要大得多,但是依賴於隨機函數實現,我們仍然可能會重複,因爲shuffle/permutation/...等僅適用於當前集合,並且不知道的人口,這可能或可能不可接受,取決於你想要達到的目標,如果你想要一組獨特的排列,那麼你將生成該集合並對其進行二次抽樣。

+0

感謝您的努力。 numpy.shuffle方法的效率沒問題。但是,當對數組進行計算時,它並不能讓我從慢循環中解脫出來。例如,我想要做sum(random_arrays,axis = 1)。對不起,我很不清楚我在找什麼。 – Aae

+0

umm random_arrays.sum(axis = 1)? random_arrays應該是一個numpy類型。還要注意,隨機數可能會產生非唯一的排列,具體取決於您需要的隨機數組的數量,如果您真的想要獨特的排列,而不是手動生成它們並對其進行子樣本化,還請注意'numpy.random.choice '被添加到1.7我目前在1.6.1,http://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.random.choice.html我不確定它的性能需要測試它,但它可能會更慢,因爲它產生新的陣列... –

+0

也許我誤解了,但我做的方式產生一個'列表':https://pastee.org/d76bb 排列不應該是唯一的。 – Aae

6

這裏是一種使用numpy的的np.random.randint做到這一點:

In [68]: l = np.array(['cat', 'mescaline', 'popcorn']) 

In [69]: l[np.random.randint(len(l), size=(3,2))] 
Out[69]: 
array([['cat', 'popcorn'], 
     ['popcorn', 'popcorn'], 
     ['mescaline', 'cat']], 
     dtype='|S9') 

編輯:後的其他細節,每一個元素應該各行

中最多一次出現,這是不是很節省空間,做你需要更好的東西?

In [29]: l = np.array(['cat', 'mescaline', 'popcorn']) 

In [30]: array([np.random.choice(l, 3, replace=False) for i in xrange(5)]) 
Out[30]: 
array([['mescaline', 'popcorn', 'cat'], 
     ['mescaline', 'popcorn', 'cat'], 
     ['popcorn', 'mescaline', 'cat'], 
     ['mescaline', 'cat', 'popcorn'], 
     ['mescaline', 'cat', 'popcorn']], 
     dtype='|S9') 
+0

謝謝你。但是,我忘了提到一個細節。新數組不應該包含多次包含相同元素的維度(如果它未在列表中多次列出)。 – Aae

+0

@Aae編輯我的答案 – davidbrai

+0

更新提供了期望的結果,但效率不高。效率真的是我要求的。對不起,如果我不清楚。 – Aae

2
>>> import numpy 
>>> l = numpy.array(['cat', 'mescaline', 'popcorn']) 
>>> l[numpy.random.randint(0, len(l), (3, 2))] 
array([['popcorn', 'mescaline'], 
     ['mescaline', 'popcorn'], 
     ['cat', 'cat']], 
     dtype='|S9') 
+0

謝謝。但正如我在這裏對其他人說的那樣:我忘了提到一個細節。新數組不應該包含多次包含相同元素的維度(如果它未在列表中多次列出)。 – Aae