Różnica między numpy.kształt tablicy (R, 1) i (R,)

W numpy niektóre operacje zwracają kształt (R, 1), ale niektóre zwracają kształt (R,). To sprawi, że mnożenie macierzy będzie bardziej żmudne, ponieważ wymagane jest jawne reshape. Na przykład, biorąc pod uwagę macierz M, jeśli chcemy zrobić numpy.dot(M[:,0], numpy.ones((1, R))), Gdzie R jest liczbą wierszy(oczywiście ta sama kwestia występuje również w przypadku kolumn). Otrzymamy błąd matrices are not aligned, ponieważ M[:,0] jest w kształcie (R,), ale {[10] } jest w kształcie (1, R).

Więc moje pytania to:

  1. Jaka jest różnica między kształtem (R, 1) i (R,). Wiem dosłownie, że to lista numerów i lista list, gdzie wszystkie listy zawierają tylko numer. Zastanawiam się, dlaczego nie zaprojektować numpy tak, aby faworyzował kształt (R, 1) zamiast (R,) dla łatwiejszego mnożenia macierzy.

  2. Czy są lepsze sposoby na powyższy przykład? Bez wyraźnej zmiany kształtu w ten sposób: numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))

Author: Dan D., 2014-02-27

5 answers

1. Znaczenie kształtów w NumPy

Piszesz: "wiem dosłownie, że to lista liczb i lista list, gdzie cała lista zawiera tylko liczbę", ale to trochę nieprzydatny sposób na myślenie o tym.

Najlepszym sposobem myślenia o tablicach NumPy jest to, że składają się one z dwóch części, bufora danych, który jest tylko blokiem nieprzetworzonych elementów, oraz widoku, który opisuje jak interpretować bufor danych.

Na przykład, jeśli utworzymy tablicę 12 liczby całkowite:

>>> a = numpy.arange(12)
>>> a
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

Następnie a składa się z bufora danych, ułożonego mniej więcej tak:

┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

I widok, który opisuje, jak interpretować dane:

>>> a.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
>>> a.dtype
dtype('int64')
>>> a.itemsize
8
>>> a.strides
(8,)
>>> a.shape
(12,)

Tutaj kształt (12,) oznacza, że tablica jest indeksowana pojedynczym indeksem, który biegnie od 0 do 11. W przypadku, gdy indeks i zostanie oznaczony, tablica a wygląda następująco:

i= 0    1    2    3    4    5    6    7    8    9   10   11
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

Jeśli przekształcimy tablicę, nie zmieni to bufora danych. Zamiast tego tworzy nowy widok, który opisuje inny sposób interpretacji danych. Więc po:

>>> b = a.reshape((3, 4))

Tablica b mA ten sam bufor danych co a, ale teraz jest indeksowana przez dwa indeksy , które działają odpowiednio od 0 do 2 i 0 do 3. Jeśli oznaczymy dwa indeksy i i j, tablica b wygląda następująco:

i= 0    0    0    0    1    1    1    1    2    2    2    2
j= 0    1    2    3    0    1    2    3    0    1    2    3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

Co oznacza, że:

>>> b[2,1]
9

Widać, że drugi indeks zmienia się szybko, a pierwszy indeks zmienia się powoli. Jeśli wolisz to być w przeciwnym razie możesz podać parametr order:

>>> c = a.reshape((3, 4), order='F')

Co daje tablicę indeksowaną w ten sposób:

i= 0    1    2    0    1    2    0    1    2    0    1    2
j= 0    0    0    1    1    1    2    2    2    3    3    3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

Co oznacza, że:

>>> c[2,1]
5

Powinno być teraz jasne, co to znaczy, że tablica ma kształt o jednym lub więcej wymiarach o rozmiarze 1. Po:

>>> d = a.reshape((12, 1))

Tablica d jest indeksowana przez dwa indeksy, z których pierwszy biegnie od 0 do 11, a drugi indeks jest zawsze 0:

i= 0    1    2    3    4    5    6    7    8    9   10   11
j= 0    0    0    0    0    0    0    0    0    0    0    0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

I tak:

>>> d[10,0]
10

Wymiar długość 1 jest "wolna" (w pewnym sensie), więc nic nie stoi na przeszkodzie, aby iść do miasta: {]}

>>> e = a.reshape((1, 2, 1, 6, 1))

Dając tablicę indeksowaną w ten sposób:

i= 0    0    0    0    0    0    0    0    0    0    0    0
j= 0    0    0    0    0    0    1    1    1    1    1    1
k= 0    0    0    0    0    0    0    0    0    0    0    0
l= 0    1    2    3    4    5    0    1    2    3    4    5
m= 0    0    0    0    0    0    0    0    0    0    0    0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

I tak:

>>> e[0,1,0,0,0]
6

Zobacz NumPy wewnętrzne dokumentacja aby uzyskać więcej szczegółów na temat implementacji tablic.

2. Co robić?

Od numpy.reshape po prostu tworzy nowy widok, nie powinieneś się bać korzystania z niego w razie potrzeby. Jest to odpowiednie narzędzie do użycia, gdy chcesz indeksować array w inny sposób.

Jednakże, w długich obliczeniach zazwyczaj możliwe jest skonstruowanie tablic o "właściwym" kształcie w pierwszej kolejności, a więc zminimalizowanie liczby przekształceń i transponowań. Ale nie widząc rzeczywistego kontekstu, który doprowadził do potrzeby zmiany kształtu, trudno powiedzieć, co należy zmienić.

Przykład w twoim pytaniu brzmi:

numpy.dot(M[:,0], numpy.ones((1, R)))
Ale to nie jest realistyczne. Po pierwsze, wyrażenie to:
M[:,0].sum()

Oblicza wynik prościej. Po drugie, czy naprawdę jest coś specjalnego w kolumnie 0? Być może to, czego naprawdę potrzebujesz, to:

M.sum(axis=0)
 379
Author: Gareth Rees,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-28 15:06:23

Różnica między (R,) i (1,R) jest dosłownie liczbą indeksów, których musisz użyć. ones((1,R)) jest tablicą 2-D, która ma tylko jeden wiersz. ones(R) jest wektorem. Ogólnie rzecz biorąc, jeśli nie ma sensu, aby zmienna miała więcej niż jeden wiersz/kolumnę, powinieneś używać wektora, a nie macierzy o wymiarze singletonowym.

Dla Twojego konkretnego przypadku, istnieje kilka opcji:

1) niech drugi argument będzie wektorem. Następujące dzieła fine:

    np.dot(M[:,0], np.ones(R))

2) jeśli chcesz operacji matlab jak macierz, Użyj klasy matrix zamiast ndarray. Wszystkie macierze są zmuszone do bycia tablicami 2-D, A operator {[7] } wykonuje mnożenie macierzy zamiast elementów (więc nie potrzebujesz kropki). Z mojego doświadczenia wynika, że jest to więcej kłopotów, które warto, ale może być miło, jeśli jesteś przyzwyczajony do matlab.

 10
Author: Evan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-06 09:29:56

Dla swojej podstawowej klasy tablic, tablice 2d nie są bardziej specjalne niż tablice 1d lub 3d. Istnieją pewne operacje zachowania wymiarów, niektóre, które je zmniejszają, inne łączą lub nawet rozszerzają.

M=np.arange(9).reshape(3,3)
M[:,0].shape # (3,) selects one column, returns a 1d array
M[0,:].shape # same, one row, 1d array
M[:,[0]].shape # (3,1), index with a list (or array), returns 2d
M[:,[0,1]].shape # (3,2)

In [20]: np.dot(M[:,0].reshape(3,1),np.ones((1,3)))

Out[20]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])

In [21]: np.dot(M[:,[0]],np.ones((1,3)))
Out[21]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])

Inne wyrażenia dające tę samą tablicę

np.dot(M[:,0][:,np.newaxis],np.ones((1,3)))
np.dot(np.atleast_2d(M[:,0]).T,np.ones((1,3)))
np.einsum('i,j',M[:,0],np.ones((3)))
M1=M[:,0]; R=np.ones((3)); np.dot(M1[:,None], R[None,:])

MATLAB zaczynał od tablic 2D. Nowsze wersje dopuszczają więcej wymiarów, ale zachowują dolną granicę 2. Ale nadal musisz zwrócić uwagę na różnicę między macierzą wiersza a kolumną pierwszą, jedną z kształtem (1,3) v (3,1). Jak często pisałeś [1,2,3].'? Miałem zamiar napisać row vector i column vector, ale z tym ograniczeniem 2d, nie ma żadnych wektorów w Matlabie - przynajmniej nie w matematycznym sensie wektora jako 1D.

Czy oglądałeś np.atleast_2d (również wersje _1d i _3d)?

 3
Author: hpaulj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-27 03:16:22

Kształt jest krotką. Jeśli jest tylko jeden wymiar, kształt będzie jedną cyfrą i po prostu pusty po przecinku. Dla 2 + wymiarów po wszystkich przecinkach będzie liczba.

# 1 dimension with 2 elements, shape = (2,). 
# Note there's nothing after the comma.
z=np.array([  # start dimension
    10,       # not a dimension
    20        # not a dimension
])            # end dimension
print(z.shape)

(2,)

# 2 dimensions, each with 1 element, shape = (2,1)
w=np.array([  # start outer dimension 
    [10],     # element is in an inner dimension
    [20]      # element is in an inner dimension
])            # end outer dimension
print(w.shape)

(2,1)

 2
Author: Katie Jergens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-11 14:23:49

1) powodem nie preferowania kształtu (R, 1) nad (R,) jest to, że niepotrzebnie komplikuje sprawy. Poza tym, dlaczego lepiej jest mieć kształt (R, 1) domyślnie dla wektora długości-R zamiast (1, R)? Lepiej być prostym i wyraźnym, gdy potrzebujesz dodatkowych wymiarów.

2) dla Twojego przykładu, obliczasz zewnętrzny produkt, więc możesz to zrobić bez wywołania reshape za pomocą np.outer:

np.outer(M[:,0], numpy.ones((1, R)))
 0
Author: bogatron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-26 21:56:24