2

一般的な質問: ループ内で行う必要があると仮定して、効率の観点から、リストを作成するための望ましいスタイルはありますか? たとえば、整数のリストを作成するよりも、次のオプションのいずれかを使用することをお勧めします。

mylist = []

for x, y in mystuff:
  # x, y are strings that need to be
  # added sequentially to list
  mylist.extend([int(x), int(y)])

for x, y in mystuff:
  mylist.append(int(x))
  mylist.append(int(y))

それとも他に?関連する場合は、これに scipy/numpy を使用できます。ありがとう。

4

3 に答える 3

11

このようにマイクロ最適化する必要がある場合、何が最速かを知る唯一の方法はテストすることです。

短いバージョンは次のとおりです:appendは よりも高速でextend、Joran Beasley の提案itertools.chain.from_iterableはどちらよりもわずかに高速ですが、mapをリスト内包表記に置き換えた場合のみです。

そう:

import itertools
import timeit

def makestuff(count):
    for i in range(count):
        yield (i, i)

def f_extend(mystuff):
    mylist = []
    for x, y in mystuff:
        mylist.extend([int(x), int(y)])
    return mylist

def f_append(mystuff):
    mylist = []
    for x, y in mystuff:
        mylist.append(int(x))
        mylist.append(int(y))
    return mylist

def f_chainmap(mystuff):
    return list(map(int, itertools.chain(*mystuff)))

def f_chaincomp(mystuff):
    return [int(x) for x in itertools.chain(*mystuff)]

def f_chainfrommap(mystuff):
    return list(map(int, itertools.chain.from_iterable(mystuff)))

def f_chainfromcomp(mystuff):
    return [int(x) for x in itertools.chain.from_iterable(mystuff)]

def f_reducecompcomp(mystuff):
    return [int(x) for x in reduce(operator.iadd, (list(y) for y in mystuff), [])]

def f_reducecompmap(mystuff):
    return [int(x) for x in reduce(operator.iadd, map(list, mystuff), [])]


try:
    import numpy
    def f_numpy(mystuff):
        return numpy.array(mystuff).flatten().tolist()
    def f_numpy2(mystuff):
        return numpy.array(list(mystuff)).flatten().tolist()
except:
    pass

if __name__ == '__main__':
  import sys
  main = sys.modules['__main__']
  count = int(sys.argv[1]) if len(sys.argv) > 1 else 10000
  for f in dir(main):
    if f.startswith('f_'):
      func = getattr(main, f)
      mystuff = makestuff(count)
      testfunc = lambda: func(mystuff)
      print('{}: {}'.format(f, timeit.timeit(testfunc, number=count)))

Python 2 についてはmap、extra なしのバージョンを試してみたところ、listわずかに高速になりましたが、まだほとんど競争力がありませんでした。もちろん、Python 3 の場合はlistが必要です。

ここに私のタイミングがあります:

$ python testlister.py 1000000
f_append: 1.34638285637
f_chaincomp: 2.12710499763
f_chainfromcomp: 1.20806899071
f_chainfrommap: 2.77231812477
f_chainmap: 3.67478609085
f_extend: 1.38338398933
f_numpy: 5.52979397774
f_numpy2: 7.5826470852
f_reducecompcomp: 2.17834687233
f_reducecompmap: 3.16517782211

$ python3 ./testlister.py 1000000
f_append: 0.9949617639649659
f_chaincomp: 2.0521950440015644
f_chainfromcomp: 0.9724521590862423
f_chainfrommap: 2.5558998831082135
f_chainmap: 3.5766013460233808
f_extend: 1.149905970087275
f_reducecompcomp: 2.2112889911513776
f_reducecompmap: 1.9317334480583668

pythonは Apple の標準の Python 2.7.2 でpython3あり、python.org 3.3.0 はどちらも 64 ビットで、両方とも OS X 10.8.2 で、2012 年半ばの MacBook Pro (2.2GHz i7 および 4GB) に搭載されています。

POSIX プラットフォームで 32 ビットの Python を使用している場合、それほど遠くない過去のどこかで、反復子が最適化されitertools、64 ビットのビルドで多くのことが高速化されたように見えることに気付きました。 、しかし32ビットでは遅くなりました。appendしたがって、その場合はそれが勝つかもしれません。(いつものように、実際に最適化したいプラットフォームでテストしてください。)

Ashwini Chaudharyは Python での浅いリストのフラット化にリンクし、さらにPython 連想リストで要素を効率的に検索することにリンクしました。私の結果と彼らの結果の違いの一部は、2.6.0 と 2.7.2/3.3.0 の間の反復子の改善にあると思いますが、大きな要素ではなく 2 要素要素を明示的に使用しているという事実は、おそらくさらに重要です。 .

また、回答の少なくとも 1 つがreduce最速であると主張しました。元の投稿のreduce実装はすべて非常に遅いですが、より高速なバージョンを思いつくことができました。彼らはまだappendまたはchain.from_iterableと競争力がありませんが、正しい範囲にいます.

f_numpy関数は heltonbiker の実装です。mystuffは 2D イテレータであるため、これは実際にはイテレータをラップする 0D 配列を生成するだけなので、できるnumpyことはオーバーヘッドを追加することだけです。イテレータの 1D 配列を生成する実装を考え出すことができましたが、それはさらに遅くなりました。現在でnumpyは、オーバーヘッドを N 倍の頻度で追加することしかできないためです。list整数の 2D 配列を取得できる唯一の方法は、 のように最初に呼び出すことでしたf_numpy2。これにより、処理がさらに遅くなりました。(公平を期すためlistに、他の関数にエクストラを投げると速度も低下しましたが、 の場合ほど悪くはありませんでしたnumpy。)

ただし、ここで空白にしている可能性は十分にあり、ここには合理的な使用方法がありnumpyます。もちろん、トップ レベルmystuffまたは の各要素mystuffが alistまたは atupleであると確信できる場合は、より良いものを作成できます。また、アプリを再設計して、numpy.arrayシーケンスの一般的なシーケンスではなく、最初に 2D を使用できる場合。 、それはまったく別の話になります。しかし、シーケンスの一般的な 2D 反復があるだけの場合、このユース ケースにはあまり適していないようです。

于 2012-12-22T01:12:32.537 に答える