Reputation: 1258
I have vector a
.
I want to calculate np.inner(a, a)
But I wonder whether there is prettier way to calc it.
[The disadvantage of this way, that if I want to calculate it for a-b
or a bit more complex expression, I have to do that with one more line. c = a - b
and np.inner(c, c)
instead of somewhat(a - b)
]
Upvotes: 13
Views: 58250
Reputation: 1003
In case you end up here looking for a fast way to get the squared norm, these are some tests showing distances = np.sum((descriptors - desc[None])**2, axis=1)
to be the quickest.
import timeit
setup_code = """
import numpy as np
descriptors = np.random.rand(3000, 512)
desc = np.random.rand(512)
"""
norm_code = """
np.linalg.norm(descriptors - desc[None], axis=-1)
"""
norm_time = timeit.timeit(stmt=norm_code, setup=setup_code, number=100, )
einsum_code = """
x = descriptors - desc[None]
sqrd_dist = np.einsum('ij,ij -> i', x, x)
"""
einsum_time = timeit.timeit(stmt=einsum_code, setup=setup_code, number=100, )
norm_sqrd_code = """
distances = np.sum((descriptors - desc[None])**2, axis=1)
"""
norm_sqrd_time = timeit.timeit(stmt=norm_sqrd_code, setup=setup_code, number=100, )
print(norm_time) # 0.7688689678907394
print(einsum_time) # 0.29194538854062557
print(norm_sqrd_time) # 0.274090813472867
Upvotes: 3
Reputation: 74232
Honestly there's probably not going to be anything faster than np.inner
or np.dot
. If you find intermediate variables annoying, you could always create a lambda function:
sqeuclidean = lambda x: np.inner(x, x)
np.inner
and np.dot
leverage BLAS routines, and will almost certainly be faster than standard elementwise multiplication followed by summation.
In [1]: %%timeit -n 1 -r 100 a, b = np.random.randn(2, 1000000)
((a - b) ** 2).sum()
....:
The slowest run took 36.13 times longer than the fastest. This could mean that an intermediate result is being cached
1 loops, best of 100: 6.45 ms per loop
In [2]: %%timeit -n 1 -r 100 a, b = np.random.randn(2, 1000000)
np.linalg.norm(a - b, ord=2) ** 2
....:
1 loops, best of 100: 2.74 ms per loop
In [3]: %%timeit -n 1 -r 100 a, b = np.random.randn(2, 1000000)
sqeuclidean(a - b)
....:
1 loops, best of 100: 2.64 ms per loop
np.linalg.norm(..., ord=2)
uses np.dot
internally, and gives very similar performance to using np.inner
directly.
Upvotes: 14
Reputation: 104762
I don't know if the performance is any good, but (a**2).sum()
calculates the right value and has the non-repeated argument you want. You can replace a
with some complicated expression without binding it to a variable, just remember to use parentheses as necessary, since **
binds more tightly than most other operators: ((a-b)**2).sum()
Upvotes: 9
Reputation: 4172
to calculate norm2
numpy.linalg.norm(x, ord=2)
numpy.linalg.norm(x, ord=2)**2
for square
Upvotes: 5