😍
1000倍の速度差が出てしまうコードの違い - Python PandasとJulia Dataframesの例
Python Pandasを使われている方々にとってみれば既に知っている方法だとは思いますが,効率のいい反復処理のやり方が紹介されていたのをたまたまみつけたので,同じことをJuliaでも試してみてPython Pandasの一番速い方法と比べてみました。
元記事はこちらです。Python Pandasのみの結果です。
ここで紹介されていたのは2つの列(src_bytes, dst_bytes)を加算する速度がやり方によって大きく変わることです。
- Iterrows
- For loop with .loc or .iloc
- Apply
- Itertuples
- List comprehensions
- Pandas vectorization
- NumPy vectorization
既にご存知の方も多いと思いますが、私の環境で(Mac mini M1 8GB, Python 3.9.7, Pandas 1.4.1)記事同様に7つの方法をやってみました。解説は元記事でされているので詳細は省いてコードと結果だけを表示します。
Python Pandas
今回使用するデータ
import pandas as pd
import numpy as np
df = pd.read_csv('https://raw.githubusercontent.com/mlabonne/how-to-data-science/main/data/nslkdd_test.txt')
Iterrows
%%timeit -n 10
total = []
for index, row in df.iterrows():
total.append(row['src_bytes'] + row['dst_bytes'])
For loop with .loc
%%timeit -n 10
total = []
for index in range(len(df)):
total.append(df['src_bytes'].loc[index] + df['dst_bytes'].loc[index])
Apply
%%timeit -n 10
df.apply(lambda row: row['src_bytes'] + row['dst_bytes'], axis=1).to_list()
Itertuples
%%timeit -n 10
total = []
for row in df.itertuples():
total.append(row[5] + row[6])
List comprehension
%%timeit -n 100
[src + dst for src, dst in zip(df['src_bytes'], df['dst_bytes'])]
Pandas vectorization
%%timeit -n 1000
(df['src_bytes'] + df['dst_bytes']).to_list()
NumPy vectorization
%%timeit -n 1000
(df['src_bytes'].to_numpy() + df['dst_bytes'].to_numpy()).tolist()
元記事にも書いてありますが、私の環境でも442msが433μsと1000倍も短縮されました。結論から言えば、List Comprehensionを使うようにし、出来るならVecotrization(ベクトル化)しろって事ですね。
Julia DataFrames
ふと同じことをJuliaでやったらどうなるかと思い試してみました。同じ環境(Mac mini M1 8GB, Julia 1.6.5, DataFrames 1.3.2)で同じデータでの比較です。
using DataFrames
using CSV
using HTTP
using BenchmarkTools
url = "https://raw.githubusercontent.com/mlabonne/how-to-data-science/main/data/nslkdd_test.txt"
df = CSV.File(HTTP.get(url).body) |> DataFrame
Eachrow (= iterrows)
total=[]
@benchmark for row in eachrow(df)
push!(total, row["src_bytes"].+row["dst_bytes"])
end
中央値をとれば22msです
List comprehension
@benchmark [(src+dst) for (src, dst) in zip(df[!,"src_bytes"],df[!,"dst_bytes"])]
Julia way
@benchmark [df[!,"src_bytes"]+df[!,"dst_bytes"]]
最終的に22msから8.9μsまで1000倍以上短縮されました。
Julia DataFramesでもPython Pandasでも、やり方次第で1000倍も違うとは、本当に知っておかないともったいないですね
まとめ
言語 | 方法 | 時間 |
---|---|---|
Python | Iterrows | 442 ms |
Python | For loop with .loc or .iloc | 217 ms |
Python | Apply | 163 ms |
Python | Itertuples | 64.4 ms |
Python | List comprehension | 3.72 ms |
Python | Pandas vectorization | 466 μs |
Python | NumPy vectorization | 433 μs |
Julia | Eachrow | 22.6 ms |
Julia | List comprehension | 13.1 μs |
Julia | Julia Dataframe | 8.9 μs |
Discussion