De matrizes ND para 1D

141

Digamos que eu tenho uma matriz a:

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

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

Gostaria de convertê-lo em uma matriz 1D (ou seja, um vetor de coluna):

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

mas isso retorna

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

que não é o mesmo que:

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

Eu posso pegar o primeiro elemento dessa matriz para convertê-lo manualmente em uma matriz 1D:

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

mas isso exige que eu saiba quantas dimensões a matriz original possui (e concatene [0] 's ao trabalhar com dimensões maiores)

Existe uma maneira independente de dimensões de obter um vetor de coluna / linha de um ndarray arbitrário?

Amelio Vazquez-Reina
fonte

Respostas:

277

Use np.ravel (para uma visualização 1D) ou np.ndarray.flatten (para uma cópia 1D) ou np.ndarray.flat (para um 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])

Note-se que ravel()retorna um viewde aquando possível. Então modificar btambém modifica a. ravel()retorna a viewquando os elementos 1D são contíguos na memória, mas retornaria a copyse, por exemplo, afossem feitos de fatiar outra matriz usando um tamanho de etapa não unitário (por exemplo a = x[::2]).

Se você deseja uma cópia em vez de uma visualização, use

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

Se você quer apenas um iterador, use 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
fonte
4
<pedantic> Neste exemplo, ravel()retorna uma visualização, mas isso nem sempre é verdade. Há casos em que ravel()retorna uma cópia. </pedantic>
Warren Weckesser
3
a.ravel()parece ser cerca de três vezes mais rápido que a.reshape(-1). a.flatten()é muito mais lento, pois precisa fazer uma cópia.
usar o seguinte
25
In [14]: b = np.reshape(a, (np.product(a.shape),))

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

ou simplesmente:

In [16]: a.flatten()
Out[16]: array([1, 2, 3, 4, 5, 6])
NPE
fonte
11
Pode ser usado b = a.reshape(-1)para abreviar no primeiro exemplo.
Syrtis Major
5

Uma das maneiras mais simples é usar flatten(), como este exemplo:

 import numpy as np

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

Minha matriz era assim:

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

Após o uso flatten():

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

É também a solução de erros desse tipo:

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

Para obter uma lista de matrizes com tamanhos diferentes, use o seguinte:

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)

Resultado:

[1 2 3 4 5 6 7 8]

bikram
fonte
como você obteria a forma das acostas b?
Dvdblk
Se você deseja dividir 1D em pedaços. Veja este stackoverflow.com/a/8495740/6117565
bikram
4

Eu queria ver um resultado de referência das funções mencionadas nas respostas, incluindo as do unutbu .

Também quero ressaltar que o documento numpy recomenda usar arr.reshape(-1)caso a visualização seja preferível. (embora ravelseja um pouco mais rápido no resultado a seguir)


TL; DR : np.ravelé o mais eficiente (por uma quantidade muito pequena).

Referência

Funções:

versão numpy: '1.18.0'

Tempos de execução em ndarraytamanhos diferentes

+-------------+----------+-----------+-----------+-------------+
|  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 |
+-------------+----------+-----------+-----------+-------------+

Conclusão

ravele reshape(-1)o tempo de execução foi consistente e independente do tamanho do ndarray. No entanto, ravelé um pouco mais rápido, mas reshapeoferece flexibilidade na reformulação do tamanho. (talvez seja por isso que o doc numpy recomenda usá-lo. Ou pode haver alguns casos em que os reshaperetornos são exibidos e ravelnão).
Se você estiver lidando com ndarray de tamanho grande, o uso flattenpoderá causar um problema de desempenho. Recomende não usá-lo. A menos que você precise de uma cópia dos dados para fazer outra coisa.

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
fonte
0

Embora isso não esteja usando o formato de matriz np, (para modificar meu código com preguiça), isso deve ser o que você deseja ... Se você realmente deseja um vetor de coluna, deseja transpor o resultado do vetor. Tudo depende de como você planeja usar isso.

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]

Portanto, se você precisar transpor, poderá fazer algo assim:

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
fonte