Written and maintained by CASRAI Editorial Board
Last updated
Element-wise multiplication in NumPy multiplies two arrays position by position, and you write it with the * operator or np.multiply(a, b). The two are equivalent on ndarrays, and both are different from the matrix product (@ or np.matmul). This guide shows the difference on identical inputs, how broadcasting decides whether two shapes can be multiplied, and how out= and where= behave. Behaviour follows the NumPy reference manual, and the outputs shown match NumPy 2.5.1.
What element-wise multiplication is used for in research
An element-wise (position-by-position) product is the operation behind applying weights to observations, masking an array with zeros and ones, scaling each column by a factor, or combining two arrays of the same measurement grid. To square every element of one array, see squaring arrays in NumPy. It is different from the linear-algebra matrix product, which is covered in matrix multiplication in NumPy. If your arrays are not the same shape, the rules in NumPy broadcasting apply.
Install or access
NumPy’s install page lists pip install numpy (ideally inside a virtual environment), and conda install numpy for conda users. Source: NumPy install page. Then import it under the usual alias, as described in import numpy as np:
import numpy as np
Step-by-step: element wise multiplication in NumPy
1. Multiply two arrays of the same shape
Use * or np.multiply. Both return a new array in which each element is the product of the elements at the same position.
a = np.array([1.0, 2.0, 3.0])
b = np.array([2.0, 2.0, 2.0])
a * b # array([2., 4., 6.])
np.multiply(a, b) # array([2., 4., 6.])
The NumPy documentation for numpy.multiply states: “Multiply arguments element-wise,” and “The * operator can be used as a shorthand for np.multiply on ndarrays.” Its signature is numpy.multiply(x1, x2, /, out=None, *, where=True, casting='same_kind', order='K', dtype=None, subok=True). If both inputs are scalars the result is a scalar, so np.multiply(2.0, 4.0) returns 8.0.
2. Multiply an array by a scalar
A scalar is broadcast to every position, so a * 2.0 gives the same array([2., 4., 6.]) as multiplying by an array of twos.
3. Multiply a 2-D array by a 1-D array (a numpy element wise multiplication that uses broadcasting)
x1 = np.arange(9.0).reshape((3, 3))
x2 = np.arange(3.0)
x1 * x2
# array([[ 0., 1., 4.],
# [ 0., 4., 10.],
# [ 0., 7., 16.]])
This is the example from the numpy.multiply reference page. The 1-D array [0., 1., 2.] is multiplied into every row, because the 3 elements of x2 line up with the last axis of x1.
4. Choose between *, np.multiply and @
The same two 3 x 3 integer arrays give different results depending on the operator. Take A = np.arange(1, 10).reshape(3, 3) and B = 2 * np.eye(3, dtype=int) (twos on the diagonal, zeros elsewhere):
| Expression | What it computes | Result for A and B |
|---|---|---|
A * B |
Element-wise product; same as np.multiply(A, B) |
[[2, 0, 0], [0, 10, 0], [0, 0, 18]] |
np.multiply(A, B) |
Element-wise product | Same as A * B |
A @ B |
Matrix product; shorthand for np.matmul on ndarrays |
[[2, 4, 6], [8, 10, 12], [14, 16, 18]] |
The numpy.matmul page also notes that “Multiplication by scalars is not allowed, use * instead”: np.matmul([1, 2], 3) raises ValueError: matmul: Input operand 1 does not have enough dimensions, while np.array([1, 2]) * 3 returns array([3, 6]) as in step 2.
5. Write into an existing array with out= and where=
Per the NumPy docs, out must have a shape that the inputs broadcast to; if it is not provided, “a freshly-allocated array is returned.” Passing one of the inputs as out overwrites it:
c = np.array([1.0, 2.0, 3.0])
np.multiply(c, b, out=c) # c is now array([2., 4., 6.])
The where argument is a condition: “At locations where the condition is True, the out array will be set to the ufunc result. Elsewhere, the out array will retain its original value.” That has a consequence worth knowing. If out was created with np.empty (uninitialized), the positions where where is False stay uninitialized, which the documentation also points out. Start from np.zeros or another initialized array when you use where:
out = np.zeros(3)
np.multiply(a, b, out=out, where=np.array([True, False, True]))
# array([2., 0., 6.])
Output and how to read it
The result has the shape that the two inputs broadcast to, and its dtype follows from the inputs (integers times integers stay integers; mixing in floats gives floats). Each value is a single product: result[i, j] = x1[i, j] * x2[i, j] after broadcasting. If a column of the result is all zeros, check whether the matching entries of either input are zero, as in the first column of the 3 x 3 example above. If the numbers look like sums of products instead, you used @ or np.matmul rather than *.
Broadcasting: why the shapes must be compatible
When x1.shape != x2.shape, the NumPy docs say the shapes “must be broadcastable to a common shape (which becomes the shape of the output).” The broadcasting rule starts “with the trailing (rightmost) dimension and works its way left. Two dimensions are compatible when 1. they are equal, or 2. one of them is 1.” More detail is in the broadcasting guide.
A common failure is multiplying a (4, 3) array by a length-4 vector meant as one factor per row. The vector has shape (4,), whose only dimension is compared with the last axis of the (4, 3) array (3), so it fails:
M = np.ones((4, 3))
v = np.array([1, 2, 3, 4])
M * v
# ValueError: operands could not be broadcast together with shapes (4,3) (4,)
To apply one factor per row, give the vector a trailing axis of size 1 so its shape is (4, 1); a dimension of 1 is compatible with 3:
M * v.reshape(4, 1)
# array([[1., 1., 1.],
# [2., 2., 2.],
# [3., 3., 3.],
# [4., 4., 4.]])
By contrast, a length-3 vector already lines up with the last axis, so M * np.array([1, 2, 3]) repeats [1., 2., 3.] on every row. The shape rule, not the length alone, decides which of the two you get.
Troubleshooting
ValueError: operands could not be broadcast together: the trailing dimensions are neither equal nor 1. Printa.shapeandb.shape, then reshape one of them (for examplev.reshape(-1, 1)to add a trailing axis) so the dimensions line up from the right.- Numbers look like a matrix product or a single number:
@andnp.matmulcompute the matrix product, andnp.doton two 1-D arrays returned a single number (32 for[1, 2, 3]and[4, 5, 6], whereas*returned[4, 10, 18]). Use*ornp.multiplyfor position-by-position products. - Unexpected values after using
where=: the positions where the condition is False keep whateveroutheld. Initializeoutfirst. - Original array changed: you passed it as
out. Omitoutto get a new array.
Free alternatives to NumPy for element-wise products
| Option | How you multiply element-wise | Source |
|---|---|---|
| NumPy | a * b or np.multiply(a, b) |
numpy.multiply |
| pandas Series | Series.mul(other, level=None, fill_value=None, axis=0) multiplies a Series and another object element-wise. Its fill_value fills NA values with a given value before the computation; positions where both inputs are NA are left unfilled and behave as NA does for the operation. |
pandas.Series.mul |
| Plain Python lists | Lists do not support * element-wise; a list comprehension such as [x * y for x, y in zip(p, q)] returned [4, 10, 18] for [1, 2, 3] and [4, 5, 6]. |
Python standard library (zip) |
FAQ
How do I do element-wise multiplication in NumPy?
Write a * b or np.multiply(a, b). The result is a new array in which each element is the product of the elements at the same position, provided the shapes are equal or broadcastable.
What is the difference between * and np.multiply?
On ndarrays there is none in terms of broadcasting: the documentation states that “* operator can be used as a shorthand for np.multiply.” np.multiply additionally lets you pass arguments such as out, where and dtype by name.
What is the difference between * and np.dot or @?
* multiplies position by position. @ (shorthand for np.matmul) computes the matrix product, and np.dot on two 1-D arrays gave a single number in the example above (32). The two 3 x 3 results in step 4 show how far apart they are. See matrix multiplication in NumPy.
Why does my shape error say “operands could not be broadcast together”?
Because, comparing shapes from the right, some pair of dimensions is neither equal nor 1. With shapes (4, 3) and (4,), the 3 and the 4 clash. Reshape the vector to (4, 1) to multiply by row.
Can I multiply an array by a scalar?
Yes. A scalar is broadcast to all positions, so a * 2.0 doubles every element.
Sources (official documentation)
- numpy.multiply, NumPy documentation, checked 2026-10-29.
- Broadcasting, NumPy documentation, checked 2026-10-29.
- numpy.matmul, NumPy documentation, checked 2026-10-29.
- pandas.Series.mul, pandas documentation, checked 2026-10-29.







