Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Dot product of each vector in two lists of vectors

Tags:

python

Say I have two lists containing vector:

A = [(1,1,1), (0,1,1)]
B = [(1,0,1), (1,0,0)]

I hope to perform dot product between each vector elementwise so that the output is

C = [2, 0]

How can I do this in python?

like image 728
Ka-Wa Yip Avatar asked Jun 07 '16 04:06

Ka-Wa Yip


3 Answers

The fastest method here is using einsum

out = numpy.einsum('ij, ij->i', A, B)

It outperforms the multiply-add version by a factor of 2; the list comprehension version is a few hundred times slower.

enter image description here


Code to reproduce the plot:

import numpy
import perfplot

perfplot.show(
    setup=lambda n: (numpy.random.rand(n, 3), numpy.random.rand(n, 3)),
    kernels=[
        lambda data: numpy.einsum("ij, ij->i", data[0], data[1]),
        lambda data: numpy.multiply(data[0], data[1]).sum(1),
        lambda data: [
            sum(ai * bi for ai, bi in zip(a, b)) for a, b in zip(data[0], data[1])
        ],
    ],
    labels=["einsum", "multiply+sum", "sum+zip"],
    n_range=[2 ** k for k in range(18)],
    xlabel="len(a)",
)
like image 74
Nico Schlömer Avatar answered Nov 15 '22 10:11

Nico Schlömer


In pure Python, try a nested list/generator comprehension:

>>> [sum(ai * bi for ai, bi in zip(a, b))
...  for a, b in zip(A, B)]
[2, 0]

or with numpy, you can do an element-wise product of the 2-dimensional arrays, followed by a sum along each row:

>>> import numpy as np
>>> np.multiply(A, B).sum(1)
array([2, 0])

Note that the numpy solution will only work if all vectors are the same length – each list of vectors is implicitly converted into a two-dimensional matrix.

like image 39
jakevdp Avatar answered Nov 15 '22 12:11

jakevdp


We can use zipping, summing, and list comprehensions for a fancy one-liner:

A = [(1,1,1), (0,1,1)]
B = [(1,0,1), (1,0,0)]
C = [sum(i*j for i, j in zip(a, b)) for a, b in zip(A, B)]
print(C)  # [2, 0]
like image 26
Adriano Avatar answered Nov 15 '22 11:11

Adriano