Pythonの高速化(パフォーマンスの最適化)

スポンサーリンク
スポンサーリンク

配列のループ(FOR文)

以下のようなデータがある前提です。

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.rand(100000).reshape(100000, 1))

print(df.tail())
#               0
# 99995  0.879119
# 99996  0.600798
# 99997  0.324799
# 99998  0.743424
# 99999  0.520695

普通にdf.iterrows()を使ってループする

%%time
a = 0
for index, row in df.iterrows():
    a += row[0]

print(a)
# 50045.80276582274

# CPU times: user 6.9 s, sys: 54.8 ms, total: 6.95 s
# Wall time: 7.11 s

df.valuesでNumPy配列でループする

%%time
a = 0
for val in df.values:
    a += val

print(a)
# [50045.80276582]

# CPU times: user 175 ms, sys: 5.27 ms, total: 180 ms
# Wall time: 187 ms

Pandasデータフレームに比べると、圧倒的な処理速度です。

df.valuesでNumPy配列でenumerateを使ってループする

%%time
a = 0

for index, val in enumerate(df.values):
    a += val

print(a)
# [50045.80276582]

# CPU times: user 176 ms, sys: 4.7 ms, total: 181 ms
# Wall time: 184 ms

enumerateを使っても、パフォーマンスの低下は見られませんでした。誤差の範囲で、逆に早くなっています。

結論

Pandasデータフレームのままループさせると異常に遅くなります。

Pandasのデータを利用する場合は、NumPy配列に変換してからループさせた方が格段に処理が早くなります。
enumerateを使ってindexを取得してもパフォーマンスは落ちませんでした。

ループで配列に値を追加

Pandasデータフレームにappendで要素を追加

%%time

df = pd.DataFrame()
for i in range(1,10000):
    df = df.append({0 : i}, ignore_index=True)

print(len(df))
print(df.head())
# 9999
#      0
# 0  1.0
# 1  2.0
# 2  3.0
# 3  4.0
# 4  5.0
# CPU times: user 13.8 s, sys: 104 ms, total: 13.9 s
# Wall time: 14 s

リスト型にappendで要素を追加

%%time

data = []

for i in range(1,10000):
    data.append(i)

print(len(data))
print(data[:5])
# 9999
# [1, 2, 3, 4, 5]
# CPU times: user 2.36 ms, sys: 356 µs, total: 2.71 ms
# Wall time: 3.18 ms

Pandasデータフレームに比べると、圧倒的な処理速度です。

二次元配列のリスト型にappendで要素を追加

%%time

data = [[]]

for i in range(1,10000):
    data.append([i])

print(len(data))
print(data[:5])
# 10000
# [[], [1], [2], [3], [4]]
# CPU times: user 4.86 ms, sys: 1.56 ms, total: 6.42 ms
# Wall time: 6.39 ms

一次元に比べて、倍ほどの処理時間を要していますが、Pandasデータフレームに比べるとやはり格段に早いです。

辞書型(dict)にupdateで要素を追加

%%time

data = {}

for i in range(1,10000):
    data.update({i : i})

print(len(data))
# 9999
# CPU times: user 5.76 ms, sys: 996 µs, total: 6.76 ms
# Wall time: 6.6 ms

二次元配列のリスト型とパフォーマンスはほとんど変わりません。

Numpyにappendで要素を追加

%%time

data = np.array([])

for i in range(1,10000):
    data = np.append(data, i)

print(len(data))
print(data[:5])
# 9999
# [1. 2. 3. 4. 5.]
# CPU times: user 111 ms, sys: 9.94 ms, total: 121 ms
# Wall time: 128 ms

リストや辞書型に比べると結構かかっていますが、Pandasデータフレームに比べるとやはり格段に早いです。

二次元のNumpyにappendで要素を追加

%%time

data = np.array([[1]])

for i in range(1,10000):
    data = np.append(data, [[i]], axis=0)

print(len(data))
print(data[:5])
# 10000
# [[1]
#  [1]
#  [2]
#  [3]
#  [4]]
# CPU times: user 91.4 ms, sys: 13.7 ms, total: 105 ms
# Wall time: 102 ms

何故か一次元より処理速度が早くなっています。誤差の範囲として、二次元配列でもパフォーマンスは変わりないということにしましょう。

結論

FOR文(ループ)と同じように、リスト型が圧倒的な早さを見せています。
辞書型(dict)はリスト型より倍ほど遅いですが、それでも他より格段に早いです。

処理速度の順位

  1. リスト型
  2. 辞書型(dict)
  3. Numpy
  4. Pandasデータフレーム*めちゃめちゃ遅いので使わない方がいいですね。

 

コメント

タイトルとURLをコピーしました