Novato de Python aquí que viene de un fondo MATLAB

Tengo una matriz de 1 columna y quiero mover esa columna a la primera columna de una matriz de 3 columnas. Con antecedentes de MATLAB, esto es lo que haría:

import numpy as np

A = np.zeros([150,3]) #three column array

B = np.ones([150,1]) #one column array which needs to replace the first column of A

#MATLAB-style solution:

A[:,0] = B

Sin embargo, esto no funciona porque la "forma" de A es (150,3) y la "forma" de B es (150,1). Y aparentemente el comando A [:, 0] da como resultado una "forma" de (150).

Ahora bien, ¿cuál es la diferencia entre (150,1) y (150)? ¿No son lo mismo: un vector de columna? ¿Y por qué Python no es "lo suficientemente inteligente" para darse cuenta de que quiero poner el vector de columna, B, en la primera columna de A?

¿Existe una manera fácil de convertir un vector de 1 columna con forma (N, 1) en un vector de 1 columna con forma (N)?

Soy nuevo en Python y esto parece una tontería que MATLAB hace mucho mejor ...

2
Darcy 14 nov. 2017 a las 04:36

2 respuestas

La mejor respuesta

Utilice el método squeeze para eliminar las dimensiones del tamaño 1 .

A[:,0] = B.squeeze()

O simplemente cree B unidimensional para empezar:

B = np.ones([150])

El hecho de que NumPy mantenga una distinción entre una matriz 1D y una matriz 2D con una de las dimensiones de 1 es razonable, especialmente cuando uno comienza a trabajar con matrices n-dimensionales.

Para responder a la pregunta del título: hay una diferencia estructural evidente entre una matriz de formas (3,) como

[1, 2, 3]

Y una matriz de forma (3, 1) como

[[1], [2], [3]]
2
14 nov. 2017 a las 02:07

Varias cosas son diferentes. En numpy, las matrices pueden ser 0d o 1d o más. En MATLAB 2d es el más pequeño (y al mismo tiempo las únicas dimensiones). MATLAB expande fácilmente las dimensiones al final porque es Fortran ordered. numpy, es por defecto c ordered, y expande más fácilmente las dimensiones en el frente.

In [1]: A = np.zeros([5,3])
In [2]: A[:,0].shape   
Out[2]: (5,)

La indexación simple reduce una dimensión, independientemente de si es A[0,:] o A[:,0]. Contraste eso con lo que sucede con una matriz de MATLAB 3d, A(1,:,:) v A(:,:,1).

numpy hace broadcasting, ajustando dimensiones durante operaciones como suma y asignación. Una regla básica es que las dimensiones se pueden expandir automáticamente hacia el inicio si es necesario:

In [3]: A[:,0] = np.ones(5)
In [4]: A[:,0] = np.ones([1,5])
In [5]: A[:,0] = np.ones([5,1])
...
ValueError: could not broadcast input array from shape (5,1) into shape (5)

Puede cambiar (5,) LHS a (1,5), pero no puede cambiarlo a (5,1).

Otro ejemplo de transmisión, +:

In [6]: A[:,0] + np.ones(5);
In [7]: A[:,0] + np.ones([1,5]);
In [8]: A[:,0] + np.ones([5,1]);

Ahora, (5,) funciona con (5,1), pero eso se debe a que se convierte en (1,5), que junto con (5,1) produce (5,5), un producto externo que difunde:

In [9]: (A[:,0] + np.ones([5,1])).shape
Out[9]: (5, 5)

En octava

>> x = ones(2,3,4);
>> size(x(1,:,:))
ans =
   1   3   4
>> size(x(:,:,1))
ans =
   2   3
>> size(x(:,1,1) )
ans =
   2   1
>> size(x(1,1,:) )
ans =
   1   1   4

Para hacer la tarea que desea, ajuste cualquier lado

Índice de una manera que conserva el número de dimensiones:

In [11]: A[:,[0]].shape    
Out[11]: (5, 1)
In [12]: A[:,[0]] = np.ones([5,1])

Transponer (5,1) a (1,5):

In [13]: A[:,0] = np.ones([5,1]).T

Aplanar / desenredar el (5,1) a (5,):

In [14]: A[:,0] = np.ones([5,1]).flat
In [15]: A[:,0] = np.ones([5,1])[:,0]

squeeze, ravel también funcionan.

Algunas pruebas rápidas en Octave indican que es más indulgente cuando se trata de diferencias de dimensiones. Pero el numpy da prioridad a la coherencia. Una vez que se entienden las reglas de transmisión, el comportamiento tiene sentido.

3
hpaulj 14 nov. 2017 a las 04:31