静かなる名辞

pythonとプログラミングのこと


【python】np.matrixの速度を測る

 numpyで行列演算を行う方法としては、普通のnumpy配列に行列演算系の関数を適用していく方法と、あまり知られていないがnp.matrix型やnp.mat型を使う方法がある。

 速度が違ったりするのだろうか? 仮に違うと困る(というか場面によって適切な方を選ぶ必要が生じてくる)ので、こんなコードを書いてみた。

import timeit

import numpy as np 

def main():
    a = np.random.random((100, 100))
    b = np.random.random((100, 100))
    a_m = np.matrix(a)
    b_m = np.matrix(b)
    a_mt = np.mat(a)
    b_mt = np.mat(b)
   
    print("add")
    print(np.allclose(a+b, np.array(a_m+b_m), np.array(a_mt+b_mt)))
    print(timeit.timeit(lambda : a+b, number=100000))
    print(timeit.timeit(lambda : a_m+b_m, number=10000))    
    print(timeit.timeit(lambda : a_mt+b_mt, number=10000))    

    print("mul")
    print(np.allclose(a*b, 
                      np.array(np.multiply(a_m, b_m)),
                      np.array(np.multiply(a_mt, b_mt))))
    print(timeit.timeit(lambda : a+b, number=10000))
    print(timeit.timeit(lambda : np.multiply(a_m, b_m), number=10000))        
    print(timeit.timeit(lambda : np.multiply(a_mt, b_mt), number=10000))        
    
    print("dot")
    print(np.allclose(np.dot(a,b),
                      np.array(a_m*b_m),
                      np.array(a_mt*b_mt)))
    print(timeit.timeit(lambda : np.dot(a,b), number=10000))
    print(timeit.timeit(lambda : a_m*b_m, number=10000))
    print(timeit.timeit(lambda : a_mt*b_mt, number=10000))

if __name__ == "__main__":
    main()

 100*100の行列の加算、要素積、行列積の計算を、np.arrayを使う方法とnp.matrix、np.matを使う方法で書いて、速度を比較している(ついでに計算結果が同じになるかも確認しているけど、これは念のためにやっているだけで、無論Trueになる)。

 結果は以下の通り。

add
True
0.6425584320095368
0.1307114879891742
0.1383463980164379
mul
True
0.07879749499261379
0.13494228100171313
0.1337542689871043
dot
True
0.8895792970142793
0.9789612090098672
1.0360321149928495

 変わるのか(困惑)。一瞬計測誤差かと思って何回も回したけど、傾向は変わらず。add, mulはnp.arrayの方が速い。dotはほとんど速度差はないようだが。

 何かの間違いだろうと思って検索したら、こんなスタックオーバーフローの質問が出てきてしまった。

python - numpy np.array versus np.matrix (performance) - Stack Overflow

 np.arrayの方が速い、と言われてしまっている。こうなると認めるしかないようだ。

 こうなると、それなりに速度重視の場面ではnp.matrixは使えないですねぇ。かといってnp.arrayで行列演算は苦行(Cとかフォートランでforループ回して書くのに比べればずっとマシだろうけど)。

 嫌な現実を見せられてしまった感がある。

 2018年11月15日追記:
 そうこうしているうちに、numpy 1.15.0から「no longer recommended」になってしまいました。

numpy.matrix — NumPy v1.15 Manual

 配列型をいろいろな関数と組み合わせて行列演算してくれということなのでしょう。