Hay varias formas de agregar una matriz o vector a cualquier matriz, vacía o no. Mucho depende del tamaño de la matriz y de la frecuencia con la que se agregará. (Tenga en cuenta que las matrices dispersas son un animal completamente diferente. Necesitan tratarse por separado.)
El esquema simple usaría la concatenación. Por ejemplo, crearé una matriz aleatoria. Si bien sé que una llamada a rand sería la solución adecuada aquí, lo hago solo para fines de comparación.
n = 10000;
tic
A = [];
for i = 1:n
Ai = rand(1,3);
A = [A;Ai];
end
toc
Elapsed time is 9.537194 seconds.
Vean que el tiempo requerido era razonablemente alto, mucho más de lo que acabo de llamar rand directamente.
tic,rand(n,3);toc
Elapsed time is 0.008036 seconds.
Otras formas de agregar son similares en el tiempo. Por ejemplo, puede añadir también indexando.
A = [];
A(end+1,:) = rand(1,3);
A
A =
0.91338 0.63236 0.09754
Esto será similar en términos de tiempo para agregar a través de la concatenación. Un hecho interesante de entender es que agregar nuevas filas a una matriz es sutilmente diferente a la adición de nuevas columnas. Toma un poco más de tiempo agregar una fila que una columna. Esto se debe a la forma en que se almacenan los elementos en MATLAB. Agregar una nueva fila significa que los elementos deben barajarse en la memoria.
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.
El problema con cualquier operación de anexión en absoluto es que MATLAB debe reasignar la memoria requerida para A, y lo hacen cada vez que la matriz crece en tamaño. Dado que el tamaño de A crece linealmente, el tiempo total requerido crece cuadráticamente con n. Así que si duplicamos el tamaño de n, la A dinámicamente desarrollada tardará cuatro veces más en construirse. Este comportamiento cuadrático es el motivo por el cual las personas le dicen que asigne previamente sus matrices MATLAB cuando crecerán dinámicamente. De hecho, si observa los indicadores de mlint en el editor, MATLAB le advierte cuando ve que esto sucede.
Una mejor solución, si conoce el tamaño final de A, es preasignar A a su tamaño final. A continuación, sólo en el índice.
tic
A = zeros(n,3);
for i = 1:n
A(i,:) = rand(1,3);
end
toc
Elapsed time is 0.156826 seconds.
Si bien esto es mucho mejor que la matriz dinámica crecido, todavía es mucho peor que un uso vectorizada de rand. De ser posible, use la forma vectorizada de funciones como esta.
El problema es que a veces simplemente no sabes con cuántos elementos terminarás. Todavía hay varios trucos que uno puede usar para evitar el desagradable crecimiento cuadrático.
Un truco consiste en adivinar el tamaño final de A. Ahora, use la indexación para insertar nuevos valores en A, pero observe cuidadosamente cuándo las nuevas entradas se desbordarán por los límites de A. Cuando esto se trata solo de para suceder, DOBLE el tamaño de A, agregando un gran bloque de ceros al final. Ahora vuelva a indexar los elementos nuevos en A. Mantenga un conteo separado de cuántos elementos se han "anexado". Al final de este proceso, elimine los elementos no utilizados. Esto evita gran parte del desagradable comportamiento cuadrático, ya que solo se realizarán algunos pasos de adición. (Recuerde, usted está doblando el tamaño de A cuando debe hacer un apéndice.)
Un segundo truco es usar punteros. Si bien MATLAB en realidad no ofrece mucha capacidad en forma de punteros, una matriz de celdas es un paso en esa dirección.
tic
C = {};
for i = 1:n
C{end+1} = rand(1,3);
end
A = cat(1,C{:});
toc
Elapsed time is 3.042742 seconds.
Esto llevó menos tiempo que la matriz desarrollada. ¿Por qué? Solo estábamos construyendo una serie de punteros a las celdas. Algo bueno de esto es que si cada paso de adición tiene una cantidad variable de filas, todavía funciona bien.
Un problema con la matriz de celdas, ¿no es terriblemente eficiente cuando hay MILLONES de elementos para anexar? Sigue siendo una operación cuadrática después de todo, porque estamos incrementando la matriz de punteros en cada paso.
Una solución a ese problema es utilizar una amalgama de los dos estilos que se muestran arriba. Por lo tanto, defina que cada celda de la matriz de celdas sea moderadamente grande en tamaño.Ahora usa indexación para rellenar nuevas filas de A en la celda. Cuando la celda actual deba ser más grande en el siguiente paso, agregue una nueva celda a la matriz de celdas.
Hace algunos años, esta discusión surgió en el grupo de noticias MATLAB, y se propusieron varias soluciones en este sentido. Publiqué las soluciones growdata & growdata2 como archivos en MATLAB Central File Exchange. Growdata2 función utilizada se encarga de resolver el problema:
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.
En ese momento, se trataba de un enfoque algo más rápido utilizar las variables persistentes.
tic
growdata
for i = 1:n
growdata(rand(1,3))
end
A = growdata;
toc
Elapsed time is 2.048584 seconds.
Desde entonces, la aplicación de las manijas de función ha mejorado claramente en MATLAB, por lo que el mango función es ahora más rápido.
Una virtud de estos esquemas es que no tendrán una penalización de rendimiento cuadrático, al tiempo que permiten millones de pasos de adición.
Bueno, seguramente esta es más información de la que originalmente se solicitó cuando se formuló la pregunta. Sin embargo, quizás alguien obtenga algo de eso.
+1 para su última frase. Esa es la forma más eficiente de inicializar una matriz en MATLAB. –