51369


<https://github.com/romi1502/NMF-matlab/blob/master/python/NMF.py>

こちらのプログラムを参考にPython2.7.15にてbeta-divergenceのbeta=2の場合のプログラムを作成しています.

(正しくは,プログラムを作成中,これのbeta=2であることが分かった)

[code]

    W*= (np.dot((Lambda**(beta-2.0)*V), H.T) + eps)/(np.dot(Lambda**(beta-1), H.T) + eps);
    
[/code]

こちらのプログラムの式は正方行列でない行列に対してA**-2のようなことは出来ません.

これを実現する方法はNumPyにありますでしょうか?

回答,お導きのほどよろしくお願いいたします.

# 作成したプログラム

[code]

    def factorizeIS(A,dim=10,iteration_num=100,seed=0):
    dim_row,dim_column=shape(A)
    
    random.seed(seed)
    U=matrix([[random.random() for j in range(dim)] for i in range(dim_row)])
    V=matrix([[random.random() for j in range(dim_column)] for i in range(dim)])
    
    eps = spacing(1)
    
    for i in range(iteration_num):
        cost=ISdivergence(A,U.dot(V))
        if i%10==0: print cost
        if cost==0: break
    
        UV = U.dot(V)
        U= (dot((UV**(-2)*A), V.T) + eps)/(dot(UV**(-1), V.T) + eps)
    
        UV = dot(U,V) + eps;
        V*= (dot(U.T, UV**(-2)*A) + eps)/(dot(U.T, UV**(-1)) + eps)
    
    return normalize_V(U,V)
    
[/code]

このプログラムを,以下でテストしています

[code]

    def k6_3_IS():
    A = matrix([ [1,1,2,1,3] , [2,3,3,4,4] , [1,1,2,1,3] , [1,2,1,3,1] ])
    U,V = factorizeIS( A , dim=2 , iteration_num=1000 , seed=0 )
    print( "U*V" )
    print( U.dot(V) )
    
[/code]

エラー全文

[code]

    Traceback (most recent call last):
      File "k6.py", line 65, in <module>
        k6_3_IS()
      File "k6.py", line 42, in k6_3_IS
        U,V = factorizeIS( A , dim=2 , iteration_num=1000 , seed=0 )
      File ********\nmf.py", line 148, in factorizeIS
        U= (dot((UV**(-2)*A), V.T) + eps)/(dot(UV**(-1), V.T) + eps)
      File ********\numpy\matrixlib\defmatrix.py", line 228, in __pow__
        return matrix_power(self, other)
      File ********\numpy\linalg\linalg.py", line 602, in matrix_power
        _assertNdSquareness(a)
      File ********\numpy\linalg\linalg.py", line 215, in _assertNdSquareness
        raise LinAlgError('Last 2 dimensions of the array must be square')
    numpy.linalg.linalg.LinAlgError: Last 2 dimensions of the array must be square
    
[/code]


CC BY-SA 4.0
2018-12-19T10:06:46.070
51352
2018-12-20T02:41:30.553
2018-12-20T00:19:54.187
3060
31519
question
python numpy
pythonの行列計算における-2乗あるいは**について


これは `np.array` と `np.matrix` の差です。実際にどのような計算がしたいのかによって場合分けして回答を書いてみます。

元のプログラムは `np.array` である `Lambda` に対して `Lambda ** -2`
のように書いていますが、これは二次元配列の各要素に対してそれぞれ -2
乗しています。逆行列を求めているわけではありません。対して質問者さんのプログラムでは、`np.matrix` である `UV` に対して `UV **
-2` のように書いています。これは内部的にはまず `UV` の逆行列を求め、それを 2 乗しています。

NumPy の `np.linalg.inv`
では正方行列の逆を求めることはできますが、非正方行列はサポートしていません。非正方行列が渡されると今回のエラー `Last 2 dimensions of
the array must be square`
が出ます。非正方行列の逆というのは正確には存在しないので、たとえば[疑似逆行列](https://ja.wikipedia.org/wiki/%E6%93%AC%E4%BC%BC%E9%80%86%E8%A1%8C%E5%88%97)を使うなどすることになります。NumPy
だと `np.linalg.pinv` です。

この上で、解決法として以下のように場合分けができます。

  * 要素ごとにべき乗したい 
    * `np.array` を使う：そのまま `**` を使えば良い
    * `np.matrix` を使う：`np.power` を使えば良い
  * 行列として逆行列を求めたい 
    * `np.array` を使う：`np.linalg.inv` を使えば求まりますが、`np.matrix` に統一することも検討してみてください。
    * `np.matrix` を使う：正方行列に関しては `**` を使えば良い (ただし逆行列を直接求める際には誤差に注意。逆行列が直接欲しいのでないなら `np.linalg.solve` を使う)。非正方行列に関しては `np.linalg.pinv` の使用などを検討する。

ところで今回の NMF.py のもとになった MATLAB のプログラム [NMF.m](https://github.com/romi1502/NMF-
matlab/blob/b5a549af1c0deb57c239adba79d4d1d86f9e9f2a/NMF.m#L102)
では以下のように書かれています。

[code]

    W = W.* ((Lambda.^(beta-2).*V)*H' +eps)./((Lambda.^(beta-1))*H' + eps);
    
[/code]

ここで使われている演算子 `.^` は要素ごとにべき乗をするものです。というわけで元のアルゴリズムに忠実に実装しつつ `Lambda` を
`np.matrix` とするのであれば、

[code]

    np.power(Lambda, beta - 2)
    
[/code]

のように書くことになります。


CC BY-SA 4.0
2018-12-20T02:19:15.097
51369
2018-12-20T02:41:30.553
2018-12-20T02:41:30.553
19110
19110
51352
answer