6

この質問はnumpyに焦点を当てています。

すべて同じ数の列を共有し、異なる数の行を持つ行列のセットがあります。それらを A、B、C、D などと呼び、それらの寸法を IaxK、IbxK、IcxK などとします。

私が望むのは、次のように定義された IaxIbxIc... tensor P を効率的に計算することです: P(ia,ib,ic,id,ie,...)=\sum_k A(ia,k)B(ib,k)C (ic,k)...

したがって、因子が 2 つある場合は、単純な行列積になります。

もちろん、次のような外積を使用してこれを「手で」計算できます。

    def parafac(factors,components=None):
        ndims = len(factors)
        ncomponents = factors[0].shape[1]
        total_result=array([])
        if components is None:
            components=range(ncomponents)

        for k in components:
            #for each component (to save memory)
            result = array([])
            for dim in range(ndims-1,-1,-1):
                #Augments model with next dimension
                current_dim_slice=[slice(None,None,None)]
                current_dim_slice.extend([None]*(ndims-dim-1))
                current_dim_slice.append(k)
                if result.size:
                    result = factors[dim].__getitem__(tuple(current_dim_slice))*result[None,...]
                else:
                    result = factors[dim].__getitem__(tuple(current_dim_slice))
            if total_result.size:
                total_result+=result
            else:
                total_result=result
        return total_result

それでも、組み込みのnumpy関数に依存するなど、計算効率がはるかに高いものが欲しいのですが、関連する関数が見つかりません。誰かが私を助けてくれますか?

乾杯、ありがとう

4

3 に答える 3

4

ご回答いただきありがとうございます。私はこれに一日を費やし、最終的に解決策を見つけたので、記録のためにここに投稿します

このソリューションには numpy 1.6 が必要で、強力なブードゥー魔法である einsum を利用します。

基本的に、同じ列数の A、B、C、および D 行列を含む factor=[A,B,C,D] がある場合、次を使用して parafac モデルを計算します。

import numpy
P=numpy.einsum('az,bz,cz,dz->abcd',A,B,C,D)

だから、一行!

一般的なケースでは、私はこれで終わります:

def parafac(factors):
    ndims = len(factors)
    request=''
    for temp_dim in range(ndims):
        request+=string.lowercase[temp_dim]+'z,'
    request=request[:-1]+'->'+string.lowercase[:ndims]
    return einsum(request,*factors)
于 2012-12-07T23:50:19.857 に答える
1

外積が変装したクロネッカー積であることを念頭に置いて、この単純な関数で問題を解決する必要があります。

def outer(vectors):
    shape=[v.shape[0] for v in vectors]
    return reduce(np.kron, vectors).reshape(shape)
def cp2Tensor(l,A):
    terms=[]    
    for r in xrange(A[0].shape[1]):
        term=l[r]*outer([A[n][:,r] for n in xrange(len(A))])
        terms.append(term)
    return sum(terms)

cp2Tensor は、実数のリストと行列のリストを取ります。

ハイメによるコメントの後に編集されました。

于 2012-12-07T21:52:21.323 に答える
0

わかりましたので、次のように動作します。最初に、何が起こっているかの具体的な例...

a = np.random.rand(5, 8)
b = np.random.rand(4, 8)
c = np.random.rand(3, 8)
ret = np.ones(5,4,3,8)
ret *= a.reshape(5,1,1,8)
ret *= b.reshape(1,4,1,8)
ret *= c.reshape(1,1,3,8)
ret = ret.sum(axis=-1)

そして充実の機能

def tensor(elems) :
    cols = elems[0].shape[-1]
    n_elems = len(elems)
    ret = np.ones(tuple([j.shape[0] for j in elems] + [cols]))
    for j,el in enumerate(elems) :
        ret *= el.reshape((1,) * j + (el.shape[0],) +
                          (1,) * (len(elems) - j - 1) + (cols,))
    return ret.sum(axis=-1)
于 2012-12-07T21:54:49.943 に答える