web-dev-qa-db-fra.com

Comment soustraire un vecteur de chaque ligne d'une matrice?

Duplicata possible:
Comment puis-je diviser chaque ligne d'une matrice par une ligne fixe?

Je cherche un moyen élégant de soustraire le même vecteur de chaque ligne d'une matrice. Voici une manière non élégante de le faire.

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);

De plus, la manière élégante ne peut pas être plus lente que cette méthode.

J'ai essayé

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

et ça semble plus lent.

EDIT: Le gagnant est cette méthode.

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

EDIT: Plus de méthodes et de résultats de tic toc:

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

résultats

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.
26
Miebster

Voici ma contribution:

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

Maintenant testez la vitesse:

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

Le résultat:

Elapsed time is 0.099979 seconds.

Pas tout à fait aussi rapide, mais c'est propre.

6
MudPhud

Il n'y a que trois réponses évidentes, et vous en avez donné deux dans votre question.

Le troisième est par rangée,

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

mais je m'attends à ce que ce soit plus lent que votre traitement par colonne pour les grandes matrices car il accède aux éléments dans l'ordre de mémoire.

Si vous transformez votre traitement par colonne en boucle for dans un fichier ou une sous-fonction * .m, est-il toujours plus rapide que la version repmat?

Une autre chose que vous pourriez tester pour la vitesse: Essayez de préallouer c.

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