2012-11-11 8 views
3

Есть ли эффективный способ создания произвольного длинного массива numpy, где каждый размер состоит из n элементов, составленных из списка длины> = n? Каждый элемент в списке можно нарисовать только один раз для каждого измерения.Создать массив numpy со случайными элементами из списка

Например, если у меня есть список l = ['cat', 'mescaline', 'popcorn'], я хочу, чтобы иметь возможность, например, набрав что-то вроде np.random.pick_random(l, (3, 2), replace=false), создать массив array([['cat', 'popcorn'], ['cat', 'popcorn'], ['mescaline', 'cat']]).

спасибо.

+0

Есть ли что-то не так с грязью простой и очевидный случайный импорт; random.shuffle()? –

+0

Интересно, почему это должно быть «numpy»? В общем, numpy для численного типа вычислений, поэтому его имя сокращается для числового python, если оно поддерживает другие типы ... pythons собственный 'random.sample' может быть лучше для этого' [random.sample (['cat' , 'mescaline', 'popcorn'], number_of_members) для индекса в xrange (number_of_arrays)] '... –

+0

@ samy-vilar Причина в том, что я хочу избежать медленных циклов. Я буду использовать это для моделирования в Монте-Карло, поэтому мне понадобятся довольно большие массивы. – Aae

ответ

7

Theres несколько способов сделать это, каждый из них имеет свои плюсы/минусы, следующие четыре, где только из верхней части моей головы ...

  • питонов собственного 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.sample с numpy.random.sample обрезкой, поэтому либо должно быть достаточно, хотя numpy.random.sample имеет более высокий объем памяти. Я по-прежнему предпочитаю его, так как мне действительно не нужно строить массивы. Мне просто нужен случайный индекс льды ...

$ 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, так что просто придерживаться перетасовать так же быстро.

UPDATE 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 здесь достаточно велик, как таковые вы собираетесь получить повторное число перестановок, перестановками я имею в виду порядок значений не повторяется значений в перестановке, так как принципиально Theres конечного числа перестановок на любом давая конечное множество, если просто вычислить целое множество, то его 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. Также обратите внимание, что shuffle может генерировать неповторимые перестановки в зависимости от количества случайных массивов, которые вам нужны, если вы действительно хотите уникальные перестановки, чем вам придется создавать их вручную и подпробовать их, также обратите внимание, что 'numpy.random.choice 'был добавлен в 1.7 Im в настоящее время на 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: EDIT

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

Смежные вопросы