Adding a vector to matrix rows in numpy
Asked Answered
G

2

24

Is there a fast way in numpy to add a vector to every row or column of a matrix.

Lately, I have been tiling the vector to the size of the matrix, which can use a lot of memory. For example

    mat=np.arange(15)
    mat.shape=(5,3)

    vec=np.ones(3)
    mat+=np.tile(vec, (5,1))

The other way I can think of is using a python loop, but loops are slow:

    for i in xrange(len(mat)):
        mat[i,:]+=vec

Is there a fast way to do this in numpy without resorting to C extensions?

It would be nice to be able to virtually tile a vector, like a more flexible version of broadcasting. Or to be able to iterate an operation row-wise or column-wise, which you may almost be able to do with some of the ufunc methods.

Gheber answered 15/8, 2012 at 14:23 Comment(4)
Could you give another example? The one you've given would give the same answer just with mat + vec, so I'm not sure exactly what you're after. [Incidentally, this is an array, not a matrix.]Aspinwall
by matrix, I mean a 2-d array (a matrix in the mathematical sense)Gheber
I want to add the same 1-d array to every row of the 2d arrayGheber
In numpy, a matrix is different from a 2d array. For example, multiplication is matrix multiplication on matrix objects but elementwise on array objects, so it's a good idea to keep them distinct.Aspinwall
K
40

For adding a 1d array to every row, broadcasting already takes care of things for you:

mat += vec

However more generally you can use np.newaxis to coerce the array into a broadcastable form. For example:

mat + np.ones(3)[np.newaxis,:]

While not necessary for adding the array to every row, this is necessary to do the same for column-wise addition:

mat + np.ones(5)[:,np.newaxis]

EDIT: as Sebastian mentions, for row addition, mat + vec already handles the broadcasting correctly. It is also faster than using np.newaxis. I've edited my original answer to make this clear.

Keening answered 15/8, 2012 at 14:37 Comment(8)
Here its not even necessary, but if mat would be shaped (3,5) then using np.ones(3)[:,np.newaxis] does the trick.Evilminded
@Sebastian: You are right; I was just trying to show a general method of getting the broadcasting correct since the OP asked for both columns and row addition.Keening
Okay, I must be really stupid today. Could someone explain to me why this isn't just a slower version of mat + vec?Aspinwall
@Aspinwall not being stupid. See my edit above. I should have been clear that what I was demonstrating was a general method for coercing arrays into a broadcasting friendly shape.Keening
It looks like mat + vec works when vec is the same size as the number of columns in mat, but you need newaxis to add columns.Gheber
In numpy 1.18 I am getting the error numpy.core._exceptions.UFuncTypeError: Cannot cast ufunc 'add' output from dtype('float64') to dtype('int64') with casting rule 'same_kind' when trying to run the mat += vec line. The np.newaxis technique works though.Consensual
@Consensual The error is telling you that you are trying to add two numpy arrays with different datatypes, which is causing the error. Making both mat and vec with the same dtype.Wyon
Update as of 2020: numpy handles the broadcasting correctly with adding a column to a matrix without the explicit broadcasting syntax, if the number of rows is the same. E.g.: np.array([[1,2],[3,4],[5,6]]) + np.array([[1],[2],[3]]) gives array([[2, 3], [5, 6], [8, 9]])Wyon
D
0

Numpy broadcasting will automatically add a compatible size vector (1D array) to a matrix (2D array, not numpy matrix). It does this by matching shapes based on dimension from right to left, "stretching" missing or value 1 dimensions to match the other. This is explained in https://numpy.org/doc/stable/user/basics.broadcasting.html:

mat:               5 x 3
vec:                   3
vec (broadcasted): 5 x 3

By default, numpy arrays are row-major ("C order"), with axis 0 is "matrix row" and axis 1 is "matrix col", so the broadcasting clones the vector as matrix rows along axis 0.

Disciplinary answered 15/4, 2022 at 22:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.