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?

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]])

13
tutaj jest doktor.
sazary


@ 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


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]])

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


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.


To powinna być akceptowana odpowiedź. Tworzenie wektora kolumnowego za pomocą .reshape(-1,1) jest najbardziej intuicyjnym sposobem korzystania z nadawania.
Paul Rougieux
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.