2011-03-17 9 views
24

Eventuali duplicati:
How can I divide each row of a matrix by a fixed row?Come sottrarre un vettore da ciascuna riga di una matrice?

Sto cercando un modo elegante per sottrarre lo stesso vettore da ogni riga di una matrice. Ecco un modo non elegante per farlo.

a = [1 2 3]; 
b = rand(7,3); 
c(:,1) = b(:,1) - a(1); 
c(:,2) = b(:,2) - a(2); 
c(:,3) = b(:,3) - a(3); 

Inoltre, il modo elegante non può essere più lento di questo metodo.

Ho provato

c = b-repmat(a,size(b,1),1); 

e sembra più lento.

MODIFICA: il vincitore è questo metodo.

c(:,1) = b(:,1) - a(1); 
c(:,2) = b(:,2) - a(2); 
c(:,3) = b(:,3) - a(3); 

EDIT: più metodi, e Tic Toc risultati:

n = 1e6; 
m = 3; 
iter = 100; 
a = rand(1,m); 
b = rand(n,m); 

tic 
c = zeros(size(b)); 
for i = 1:iter 
    c(:,1) = b(:,1) - a(1); 
    c(:,2) = b(:,2) - a(2); 
    c(:,3) = b(:,3) - a(3); 
end 
toc 

tic 
c = zeros(size(b)); 
for i = 1:iter 
    c(:,1) = b(:,1) - a(1); 
    c(:,2) = b(:,2) - a(2); 
    c(:,3) = b(:,3) - a(3); 
end 
toc 

tic 
c = zeros(size(b)); 
for i = 1:iter 
    for j = 1:3 
     c(:,j) = b(:,j) - a(j); 
    end 
end 
toc 

tic 
for i = 1:iter 
    c = b-repmat(a,size(b,1),1); 
end 
toc 

tic 
for i = 1:iter 
    c = bsxfun(@minus,b,a); 
end 
toc 

tic 
c = zeros(size(b)); 
for i = 1:iter 
    for j = 1:size(b,1) 
     c(j,:) = b(j,:) - a; 
    end 
end 
toc 

risultati

Elapsed time is 0.622730 seconds. 
Elapsed time is 0.627321 seconds. 
Elapsed time is 0.713384 seconds. 
Elapsed time is 2.621642 seconds. 
Elapsed time is 1.323490 seconds. 
Elapsed time is 17.269901 seconds. 
+2

Questo è fondamentalmente un duplicato di queste altre domande (stessa idea, operazione aritmetica diversa): [Come posso dividere gli elementi di matrice per somme di colonne in MATLAB?] (Http://stackoverflow.com/questions/1773099/how- do-i-divide-matrix-elements-by-column-sums-in-matlab), [Come posso dividere ogni riga di una matrice per una riga fissa?] (http: // stackoverflow.it/questions/4723824/how-can-i-divide-each-row-of-a-matrix-by-a-fixed-row) – gnovice

+4

Per quelli troppo pigri per seguire i link: 'c = bsxfun (@minus, b, a); ' – Jonas

+0

bsxfun sembra più lento, vedi modifica – Miebster

risposta

1

Ci sono solo tre risposte ovvie, e ti ha dato due di loro nella sua interrogazione.

Il terzo è per riga,

c(1,:) = b(1,:) - a; %... 

ma mi aspetto che per essere più lento del vostro trattamento da parte di colonna per i grandi matrici in quanto accede elementi fuori uso la memoria.

Se si trasforma l'elaborazione per colonna in un ciclo for in un file * .m o in una sottofunzione, è ancora più veloce della versione repmat?

Un'altra cosa che potresti testare per la velocità: prova a preallocare c.

c = zeros(size(b)); 
c(:,1) = b(:,1) - a(1); %... 
+0

Il quarto è usando 'bsxfun', come spiegato nelle risposte doppie e nel mio commento. – Jonas

6

Ecco il mio contributo:

c = b - ones(size(b))*diag(a)

Ora prova di velocità è:

tic 
for i = 1:10000 
    c = zeros(size(b)); 
    b = rand(7,3); 
    c = b - ones(size(b))*diag(a); 
end 
toc 

Il risultato:

Elapsed time is 0.099979 seconds.

Non abbastanza veloce, ma pulito.

+0

Funziona anche: 'b - ones (size (b, 1), size (a, 1)) * a' – suzanshakya

+0

Si noti che se la dimensione (b) è molto grande, questo sarà molto lento ed estremamente inefficiente in memoria. repmat probabilmente funzionerà meglio in quel caso. –