Od macierzy ND do 1D


141

Powiedz, że mam tablicę a:

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

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

Chciałbym przekonwertować go na tablicę 1D (tj. Wektor kolumnowy):

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

ale to wraca

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

co nie jest tym samym, co:

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

Mogę wziąć pierwszy element tej tablicy, aby ręcznie przekonwertować ją na tablicę 1D:

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

ale to wymaga ode mnie, aby wiedzieć, ile wymiarów ma oryginalna tablica (i połączyć [0] podczas pracy z wyższymi wymiarami)

Czy istnieje niezależny od wymiarów sposób uzyskania wektora kolumny / wiersza z dowolnej tablicy ndarray?

Odpowiedzi:


277

Użyj np.ravel (dla widoku 1D) lub np.ndarray.flatten (dla kopii 1D) lub np.ndarray.flat (dla iteratora 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])

Zwróć uwagę, że ravel()zwraca viewof, ajeśli to możliwe. Więc modyfikowanie brównież modyfikuje a. ravel()zwraca wartość a, viewgdy elementy 1D są ciągłe w pamięci, ale zwróci wartość a, copyjeśli na przykład azostały utworzone z wycinania innej tablicy przy użyciu niejednostkowego rozmiaru kroku (np a = x[::2].).

Jeśli chcesz mieć kopię, a nie widok, użyj

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

Jeśli potrzebujesz tylko iteratora, użyj 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]

4
<pedantyczny> W tym przykładzie ravel()zwraca widok, ale nie zawsze jest to prawdą. Są przypadki, w których ravel()zwraca kopię. </
pedantic

3
a.ravel()wygląda na około trzy razy szybszą niż a.reshape(-1). a.flatten()jest znacznie wolniejszy, ponieważ musi wykonać kopię.
BallpointBen

25
In [14]: b = np.reshape(a, (np.product(a.shape),))

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

lub po prostu:

In [16]: a.flatten()
Out[16]: array([1, 2, 3, 4, 5, 6])

11
Może użyć b = a.reshape(-1)skrótu w pierwszym przykładzie.
Syrtis Major

5

Jednym z najprostszych sposobów jest użycie flatten(), jak w tym przykładzie:

 import numpy as np

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

Moja tablica wyglądała tak:

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

Po użyciu flatten():

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

To także rozwiązanie błędów tego typu:

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

4

Aby uzyskać listę tablic o różnym rozmiarze, użyj następującego:

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)

Wynik:

[1 2 3 4 5 6 7 8]


jak uzyskać kształt apleców b?
dvdblk

Jeśli chcesz podzielić 1D na kawałki. Zobacz ten stackoverflow.com/a/8495740/6117565
bikram,

4

Chciałem zobaczyć wynik testu porównawczego funkcji wymienionych w odpowiedziach, w tym unutbu .

Chcę również zwrócić uwagę, że numpy doc zaleca użycie arr.reshape(-1)w widoku przypadku. (chociaż raveljest odrobinę szybszy w następującym wyniku)


TL; DR : np.raveljest najbardziej wydajny (w bardzo niewielkim stopniu).

Reper

Funkcje:

wersja numpy: „1.18.0”

Czasy realizacji dla różnych ndarrayrozmiarów

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

Wniosek

ravela reshape(-1)czas wykonania był spójny i niezależny od rozmiaru ndarray. Jest jednak ravelodrobinę szybszy, ale reshapezapewnia elastyczność w zmianie rozmiaru. (może dlatego numpy doc zaleca użycie go zamiast tego. Lub mogą wystąpić przypadki, w których reshapezwraca widok, a ravelnie).
Jeśli masz do czynienia z ndarray o dużych rozmiarach, użycie flattenmoże spowodować problemy z wydajnością. Zalecam, aby go nie używać. Chyba że potrzebujesz kopii danych do zrobienia czegoś innego.

Używany kod

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)

0

Chociaż nie używa to formatu tablicy np, (aby leniwie modyfikować mój kod) powinno to zrobić, co chcesz ... Jeśli naprawdę chcesz mieć wektor kolumnowy, będziesz chciał transponować wynik wektora. Wszystko zależy od tego, jak planujesz to wykorzystać.

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]

Więc jeśli potrzebujesz transpozycji, możesz zrobić coś takiego:

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.