Python高速化実験~map関数とか~

はじめに

僕は一応Pythonが母語で,C言語はできないことはない,という設定で生きています.

Pythonは書きやすいですが,実行速度にかなり難がありますよね.
スピードが肝になってくるプログラムだとCで書き直さなければいけない局面がでてくるかと思います.
しかし,できればPythonで完結したいというのが本音.

Pythonの利点の「書きやすさ」というのは時に,やたら冗長なコードを書いてしまう原因にもなるかと思います.

Pythonの高速化手法はいろいろ紹介されていますが,自分でコード書いて試してみるのが一番かなと思い,
今回から数回をかけて実際に手を動かして,速度比較実験をしていきたいと思います.

別に体系的にまとめるつもりはないので,思いついたら順次記事にしていく予定です.

今回は,map関数系の処理速度について比較してみました.

実験内容

  • リストの各要素に対して同じ関数を適用
  • 関数の返り値を各要素とする配列を作成
  • float()関数で実験

つまり,あるリストの各要素を全部float型にする操作ってこと!!

さっそく思いつく限りの手を試す.

In [1]:
#純粋listだけでなく,numpy arrayも用いる
import numpy as np
In [2]:
#適当に用意
py_list = list(range(10**7)) #以下,「純粋list」と呼びます
np_list = np.arange(10**7) #以下,「numpy配列」と呼びます

#np_listというネーミングには突っ込まないで

純粋listに対し,list内包表記

In [3]:
%%time
hoge = [float(i) for i in py_list]
Wall time: 1.38 s

numpy配列に対し,list内包表記

In [4]:
%%time
hoge = [float(i) for i in np_list]
Wall time: 1.74 s

純粋listに対し,map関数

In [5]:
%%time
hoge = list(map(float, py_list))
Wall time: 1.18 s

numpy配列に対し,map関数

In [6]:
%%time
hoge = list(map(float, np_list))
Wall time: 1.47 s

numpy.frompyfunc()

任意の関数をnupmyのユニバーサル関数化する関数frompyfunc()を利用する.

引数は,(func=関数,nin=その関数の引数の数,nout=その関数の返り値の数)

詳しくはnumpy.frompyfunc — NumPy v1.15 Manual

In [7]:
%%time
f = np.frompyfunc(float, 1, 1)
hoge = f(np_list)
Wall time: 932 ms

numpy.vectorize()

frompyfuncと同様に,任意の関数をユニバーサル関数化することができる.

詳しくは,numpy.vectorize — NumPy v1.15 Manual

ドキュメントには,

The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop.

とある.
つまり,vectorize()はあくまでコードの利便性を高めるだけで,パフォーマンスは高めないよと.本質的にはfor文を呼んでいるだけらしい.

In [8]:
%%time
f = np.vectorize(float)
hoge = f(np_list)
Wall time: 1.31 s

まとめ

方法 実行時間(s) 順位
純粋listに対し,list内包表記 1.38 4
numpy配列に対し,list内包表記 1.74 6
純粋listに対し,map関数 1.18 2
numpy配列に対し,map関数 1.47 5
numpy.frompyfunc() 0.93 1
numpy.vectorize() 1.31 3
規模が小さいので,そこまで大きな差はでなかったが,いちおうnumpy.frompyfunc()を利用するもの一番高速という結果となった.

次点が純粋listに対するmap関数の適用であるので,単純な操作については一概にnumpyを使うのが良いとは言えないのかもしれない.

リストのサイズによる速度差については,python – Most efficient way to map function ver numpy array – Stack Overflow にまとめられている.

今回の実験は,あまり体系的になっていないので,今後より詳細に検討していくつもり.

書きやすいPythonだからこそ,各変数の型については常に意識しておくべきだと思った.

2