2009-04-23 18 views
14

Tengo el código MATLAB insertando puntos n-dimensionales (n> 1) en una matriz (myPointMatrix) y estoy pensando en cómo insertar el primer punto.Adjuntar un vector a una matriz MATLAB vacía

En este momento, el programa comprueba el tamaño de myPointMatrix antes de insertar un punto. Si es 1x1, myPointMatrix se establece igual al punto actual. De lo contrario, se agrega el punto actual. Esta declaración if-es solo cierta vez, pero se evalúa cada vez que inserto un punto, lo cual es muy frecuente.

Al quitar el if y al intentar agregar a myPointMatrix, hace que MATLAB se queje comprensiblemente de que las dimensiones de la matriz no sean consistentes. La eliminación de la if -statement y la inicialización de myPointMatrix = 0 hace que MATLAB encuentre myPointMatrix indefinido. También comprensible

¿Cómo inicializo myPointMatrix para poder eliminar la declaración if? ¿O hay alguna otra solución inteligente?

myPointMatrix = 0; 
for x=0:limit 
    for y=0:limit 
     for z=0:limit 
      tempPoint = [x y z]; 
      if (length(myPointMatrix) == 1) 
       myPointMatrix = tempPoint; 
      else 
       myPointMatrix = [myPointMatrix; tempPoint]; 
      end 
     end 
    end 
end 

Respuesta

13

Utilice myPointMatrix = []; para inicializar la matriz.

Cuanto mayor sea myPointMatrix, más lento será. Se vuelve cada vez más lento, ya que cada vez que agrega un punto, matlab asigna una nueva matriz del nuevo tamaño y copia la información de su matriz anterior + su nuevo punto en la nueva matriz.

Entonces es mejor inicializar MyPointMatrix con su tamaño final e insertar los puntos en las posiciones dadas en la matriz.

+2

+1 para su última frase. Esa es la forma más eficiente de inicializar una matriz en MATLAB. –

3

Su mejor opción es ubicar previamente la matriz y usar una variable de bucle. Esto debería ser significativamente más rápido.

limit = 9; 
myPointMatrix = nan((limit+1)^3,3); 

loopVar = 1; 
for x=0:limit 
    for y=0:limit 
     for z=0:limit 
      myPointMatrix(loopVar,:) = [x y z]; 
      loopVar = loopVar + 1; 
     end 
    end 
end 
0

creo que la solución que busca es inicializar el myPointMatrix a una matriz con 0 líneas y 3 columnas, es decir

myPointMatrix = zeros(0, 3); 

A continuación, la primera asignación

myPointMatrix = [myPointMatrix; tempPoint]; 

funcionará correctamente, así como los siguientes. Una forma equivalente a escribir la asignación es

myPointMatrix(end+1,:) = tempPoint; 

Sin embargo, tenga en cuenta que el cultivo de una matriz como que no es eficiente y, como dice ANNAR, inicializar myPointMatrix con IFS tamaño final, si se conoce, es una solución mejor.

28

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.

0

Esto es lo que necesita

myPointMatrix=[]; 
for x=0:limit 
for y=0:limit 
for x=0:limit 
    myPointMatrix(:,end+1)=[x y z]; 
end 
end 
end 

pero sólo en el caso de que lo hace alguna operación no lineal con [x y z], antes de asignarlo. Si no, entonces usted puede escribir las líneas anteriores de la siguiente manera:

myPointMatrix=[]; 
myPointMatrix(1,:)=kron([1:limit],ones(1,limit^2)); 
myPointMatrix(2,:)=kron([1:limit^2],ones(1,limit)); 
myPointMatrix(3,:)=kron(ones(1,limit^2),[1:limit]); 

Lo anterior está totalmente vectorizado, aunque uno podría querer edit kron.m y reemplazar algunos find con logical ... pero se puede hacer que usted mismo supongo .. .: D

0
%appending to matlab array "f": 

lfg=[697 770 852 941]; 
hfg=[1209 1336 1477]; 
f=[]; 
for i=1:4, 
    for j=1:3, 
     %f = [ f [lfg(i);hfg(j)] ]; 
     append(f , [lfg(i);hfg(j)]); 
    end 
end 
f