3

各次元が長さ >= nのリストから引き出されたn 個の要素で構成される、任意の長い numpy 配列を作成する効率的な方法はありますか? リスト内の各要素は、次元ごとに 1 回だけ描画できます。

たとえば、 list がある場合、たとえば のようなものを入力して、 array を作成l = ['cat', 'mescaline', 'popcorn']できるようにしたいと考えています。np.random.pick_random(l, (3, 2), replace=false)array([['cat', 'popcorn'], ['cat', 'popcorn'], ['mescaline', 'cat']])

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

4

3 に答える 3

8

これを行うにはいくつかの方法があり、それぞれに長所と短所があります。次の 4 つは私の頭の上から...

  • pythons ownrandom.sampleは、最速ではないかもしれませんが、シンプルで組み込まれています...
  • numpy.random.permutationこれも単純ですが、スライスする必要があるコピーが作成されます。
  • numpy.random.shuffleその場でシャッフルするので高速ですが、それでもスライスする必要があります。
  • numpy.random.sampleが最速ですが、0 から 1 の間隔でしか機能しないため、正規化して int に変換し、ランダム インデックスを取得する必要があります。最後にスライスする必要があります。必要なサイズに正規化しても生成されないことに注意してください。一様ランダム分布。

ここにいくつかのベンチマークがあります。

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()

そして結果:

ここに画像の説明を入力

したがってnumpy.random.permutation、最悪のように見えますが、驚くことではありませんが、pythons自身がそれを保持しているため、エッジアウトとrandom.sampleの間の接近戦のように見えるため、メモリフットプリントが高くても、どちらでも十分です。本当に配列を構築する必要はありません。ランダムなインデックスが必要なだけです...numpy.random.shufflenumpy.random.samplenumpy.random.samplenumpy.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

アップデート

残念ながら、人口から一意の要素を引き出すnumpy.random.sampleことはできないため、繰り返しが発生するため、シャッフルに固執するだけでも同じくらい高速です。

更新 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)! これが当てはまらない場合でも、つまりセットがはるかに大きかった場合でも、シャッフル/順列/...などは現在のセットでのみ機能し、わからないため、ランダム関数の実装によっては繰り返しが発生する可能性がありますこれは、何を達成しようとしているかによって異なります。一意の順列のセットが必要な場合は、そのセットを生成してサブサンプリングします。

于 2012-11-12T23:51:48.817 に答える
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')

編集:各要素が各行に最大1回表示される必要があるという追加の詳細の後

これはあまりスペース効率が良くありません。もっと良いものが必要ですか?

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')
于 2012-11-11T21:06:52.057 に答える
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')
于 2012-11-11T21:07:00.853 に答える