やりたいこと
PythonのNumpyを用いて,行列計算を行いたいが,これらはnumpy同士の*, + , -, / numpy.dotなどを使用しないと計算速度がむしろ,落ちいてしまう.
しかし,実際には,行列の各要素に複雑な計算を代入していきたいことがよくある.その時のために,np.vetorizeなるものがあるが,それの使い方と速さを検証していきたい
## 今回の使う環境
import sys
import numpy as np
print("PythonのVerson:", sys.version)
print("NumpyのVersion:", np.__version__)
PythonのVerson: 3.5.3 |Anaconda custom (64-bit)| (default, Mar 6 2017, 12:15:08)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)]
NumpyのVersion: 1.15.2
np.vectoraizeの使い方
行列$A = (a){i, j}$に対して,$a{i, j} = a_{i, j} + 1$のような操作を行いたい場合は
A = A + 1などで十分である.
間違っても
for i in range(A.shape[0]):
for j in range(A.shape[1]):
A[i, j] = A[i, j] + 1
というようにしてはいけない.
しかし行列$A = (a)_{i, j}$に対して,以下のような複雑な操作を行いたい場合は,例えば,
for i in range(A.shape[0]):
for j in range(A.shape[1]):
while A[i, j] < 100:
A[i, j] *= 2
のような操作を行いたいとする
その場合は,
def f(x):
while x < 100:
x *= 2
return x
vf = np.vectorize(f)
A = np.random.random((1000, 1000))
そして,使い方は下のように,なる.書き方としてはとても簡潔であるように感じる.
ついでに,実行時間も計算してみる.
%timeit vf(A)
1 loop, best of 3: 1.49 s per loop
また,通常の書き方もやってみて,実行時間も計測してみる.
def loop():
A = np.random.random((1000, 1000))
for i in range(A.shape[0]):
for j in range(A.shape[1]):
A[i, j] = f(A[i, j])
%timeit loop()
1 loop, best of 3: 650 ms per loop
実行してみたら,普通に書いた方が実行時間が早かった!vectorizeの方が早いと思っていただけに少しショックである.
また理由がよくわからない.