https://numpy.org/doc/1.18/reference/generated/numpy.vectorize.html
このチュートリアルでは、vectorizeの実装は本質的にforループであると述べています。 しかし、私が知る限り、ベクトル化された関数は
SIMDなので、numpy.vectorizeの実装は本質的にforループであると言うのは正確ですか? trueの場合、C言語でループが実装されているという理由だけで、ベクトル化されていない関数よりも高速ですか?
よろしくお願いします。
はい。 Python(numpyを使用)やMATLAB™などのインタープリター型数値配列プログラミング言語のコンテキストでは、「ベクトル化」を使用して、インタープリター型プログラミング言語の明示的なループを、すべての処理を行う関数(または演算子)に置き換えることを指すことがよくあります。内部でロジックをループします。 numpyでは、 ufunc
このロジックを実装します。 これは、複数の入力を同時に計算するSIMD CPU命令を使用することを指す「ベクトル化」の使用とは関係ありません。ただし、両方とも同様のメタファーを使用します。これらは「スカラー」の対応物に似ていますが、複数の入力値に対して計算を実行します。 1回の呼び出しで。
numpy.vectorize()
を使用すると、通常、明示的なPython for
ループに比べて速度のメリットはそれほど多くありません。 その主なポイントは、Python関数をufunc
に変換することです。これは、すべてのブロードキャストセマンティクスを実装し、任意のサイズの入力を処理します。 「ベクトル化」されているPython関数は、各要素の生の値をPythonオブジェクトに変換して関数に渡すだけでなく、ほとんどの時間を費やします。 np.vectorize(lambda x, y: x + y)
が、ループ内とループの内容の両方でCであるufunc np.add
ほど高速であるとは期待できません。
詳細なご説明ありがとうございます。 しかし、明確にするために、例を挙げましょう。
import pandas as pd
import numpy as np
df = pd.DataFrame({'a': range(100000), 'b': range(1, 1000001)})
# method1
df.loc[:, 'c'] = df.apply(lambda x: x['a'] + x['b'], axis=1)
# method2
df.loc[:, 'c'] = np.vectorize(lambda x, y: x + y)(df['a'], df['b'])
# method3
df.loc[:, 'c'] = np.add(df['a'], df['b'])
だからあなたの説明で、私は推測します
メソッド| Cでのループ| Cのループコンテンツ| SIMDを使用する
-| -| -| -
1 | ×| ×| ××
2 | √| ×| ××
3 | √| √| √
正しい?
np.add
は、C doubleをPythonオブジェクトに変換したり、Python関数呼び出しのオーバーヘッドを回避したりするため、 np.vectorize(lambda x, y: x + y)
よりも高速です。 AVX2拡張機能があるかどうかによっては、SIMD命令も使用する可能性がありますが、それが高速である理由ではありません。
np.add
は、C doubleをPythonオブジェクトに変換したり、Python関数呼び出しのオーバーヘッドを回避したりするため、np.vectorize(lambda x, y: x + y)
よりも高速です。 AVX2拡張機能があるかどうかによっては、SIMD命令を使用することも可能
わかった。 ありがとう。
numbaのvectorize
を使用して、Pythonのオーバーヘッドなしで並列に動作するufuncを生成できます。
https://numba.pydata.org/numba-doc/latest/user/vectorize.html
最も参考になるコメント
はい。 Python(numpyを使用)やMATLAB™などのインタープリター型数値配列プログラミング言語のコンテキストでは、「ベクトル化」を使用して、インタープリター型プログラミング言語の明示的なループを、すべての処理を行う関数(または演算子)に置き換えることを指すことがよくあります。内部でロジックをループします。 numpyでは、
ufunc
このロジックを実装します。 これは、複数の入力を同時に計算するSIMD CPU命令を使用することを指す「ベクトル化」の使用とは関係ありません。ただし、両方とも同様のメタファーを使用します。これらは「スカラー」の対応物に似ていますが、複数の入力値に対して計算を実行します。 1回の呼び出しで。numpy.vectorize()
を使用すると、通常、明示的なPythonfor
ループに比べて速度のメリットはそれほど多くありません。 その主なポイントは、Python関数をufunc
に変換することです。これは、すべてのブロードキャストセマンティクスを実装し、任意のサイズの入力を処理します。 「ベクトル化」されているPython関数は、各要素の生の値をPythonオブジェクトに変換して関数に渡すだけでなく、ほとんどの時間を費やします。np.vectorize(lambda x, y: x + y)
が、ループ内とループの内容の両方でCであるufuncnp.add
ほど高速であるとは期待できません。