pythonのforループは遅い?

pythonはデータの処理になにかと便利なので重宝していますが、ループ(for)の処理は一般的に遅いと言われています。(このためベクターで処理するのが良いらしい)

とはいえ、今まで実感としてはなかったんですが、ちょっとした処理をforループとnumpyで比較してみたら、桁違いだったのでメモにまとめます。

処理内容

処理したのは年間の風データ。1時間毎の風向(角度)のデータです。

  • 風向(0~360°)
  • 1時間単位で1年分(8760h)

これを16方位、22.5°刻みの角度へ集約します。

forループ

まず、forループを使って次のように処理しました。8760h×16方位のループです。

theta = 360/16
for i in range(8760):          
    for j in range(16):
        angle = theta*j
        if(j==0):
            if ((360 - theta/2 < winddirs[i]) or (winddirs[i] <= angle + theta/2)):
                winddirs[i] = 0.0
                break
        else:
            if ((angle - theta/2 < winddirs[i]) and (winddirs[i] <= angle + theta/2)):
                winddirs[i] = angle
                break

ループ処理としてありがちなパターンですが、これがひたすら遅い。恐ろしく遅い。処理時間は約240秒。処理がなかなか終わらないのでフリーズしたのかと思うほどです。

2021/11/10追記 

いま同じようなコードを書いたら0.5秒ぐらいで終了してしまって、以前の240秒は何だったんだろう?ってなっている。PCを更新しているので、その影響?それにしても処理速度が違いすぎるので何か間違えていたのかも?

ちなみに同じコードをNumpyに書き直すと計測不能なほど速い。やはりforループとNumpyの速度差は大きいのは確かなようです。

Numpy

そして、NumPyで書き直したのが次のコード。where()を使って8760h分の値をまとめて一気に条件判定して値を更新します。

theta = 360/16
for j in range(16):
    angle = theta*j
    if(j==0):
        min_angle = 360 - theta/2
        max_angle = theta/2
        winddirs = np.where((min_angle < winddirs)|(winddirs <= max_angle), 0.0, winddirs)
    else:
        min_angle = angle - theta/2
        max_angle = angle + theta/2                
        winddirs = np.where((min_angle < winddirs) & (winddirs <= max_angle), angle, winddirs) 

ステップ数はそれほど変わりませんが、こちらは約0.5秒、なんと500倍近い速度アップです。ループの処理が大幅に減った(16×8760hから16個)も効いているようですが、それにしてもベクトルをまとめて処理すると速い。

まとめ

ということで、一般に言われているようにループ処理が遅いのは確かなようです。

大量のデータはループを使わず、Numpyなどでまとめて処理すると高速に処理できます。

動作環境

以下の環境で動作を確認しています。

Windows10 Pro(64bit, 1809)
Python3.7.3

Pocket

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です