2016-07-14 12 views
2

コードとタイミングが更新されました。パフォーマンスnumpy.random.choice

私のコードで関数のパフォーマンスを向上させようとしています。私はランダムな要素でリストを生成する必要があります。しかし、リストの異なる部分は、異なるセットから取られた要素で満たされなければならない。コードの例を以下に示します。私はそれらのような数百万のリストを一度に1つずつ生成しなければなりません。

ファンクションfoo1が最も高速ですが、必要な機能を実行できません。それはパフォーマンスの参照のためです。関数foo2とfoo3は必要な処理を行いますが、foo1の処理時間はほぼ3倍です。

Python 2.7.9(デフォルト、2015年2月10日、03:29:19)。 darwinの[GCC 4.2.1互換Apple LLVM 6.0(clang-600.0.56)]。数が少ない。 バージョン '1.8.1'

import numpy 

import timeit 

_ops_1 = ["-123.456", "3.1416", "1", "2"] 
_ops_2 = ["ABC", "XYZ", 'A', 'B', 'C'] 

size = 10 

def foo1(): 
    return numpy.random.choice(_ops_1 + _ops_2, 5*size) 

def foo2(): 
    return list(numpy.concatenate((numpy.random.choice(_ops_1, 2*size), 
     numpy.random.choice(_ops_1 + _ops_2, size), 
     numpy.random.choice(_ops_2, 2*size)), 0)) 

def foo3(): 
    return numpy.random.choice(_ops_1, 2*size).tolist() + \ 
     numpy.random.choice(_ops_1 + _ops_2, size).tolist() + \ 
     numpy.random.choice(_ops_2, 2*size).tolist() 

### Suggested by Divakar 
def random_choice_replace_True(arr,size): 
    return numpy.take(arr,numpy.random.randint(0,len(arr),size)) 

def foo4(): 
    return random_choice_replace_True(_ops_1, 2*size).tolist() + \ 
     random_choice_replace_True(_ops_1 + _ops_2, size).tolist() + \ 
     random_choice_replace_True(_ops_2, 2*size).tolist() 

### 2nd suggestion by Divakar 
def random_choice_replace_True_idx(arr,size): 
    return numpy.array(arr)[numpy.random.randint(0,len(arr),size)] 

def foo5(): 
    return random_choice_replace_True_idx(_ops_1, 2*size).tolist() + \ 
     random_choice_replace_True_idx(_ops_1 + _ops_2, size).tolist() + \ 
     random_choice_replace_True_idx(_ops_2, 2*size).tolist() 

########### 

setup = '''import numpy 

_ops_1 = ["-123.456", "3.1416", "1", "2"] 
_ops_2 = ["ABC", "XYZ", 'A', 'B', 'C'] 

size = 10''' 

# As required, Number was increased to 10 million to get closer to actual timings 
timeit.timeit(foo1, setup=setup, number=10000000) 

timeit.timeit(foo2, setup=setup, number=10000000) 

timeit.timeit(foo3, setup=setup, number=10000000) 

timeit.timeit(foo4, setup=setup, number=10000000) 

timeit.timeit(foo5, setup=setup, number=10000000) 

私のマシン上で実行している時間があった。

timeit.timeit(foo1は、セットアップ=セットアップ、番号= 10000000) 235.22050380706787

timeit.timeit(foo2、setup = setup、number = 10000000) 760.1884841918945

timeit.timeit (foo3、セットアップ=セットアップ、数= 10000000) 560.77258586883545

timeit.timeit(foo4、セットアップ=セットアップ、数= 10000000) 388.69550228118896

timeit.timeit(foo5、セットアップ=セットアップ、数= 10000000 ) 252.32089233398438

これまでのところ、私はDivakarによる2番目の提案を受け取ります。これはかなり良いです。しかし、他の提案は大歓迎です!

+0

コードは1秒より速く、パフォーマンスを向上させる必要がありますか?実行時間が短いランタイムでは、現在実行中のシステム(バックグラウンドプロセス)に応じてランタイムが大きく変わります。私はあなたの問題が問題であるかどうかは分かりません。 – Ian

+0

実際の問題(何百万ものリストを生成する方法)を共有すると、最適化がより簡単になる可能性があります。 – ayhan

+0

必要に応じて、コードとタイミングを更新しました。 – user1348438

答えて

2

そのオプション引数replacenp.random.choiceは、入力アレイからTrue戻るランダムに選択された要素として設定されると、要素は繰り返すことができること。このような振る舞いをシミュレートするには、配列の長さをカバーするランダムなインデックスを作成し、選択のために配列にインデックスを付けます。すでにnumpyの配列での入力を扱っている場合は

def random_choice_replace_True(A,size): 
    return np.array(A)[np.random.randint(0,len(A),size)] 

、あなたは変換のためにnp.array(A)部分をスキップし、単にそこAを使用することができます - したがって、我々は、組み込みのこのような何かをすることをシミュレートすることができます。

+0

親愛なるDivakar。あなたの提案をありがとう。パフォーマンスが大幅に向上しました。それをさらに改善することは素晴らしいことです。 – user1348438

+0

@ user1348438 'numpy.take'をシンプルなインデックスに置き換えました。私が実行したいくつかのテストによれば、もう少しランタイムを削っているようです。それらをチェック!また、私はそれをさらに最適化できるとは思わない:) – Divakar

+0

親愛なるDivakar。提案していただきありがとうございます。今はずっと良いです!宜しくお願いします。 – user1348438