Numpy: divise chaque ligne par un élément vectoriel

119

Supposons que j'ai un tableau numpy:

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

et j'ai un "vecteur" correspondant:

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

Comment puis-je opérer le datalong de chaque ligne pour soustraire ou diviser afin que le résultat soit:

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

En bref: comment effectuer une opération sur chaque ligne d'un tableau 2D avec un tableau 1D de scalaires correspondant à chaque ligne?

BFTM
la source

Réponses:

181

Voici. Il vous suffit d'utiliser None(ou alternativement np.newaxis) combiné avec la diffusion:

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
la source
13
voici le doc.
sazary
2
un exemple visuel
PlsWork
@ user108569 en utilisant la dernière version de numpy (1.18.1), Nonefonctionne toujours de manière équivalente à np.newaxis. Je ne suis pas sûr de votre configuration ou du problème exact que vous rencontrez, mais la réponse est toujours valable.
JoshAdel le
11

Comme cela a été mentionné, trancher avec Noneou avec np.newaxesest un excellent moyen de le faire. Une autre alternative consiste à utiliser les transpositions et la diffusion, comme dans

(data.T - vector).T

et

(data.T / vector).T

Pour les tableaux de dimensions supérieures, vous pouvez utiliser la swapaxesméthode des tableaux NumPy ou NumPyrollaxis fonction . Il existe vraiment de nombreuses façons de procéder.

Pour une explication plus complète de la diffusion, voir http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

IanH
la source
4

La solution de JoshAdel utilise np.newaxis pour ajouter une dimension. Une alternative consiste à utiliser reshape () pour aligner les dimensions en vue de la diffusion .

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

Effectuer le remodelage () permet aux dimensions de s'aligner pour la diffusion:

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

Notez que data/vectorc'est correct, mais cela ne vous donne pas la réponse que vous voulez. Il divise chaque colonne de array(au lieu de chaque ligne ) par chaque élément correspondant de vector. C'est ce que vous obtiendriez si vous vous reformiez explicitement vectorpour être à la 1x3place de 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
la source
2

La manière pythonique de faire ceci est ...

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

Cela prend en charge le remodelage et les résultats sont également au format à virgule flottante. Dans les autres réponses, les résultats sont au format entier arrondi.

#REMARQUE: le nombre de colonnes dans les données et le vecteur doit correspondre

shantanu pathak
la source
Remarque: cela ne fait pas ce que l'OP demande. Le résultat final est array ([[1., 0.5, 0.33333333], [2., 1., 0.66666667], [3., 1.5, 1.]]). C'est peut-être «pythonique» mais c'est incorrect.
Mark Cramer
1
@MarkCramer Merci. J'ai corrigé ma réponse pour fournir le bon résultat.
shantanu pathak
1

Ajoutant à la réponse de stackoverflowuser2010, dans le cas général, vous pouvez simplement utiliser

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

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

data / vector.reshape(-1,1)

Cela transformera votre vecteur en fichier column matrix/vector. Vous permettant d'effectuer les opérations élément par élément comme vous le souhaitez. Au moins pour moi, c'est la manière la plus intuitive de s'y prendre et puisque (dans la plupart des cas) numpy utilisera simplement une vue de la même mémoire interne pour le remodelage, elle est également efficace.

Miaou
la source
Cela devrait être la réponse acceptée. La création d'un vecteur de colonne avec .reshape(-1,1) est la manière la plus intuitive d'utiliser la diffusion.
Paul Rougieux le