リストの生成と内包表記|Pythonにおける処理高速化をラフに考える #4

f:id:lib-arts:20201113203327j:plain

このシリーズではPythonの処理高速化についてラフに取り扱っています。
#3ではPandasとmapについて取り扱いました。

#4ではリストの生成と内包表記について取り扱います。
以下、目次になります。
1. 内包表記の構文とパフォーマンスの比較
2. timeitを用いた統計による比較
3. まとめ

 

1. 内包表記の構文とパフォーマンスの比較
1節では内包表記の構文と、パフォーマンスの比較について確認を行います。

[iの式 for i in リスト]

まず、内包表記の構文ですが、上記のようにリストを作成します。

[i*2 for i in range(10)]

たとえば、偶数を0から10個並べたリストだと上記のように実装できます。

大体の構文については把握できたと思うので、具体的に実行しつつパフォーマンスを比較してみましょう。

%%time

a1 = [i*2 for i in range(100000)]
print(a1[:10])

f:id:lib-arts:20201119211707p:plain

偶数のリストを上記のように内包表記を用いて作成を行っています。

次に、for文を用いてappendした実装について確認してみます。

%%time

a2 = list()
for i in range(100000):
    a2.append(i*2)
print(a1[:10]) 

f:id:lib-arts:20201119212054p:plain

内包表記の記載と同じ結果が得られていますが、処理時間としては約2倍となっていることが確認できます。

#2や#3でご紹介したmapについても合わせて比較してみましょう。

%%time

a3 = list(map(lambda x: x*2, range(100000)))
print(a3[:10])

f:id:lib-arts:20201119212328p:plain

上記のように、内包表記よりは遅く、appendを利用したパターンよりは高速であることが確認できます。

ここまで3通りのリストの作成について確認してきましたが、内包表記で作成した場合が一番パフォーマンスがよくなりそうです。とはいえ、処理時間が0.01秒くらいではあるので、誤差についても気になるところです。そこで、2節では%%timeではなく%%timeitを用いることで、処理の実行時間を統計的な視点で確認します。


2. timeitを用いた統計による比較
1節では内包表記を用いたリストの生成にあたっての処理速度を他の2つの方法と比較を行いましたが、2節では%%timeではなく%%timeitを用いることで統計的に実行時間を確認してみれればと思います。実行コードは基本的に同じで、%%timeを%%timeitに変えているだけなので、キャプチャだけのご紹介とします。

f:id:lib-arts:20201119212841p:plain

結果としては上記のように、1節で取り扱ったのとほぼ同様な結果ですが、若干appendを用いた実装が高速であることが読み取れます。1節で用いた%%timeでは1回の実行結果である一方で、2節で用いた%%timeitは複数回の実行結果の平均と標準偏差を計算しています。

f:id:lib-arts:20201119215127p:plain

runsやloopsについては上記のように引数を制御することも可能です。関連のドキュメントがいまいち読み取りづらく一旦詳しくまでは確認していませんが、rについて1を入れた場合は標準偏差が0になるということは確認できました。


3. まとめ
#4では内包表記を用いたリストの生成のパフォーマンスの確認と、timeitを用いた複数回実行の結果について確認しました。
続く#5以降では回帰分析の処理のパフォーマンスの確認を行います。