De matrices ND a 1D

141

Digamos que tengo una matriz a:

a = np.array([[1,2,3], [4,5,6]])

array([[1, 2, 3],
       [4, 5, 6]])

Me gustaría convertirlo en una matriz 1D (es decir, un vector de columna):

b = np.reshape(a, (1,np.product(a.shape)))

pero esto vuelve

array([[1, 2, 3, 4, 5, 6]])

que no es lo mismo que:

array([1, 2, 3, 4, 5, 6])

Puedo tomar el primer elemento de esta matriz para convertirla manualmente en una matriz 1D:

b = np.reshape(a, (1,np.product(a.shape)))[0]

pero esto requiere que sepa cuántas dimensiones tiene la matriz original (y concatene [0] cuando se trabaja con dimensiones más altas)

¿Existe una forma independiente de las dimensiones de obtener un vector de columna / fila de un ndarray arbitrario?

Amelio Vazquez-Reina
fuente

Respuestas:

277

Utilice np.ravel (para una vista 1D) o np.ndarray.flatten (para una copia 1D) o np.ndarray.flat (para un iterador 1D):

In [12]: a = np.array([[1,2,3], [4,5,6]])

In [13]: b = a.ravel()

In [14]: b
Out[14]: array([1, 2, 3, 4, 5, 6])

Tenga en cuenta que ravel()devuelve un viewde acuando sea posible. Entonces modificar btambién modifica a. ravel()devuelve unview cuando los elementos 1D están contiguos en la memoria, pero devolvería un copyif si, por ejemplo, ase hiciera cortando otra matriz utilizando un tamaño de paso no unitario (p a = x[::2]. ej .).

Si desea una copia en lugar de una vista, use

In [15]: c = a.flatten()

Si solo quieres un iterador, usa np.ndarray.flat:

In [20]: d = a.flat

In [21]: d
Out[21]: <numpy.flatiter object at 0x8ec2068>

In [22]: list(d)
Out[22]: [1, 2, 3, 4, 5, 6]
unutbu
fuente
44
<pedante> En este ejemplo, ravel()devuelve una vista, pero eso no siempre es cierto. Hay casos en los que ravel()devuelve una copia. </
pedantic
3
a.ravel()parece ser alrededor de tres veces más rápido que a.reshape(-1). a.flatten()es mucho más lento, ya que necesita hacer una copia.
BallpointBen
25
In [14]: b = np.reshape(a, (np.product(a.shape),))

In [15]: b
Out[15]: array([1, 2, 3, 4, 5, 6])

o simplemente:

In [16]: a.flatten()
Out[16]: array([1, 2, 3, 4, 5, 6])
NPE
fuente
11
Puede usar b = a.reshape(-1)para abreviar en el primer ejemplo.
Syrtis Major
5

Una de las formas más simples es usar flatten(), como este ejemplo:

 import numpy as np

 batch_y =train_output.iloc[sample, :]
 batch_y = np.array(batch_y).flatten()

Mi matriz fue así:

    0
0   6
1   6
2   5
3   4
4   3
.
.
.

Después de usar flatten():

array([6, 6, 5, ..., 5, 3, 6])

También es la solución de errores de este tipo:

Cannot feed value of shape (100, 1) for Tensor 'input/Y:0', which has shape '(?,)' 
DINA TAKLIT
fuente
4

Para obtener una lista de la matriz con diferentes tamaños, utilice lo siguiente:

import numpy as np

# ND array list with different size
a = [[1],[2,3,4,5],[6,7,8]]

# stack them
b = np.hstack(a)

print(b)

Salida:

[1 2 3 4 5 6 7 8]

bikram
fuente
¿Cómo obtendrías la forma de la aespalda b?
dvdblk
Si quieres dividir 1D en trozos. Ver este stackoverflow.com/a/8495740/6117565
bikram
4

Quería ver un resultado de referencia de las funciones mencionadas en las respuestas, incluidas las de unutbu .

También quiero señalar que doc numpy recomienda usar arr.reshape(-1)en caso de que la vista sea preferible. (aunque raveles un poco más rápido en el siguiente resultado)


TL; DR : np.raveles el más eficaz (por una cantidad muy pequeña).

Punto de referencia

Funciones:

versión numpy: '1.18.0'

Tiempos de ejecución en diferentes ndarraytamaños.

+-------------+----------+-----------+-----------+-------------+
|  function   |   10x10  |  100x100  | 1000x1000 | 10000x10000 |
+-------------+----------+-----------+-----------+-------------+
| ravel       | 0.002073 |  0.002123 |  0.002153 |    0.002077 |
| reshape(-1) | 0.002612 |  0.002635 |  0.002674 |    0.002701 |
| flatten     | 0.000810 |  0.007467 |  0.587538 |  107.321913 |
| flat        | 0.000337 |  0.000255 |  0.000227 |    0.000216 |
+-------------+----------+-----------+-----------+-------------+

Conclusión

ravely reshape(-1)el tiempo de ejecución fue consistente e independiente del tamaño de ndarray. Sin embargo, raveles un poco más rápido, pero reshapeproporciona flexibilidad para cambiar el tamaño. (tal vez por eso numpy doc recomienda usarlo en su lugar. O podría haber algunos casos en los que reshapedevuelve la vista y ravelno).
Si se trata de ndarray de gran tamaño, el uso flattenpuede causar un problema de rendimiento. Recomiendo no usarlo. A menos que necesite una copia de los datos para hacer otra cosa.

Código usado

import timeit
setup = '''
import numpy as np
nd = np.random.randint(10, size=(10, 10))
'''

timeit.timeit('nd = np.reshape(nd, -1)', setup=setup, number=1000)
timeit.timeit('nd = np.ravel(nd)', setup=setup, number=1000)
timeit.timeit('nd = nd.flatten()', setup=setup, number=1000)
timeit.timeit('nd.flat', setup=setup, number=1000)
haku
fuente
0

Aunque esto no está usando el formato de matriz np, (para perezoso modificar mi código) esto debería hacer lo que quieras ... Si realmente quieres un vector de columna, querrás transponer el resultado del vector. Todo depende de cómo planeas usar esto.

def getVector(data_array,col):
    vector = []
    imax = len(data_array)
    for i in range(imax):
        vector.append(data_array[i][col])
    return ( vector )
a = ([1,2,3], [4,5,6])
b = getVector(a,1)
print(b)

Out>[2,5]

Entonces, si necesita transponer, puede hacer algo como esto:

def transposeArray(data_array):
    # need to test if this is a 1D array 
    # can't do a len(data_array[0]) if it's 1D
    two_d = True
    if isinstance(data_array[0], list):
        dimx = len(data_array[0])
    else:
        dimx = 1
        two_d = False
    dimy = len(data_array)
    # init output transposed array
    data_array_t = [[0 for row in range(dimx)] for col in range(dimy)]
    # fill output transposed array
    for i in range(dimx):
        for j in range(dimy):
            if two_d:
                data_array_t[j][i] = data_array[i][j]
            else:
                data_array_t[j][i] = data_array[j]
    return data_array_t
xcellsior
fuente