Skip to main content
v2026.11,858 entries · CC-BY 4.0
LAC HealthMedical & Research SuppliesReagents, PPE & instruments — chain-of-custody documented.Fast, traceable sourcing built for regulated research environments, from bench consumables to instrumentation.Shop lac.us CodeCASRAIlac.us

Element-Wise Multiplication in NumPy: * vs np.multiply

How to do element wise multiplication in NumPy with * or np.multiply, how it differs from @ and np.matmul, and how to fix broadcasting errors.

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. Print a.shape and b.shape, then reshape one of them (for example v.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: @ and np.matmul compute the matrix product, and np.dot on two 1-D arrays returned a single number (32 for [1, 2, 3] and [4, 5, 6], whereas * returned [4, 10, 18]). Use * or np.multiply for position-by-position products.
  • Unexpected values after using where=: the positions where the condition is False keep whatever out held. Initialize out first.
  • Original array changed: you passed it as out. Omit out to 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)

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about Element-Wise Multiplication in NumPy: * vs np.multiply

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →