Il existe plusieurs façons d'ajouter une matrice ou un vecteur à une matrice, vide ou non. Beaucoup dépend de la taille de la matrice, et à quelle fréquence vous allez faire l'appendice. (Notez que les matrices creuses sont un animal entièrement différent, elles doivent être traitées séparément.)
Le schéma simple utiliserait la concaténation. Par exemple, je vais créer un tableau aléatoire. Bien que je sache qu'un appel à rand serait la bonne solution ici, je le fais seulement à des fins de comparaison.
n = 10000;
tic
A = [];
for i = 1:n
Ai = rand(1,3);
A = [A;Ai];
end
toc
Elapsed time is 9.537194 seconds.
Voir que le temps requis était raisonnablement élevé, beaucoup plus que si je venais d'appeler rand directement.
tic,rand(n,3);toc
Elapsed time is 0.008036 seconds.
D'autres façons d'ajouter sont similaires dans le temps. Par exemple, vous pouvez également ajouter par indexation.
A = [];
A(end+1,:) = rand(1,3);
A
A =
0.91338 0.63236 0.09754
Ce sera similaire en termes de temps par concaténation annexant. Un fait intéressant à comprendre est que l'ajout de nouvelles lignes à un tableau est subtilement différent de l'ajout de nouvelles colonnes. Il faut un peu plus de temps pour ajouter une ligne qu'une colonne. C'est à cause de la façon dont les éléments sont stockés dans MATLAB. L'ajout d'une nouvelle ligne signifie que les éléments doivent effectivement être mélangés en mémoire.
A = zeros(10000,3);
B = zeros(3,10000);
tic,for i = 1:100,A(end+1,:) = rand(1,3);end,toc
Elapsed time is 0.124814 seconds.
tic,for i = 1:100,B(:,end+1) = rand(3,1);end,toc
Elapsed time is 0.116209 seconds.
Le problème avec toute opération append tout est que Matlab doit réallouer la mémoire requise pour A, et ce, chaque fois que la matrice croît en taille. Puisque la taille de A augmente linéairement, le temps global nécessaire croît quadratiquement avec n. Donc, si nous devions doubler la taille de n, le A développé dynamiquement prendra quatre fois plus de temps à construire. Ce comportement quadratique est la raison pour laquelle les gens vous demandent de pré-allouer vos tableaux MATLAB quand ils seront développés dynamiquement. En fait, si vous regardez les drapeaux mlint dans l'éditeur, MATLAB vous avertit quand cela se produit.
Une meilleure solution, si vous connaissez la taille finale de A, est de pré-allouer A à sa taille finale. Ensuite, il suffit index.
tic
A = zeros(n,3);
for i = 1:n
A(i,:) = rand(1,3);
end
toc
Elapsed time is 0.156826 seconds.
Bien que ce soit beaucoup mieux que le tableau augmenté de façon dynamique, il est encore bien pire qu'une utilisation vectorisée de rand. Donc, dans la mesure du possible, utilisez la forme vectorisée des fonctions comme celle-ci. Le problème est, parfois vous ne savez tout simplement pas combien d'éléments vous finirez avec. Il y a encore plusieurs astuces que l'on peut utiliser pour éviter la croissance quadratique désagréable. Une astuce consiste à faire une estimation de la taille finale de A. Maintenant, utilisez l'indexation pour insérer de nouvelles valeurs dans A, mais surveillez attentivement quand les nouvelles entrées déborderont sur les limites de A. pour arriver, DOUBLE la taille de A, en ajoutant un gros bloc de zéros à la fin. Revenez maintenant à l'indexation des nouveaux éléments dans A. Gardez un compte séparé du nombre d'éléments qui ont été "ajoutés". À la toute fin de ce processus, supprimez les éléments inutilisés. Cela évite une bonne partie du comportement quadratique désagréable, car seules quelques étapes d'ajout seront possibles. (Rappelez-vous que vous doublez la taille de A lorsque vous devez faire un ajout.)
Une deuxième astuce consiste à utiliser des pointeurs. Alors que MATLAB n'offre pas vraiment beaucoup de possibilités en termes de pointeurs, un tableau de cellules est un pas dans cette direction.
tic
C = {};
for i = 1:n
C{end+1} = rand(1,3);
end
A = cat(1,C{:});
toc
Elapsed time is 3.042742 seconds.
Cela a pris moins de temps à accomplir que le réseau développé. Pourquoi? Nous construisions seulement un tableau de pointeurs sur les cellules. Une bonne chose à ce sujet est que si chaque étape d'ajout a un nombre variable de lignes, cela fonctionne toujours bien.
Un problème avec le tableau de cellules, c'est qu'il n'est pas très efficace lorsqu'il y a des MILLIONS d'éléments à ajouter. Après tout, c'est encore une opération quadratique, car nous élargissons le tableau des pointeurs à chaque étape.
Une solution à ce problème consiste à utiliser un amalgame des deux styles présentés ci-dessus. Ainsi, définissez chaque cellule du tableau de cellules pour qu'elle soit de taille modérément grande.Utilisez maintenant l'indexation pour insérer de nouvelles lignes de A dans la cellule. Lorsque la cellule actuelle doit être agrandie à la prochaine étape d'ajout, ajoutez simplement une nouvelle cellule au tableau de cellules.
Il y a quelques années, cette discussion a été soulevée sur le groupe de discussion MATLAB, et plusieurs solutions dans ce sens ont été proposées. J'ai posté les solutions growdata & growdata2 en tant que fichiers sur l'échange de fichiers central MATLAB. Growdata2 fonction utilisée poignées pour résoudre le problème:
tic
Ahandle = growdata2;
for i = 1:n
Ahandle(rand(1,3))
end
% unpack the object into a normal array
A = Ahandle();
toc
Elapsed time is 1.572798 seconds.
À l'époque, il était une approche un peu plus rapide d'utiliser des variables persistantes. Depuis lors, l'implémentation des poignées de fonction s'est clairement améliorée dans MATLAB, donc la poignée de fonction est maintenant plus rapide.
Une des caractéristiques de ces schémas est qu'ils n'auront pas de pénalité de performance quadratique, tout en permettant des millions d'étapes d'ajout.
Eh bien, c'est certainement plus d'informations que ce qui a été demandé à l'origine lorsque la question a été posée. Peut-être que quelqu'un s'en sortira quand même.
+1 pour votre dernière phrase. C'est le moyen le plus efficace d'initialiser une matrice dans MATLAB. –