2016-08-23 2 views
3

Ich habe versucht, eine bestimmte gewichtete Summe zu vektorisieren, konnte aber nicht herausfinden, wie es geht. Ich habe unten ein einfaches minimales Arbeitsbeispiel erstellt. Ich nehme an, die Lösung beinhaltet entweder bsxfun oder reshape und kronecker Produkte, aber ich habe es immer noch nicht geschafft, es zum Laufen zu bringen.Dreifach gewichtete Summe

rng(1); 
N = 200; 
T1 = 5; 
T2 = 7; 
T3 = 10; 


A = rand(N,T1,T2,T3); 
w1 = rand(T1,1); 
w2 = rand(T2,1); 
w3 = rand(T3,1); 

B = zeros(N,1); 

for i = 1:N 
for j1=1:T1 
    for j2=1:T2 
    for j3=1:T3 
    B(i) = B(i) + w1(j1) * w2(j2) * w3(j3) * A(i,j1,j2,j3); 
    end 
    end 
end 
end 

A = B; 

Für den zweidimensionalen Fall gibt es eine intelligente Antwort here.

+0

brauchen Sie zu verallgemeinern? Wenn ja, würde ich Ihr N, T1, T2, T3 als Array umformulieren. –

+0

Ich wollte eigentlich nur den dreidimensionalen Fall. Aber die Verallgemeinerung könnte für jemand anderen nützlich sein :) – phdstudent

+0

Generalisierung unten :) –

Antwort

5

Sie können eine zusätzliche Multiplikation verwenden, um das Gitter w1 * w2' aus der vorherigen Antwort zu ändern und es dann ebenfalls mit w3 zu multiplizieren. Sie können dann die Matrixmultiplikation erneut verwenden, um mit einer "abgeflachten" Version von A zu multiplizieren.

W = reshape(w1 * w2.', [], 1) * w3.'; 
B = reshape(A, size(A, 1), []) * W(:); 

Sie könnten die Schaffung von Gewichten in seine eigene Funktion wickeln und diese verallgemeinerbar zu N Gewichte machen. Da hierbei Rekursion verwendet wird, ist N auf Ihre aktuelle Rekursionsgrenze beschränkt (standardmäßig 500).

function W = createWeights(W, varargin) 
    if numel(varargin) > 0 
     W = createWeights(W(:) * varargin{1}(:).', varargin{2:end}); 
    end 
end 

Und verwenden Sie es mit:

W = createWeights(w1, w2, w3); 
B = reshape(A, size(A, 1), []) * W(:); 

aktualisieren

Mit einem Teil von @ CKT der sehr guten Vorschlag kron zu verwenden, könnten wir createWeights nur ein wenig ändern.

function W = createWeights(W, varargin) 
    if numel(varargin) > 0 
     W = createWeights(kron(varargin{1}, W), varargin{2:end}); 
    end 
end 
+0

@Suever Benchmarks an der Spitze! :) –

1

Das ist die Logik dahinter:

ww1 = repmat (permute (w1, [4, 1, 2, 3]), [N, 1, T2, T3]); 
ww2 = repmat (permute (w2, [3, 4, 1, 2]), [N, T1, 1, T3]); 
ww3 = repmat (permute (w3, [2, 3, 4, 1]), [N, T1, T2, 1 ]); 

B = ww1 .* ww2 .* ww3 .* A; 
B = sum (B(:,:), 2) 

Sie permutew1 indem vermeiden können, w2 und w3 in der entsprechenden Dimension in erster Linie. Sie können auch bsxfun anstelle von repmat für zusätzliche Leistung verwenden, ich zeige nur die Logik hier und repmat ist einfacher zu folgen.

EDIT: verallgemeinerte Version für beliebige Eingabedimensionen:

Dims = {N, T1, T2, T3}; % add T4, T5, T6, etc as appropriate 
Params = cell (1, length (Dims)); 

Params{1} = rand (Dims{:}); 
for n = 2 : length (Dims) 
    DimSubscripts = ones (1, length (Dims)); DimSubscripts(n) = Dims{n}; 
    RepSubscripts = [Dims{:}]; RepSubscripts(n) = 1; 
    Params{n} = repmat (rand (DimSubscripts), RepSubscripts); 
end 

B = times (Params{:}); 
B = sum (B(:,:), 2) 
1

Auch hier könnte man das nicht verallgemeinern, die gut für ND, wenn Sie eine Funktion aus, das Kronecker-Produkt Vektor zu konstruieren, aber wie wäre es

A = reshape(A, N, []) * kron(w3, kron(w2, w1)); 
1

Wenn wir die Route der mit Funktionen sowieso gehen, und favorisieren Leistung über Eleganz/Kürze, dann bedenken Sie:

function B = weightReduce(A, varargin) 

    B = A; 
    for i = length(varargin):-1:1 
     N = length(varargin{i}); 
     B = reshape(B, [], N) * varargin{i}; 
    end 

end 

Dies ist der Leistungsvergleich sehe ich:

tic; 
for i = 1:10000 
    W = createWeights(w1,w2,w3); 
    B = reshape(A, size(A,1), [])*W(:); 
end 
toc 
Elapsed time is 0.920821 seconds. 
tic; 
for i = 1:10000 
    B2 = weightReduce(A, w1, w2, w3); 
end 
toc 
Elapsed time is 0.484470 seconds.