Numpy: divide ogni riga per un elemento vettoriale


119

Supponiamo di avere un array numpy:

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

e ho un "vettore" corrispondente:

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

Come opero su dataogni riga per sottrarre o dividere in modo che il risultato sia:

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

Per farla breve: come si esegue un'operazione su ogni riga di un array 2D con un array 1D di scalari che corrispondono a ciascuna riga?

Risposte:


181

Ecco qui. Hai solo bisogno di usare None(o in alternativa np.newaxis) in combinazione con la trasmissione:

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
ecco il doc.
sazary


@ user108569 utilizzando l'ultima versione di numpy (1.18.1), Nonefunziona ancora in modo equivalente a np.newaxis. Non sono sicuro di quale sia la tua configurazione o del problema esatto che stai riscontrando, ma la risposta è ancora valida.
JoshAdel

11

Come è stato detto, tagliare con Noneo con np.newaxesè un ottimo modo per farlo. Un'altra alternativa è usare trasposizioni e trasmissioni, come in

(data.T - vector).T

e

(data.T / vector).T

Per array di dimensioni superiori potresti utilizzare il swapaxesmetodo degli array NumPy o la rollaxisfunzione NumPy . Ci sono davvero molti modi per farlo.

Per una spiegazione più completa della trasmissione, vedere http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html


4

La soluzione di JoshAdel utilizza np.newaxis per aggiungere una dimensione. Un'alternativa è usare reshape () per allineare le dimensioni in preparazione per la trasmissione .

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

L'esecuzione di reshape () consente alle dimensioni di allinearsi per la trasmissione:

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

Nota che data/vectorva bene, ma non ti dà la risposta che desideri. Divide ogni colonna di array(invece di ogni riga ) per ogni elemento corrispondente di vector. È ciò che otterresti se ti rimodellassi esplicitamente vectorper essere 1x3invece di 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

Il modo pitonico per farlo è ...

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

Questo si occupa del rimodellamento e anche i risultati sono in formato virgola mobile. In altre risposte i risultati sono in formato intero arrotondato.

#NOTA: il numero di colonne nei dati e nel vettore deve corrispondere


Nota: questo non fa ciò che richiede l'OP. Il risultato finale è un array ([[1., 0.5, 0.33333333], [2., 1., 0.66666667], [3., 1.5, 1.]]). Potrebbe essere "Pythonic" ma non è corretto.
Mark Cramer

1
@MarkCramer Grazie. Ho corretto la mia risposta per fornire il risultato giusto.
shantanu pathak

1

Aggiungendo alla risposta di stackoverflowuser2010, nel caso generale puoi semplicemente usare

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

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

data / vector.reshape(-1,1)

Questo trasformerà il tuo vettore in un file column matrix/vector. Permettendoti di eseguire le operazioni elementwise come desideri. Almeno per me, questo è il modo più intuitivo per farlo e poiché (nella maggior parte dei casi) numpy userà solo una vista della stessa memoria interna per il rimodellamento, è anche efficiente.


Questa dovrebbe essere la risposta accettata. La creazione di un vettore colonna con .reshape(-1,1) è il modo più intuitivo per utilizzare la trasmissione.
Paul Rougieux
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.