Environment
version | |
---|---|
OS | CentOS7 |
python | 3.8.1 |
pandas | 1.0.1 |
numpy | 1.18.1 |
概要
結論を一言でいうと、使いどころは微妙でした
pandasの並列演算をnumpy.frompyfunc()
で置き換えようとした時の記録です。
経緯
とある開発中、pandasで並列演算していた部分を他メソッドからも使い回して呼びたくなり、numpy.frompyfunc()
を使った。
ソースの変更内容を簡略化すると、こんな感じ。
import numpy as np
import pandas as pd
# 元々の処理 - pandasによる並列演算を使った処理
def intercomparison_between_dataframes_old(...):
# 略 ...
y_exceed_x_series = df1['x'] < df2['y']
return y_exceed_x_series
# 書き換え後 - frompyfuncによる処理
def intercomparison_between_dataframes_new(...):
y_exceed_x = np.frompyfunc(compare, 2, 1)
y_exceed_x_series = y_exceed_x(df1['x'], df2['y'])
retutn y_exceed_x_series
def compare(x, y):
return x < y
# ※注
# 書き換え前と書き換え後では、処理結果が若干異なる
#
intercomparison_between_dataframes_old(...)
0 False
1 False
2 False
dtype: bool <-
intercomparison_between_dataframes_new(...)
0 False
1 False
2 False
dtype: object <- 速いけど dtype が object になってた
こうすると何が嬉しいかというと、compare()
メソッドを呼び出せすことで、比較ロジックだけを使い回すことができる。
Series
同士の並列計算ではなく、1対1で比較したいこともあるのです(←当初の目的)
ほ、本当は引数が6個もある複雑な比較処理なんだからね!(>д<;)
速度を測ってみた
この処理変更によって速度が低下しないか心配だったので、念のため以下の記事の方法で速度測定してみた。
結果
old_dealtelapsed_time が元々の処理の処理時間
new_dealtelapsed_time が書き換え後処理の処理時間
「え、 pandasよりfrompyfuncの方が速い じゃん♪(^^*)ラッキー」
処理時間が約7分の1になりました。
想定外の収穫でした。
ちょっと気が早いですが、
「もう並列演算は全部 frompyfunc でいいんじゃないか....(`・д´・;)」
と思ってしまいました。
ところが...
更なる調査で分かったこと
処理結果を調べていて分かったことがあった。
frompyfuncに渡すメソッドの戻り値が2個(以上)の時、戻り値の型がタプル(tupple)になる。
たとえば今回の例でいえば、compare()
メソッドの戻り値が2個だったとしたら戻り値がこんな感じになる
>>> intercomparison_between_dataframes_new(...)
(0 True
1 False
2 True
3 False
4 False
...
1553 True
1554 True
1555 True
1556 False
1557 True
Length: 1558, dtype: object, 0 True
1 False
2 True
3 False
4 True
...
1553 True
1554 False
1555 False
1556 True
1557 False
Length: 1558, dtype: object) <- tupple かよぉ....
numpyのメソッドだから二次元のndarrayを返してくれると思ったのに...
frompyfunc()に渡すメソッドの戻り値が1個の時しか、速度改善は望めなさそう。
もし使うとしたら
- frompyfunc()に渡すメソッドの戻り値が1個ならそこそこ使えそう。
もしかしたら...
処理によっては速度に大差なかったり、逆にfrompyfunc
の方が遅いこともあるかもしれない。
とはいえ、結構な差がついているので、基本的にはfrompyfunc
の方が速そう。
実際に簡単な処理でも調査したら追記しようと思う。