Numpy: podziel każdy wiersz przez element wektora

119

Załóżmy, że mam tablicę numpy:

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

i mam odpowiedni „wektor”:

vector = np.array([1,2,3])

Jak operować datawzdłuż każdego wiersza, aby odjąć lub podzielić, aby wynik był następujący:

sub_result = [[0,0,0], [0,0,0], [0,0,0]]
div_result = [[1,1,1], [1,1,1], [1,1,1]]

Krótko mówiąc: jak wykonać operację na każdym wierszu tablicy 2D z tablicą skalarną 1D, która odpowiada każdemu wierszowi?

BFTM
źródło

Odpowiedzi:

181

Proszę bardzo. Wystarczy użyć None(lub alternatywnie np.newaxis) w połączeniu z nadawaniem:

In [6]: data - vector[:,None]
Out[6]:
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

In [7]: data / vector[:,None]
Out[7]:
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])
JoshAdel
źródło
13
tutaj jest doktor.
sazary
2
wizualny przykład
PlsWork
@ user108569 używając najnowszej wersji numpy (1.18.1), Nonenadal działa równoważnie z np.newaxis. Nie jestem pewien, jaka jest Twoja konfiguracja ani jaki jest konkretny problem, ale odpowiedź jest nadal aktualna.
JoshAdel
11

Jak już wspomniano, krojenie z Nonelub z użyciem np.newaxesjest świetnym sposobem na zrobienie tego. Inną alternatywą jest użycie transpozycji i nadawania, jak w

(data.T - vector).T

i

(data.T / vector).T

W przypadku tablic o wyższych wymiarach możesz chcieć użyć swapaxesmetody tablic NumPy lub rollaxisfunkcji NumPy . Naprawdę można to zrobić na wiele sposobów.

Pełniejsze wyjaśnienie nadawania można znaleźć pod adresem http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

IanH
źródło
4

Rozwiązanie JoshAdel wykorzystuje np.newaxis, aby dodać wymiar. Alternatywą jest użycie reshape () do wyrównania wymiarów w ramach przygotowań do nadawania .

data = np.array([[1,1,1],[2,2,2],[3,3,3]])
vector = np.array([1,2,3])

data
# array([[1, 1, 1],
#        [2, 2, 2],
#        [3, 3, 3]])
vector
# array([1, 2, 3])

data.shape
# (3, 3)
vector.shape
# (3,)

data / vector.reshape((3,1))
# array([[1, 1, 1],
#        [1, 1, 1],
#        [1, 1, 1]])

Wykonanie reshape () umożliwia wyrównanie wymiarów do nadawania:

data:            3 x 3
vector:              3
vector reshaped: 3 x 1

Zauważ, że data/vectorjest to w porządku, ale nie daje Ci odpowiedzi, której chcesz. Dzieli każdą kolumnę z array(a nie dla każdego rzędu ) w każdym odpowiednim elementem vector. To jest to, co byś uzyskał, gdybyś wyraźnie przekształcił vectorsię w 1x3zamiast 3x1.

data / vector
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
data / vector.reshape((1,3))
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
stackoverflowuser2010
źródło
2

Pythonowym sposobem na to jest ...

np.divide(data.T,vector).T

To zajmuje się przekształcaniem, a także wyniki są w formacie zmiennoprzecinkowym. W innych odpowiedziach wyniki są w zaokrąglonych liczbach całkowitych.

# UWAGA: liczba kolumn w obu danych i wektorze powinna być zgodna

shantanu pathak
źródło
Uwaga: To nie robi tego, o co prosi OP. Wynik końcowy to tablica ([[1., 0.5, 0.33333333], [2., 1., 0.66666667], [3., 1.5, 1.]]). Może to być „Pythonic”, ale jest niepoprawne.
Mark Cramer
1
@MarkCramer Dziękuję. Poprawiłem swoją odpowiedź, aby podać właściwy wynik.
shantanu pathak
1

Dodając do odpowiedzi stackoverflowuser2010, w ogólnym przypadku możesz po prostu użyć

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

vector = np.array([1,2,3])

data / vector.reshape(-1,1)

To zmieni twój wektor w column matrix/vector. Umożliwiając wykonywanie podstawowych operacji, jak chcesz. Przynajmniej dla mnie jest to najbardziej intuicyjny sposób postępowania, a ponieważ (w większości przypadków) numpy po prostu użyje widoku tej samej pamięci wewnętrznej do zmiany kształtu, również jest wydajna.

miauczeć
źródło
To powinna być akceptowana odpowiedź. Tworzenie wektora kolumnowego za pomocą .reshape(-1,1) jest najbardziej intuicyjnym sposobem korzystania z nadawania.
Paul Rougieux