pythonprotein
pythonprotein

Reputation: 47

Quickly rotating list of points in Python

I have a list (L1) of points and a rotation matrix (R1) made using numpy as shown below

L1 = [[1.1,2.3,-5.5],[3.4,2.0,3.0]]
R1 = [[ 0.99214145 -0.09280282 -0.08392241]
 [-0.09280282 -0.09592336 -0.99105315]
 [ 0.08392241  0.99105315 -0.10378191]]

I would like to rotate each point in L1 using R1, but instead of two points, I have >1000000 points in L1.

I have used the following code to do the rotations but they take in excess of 8 minutes for 30 lists like L1 and I would like to know if there is any faster way using numpy or any other module. Thank you so much.

#make new list of rotated points
rotatedpoints = []
#do the inverse rotation for each point in dome
for point in L1:
        rotatedpoint = list((np.dot(R1, point)) )
        rotatedpoints.append(rotatedpoint)

Upvotes: 1

Views: 1540

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477607

You can perform matrix multiplication here, basically matrix multiplication is the same as vector multiplication for each row:

You can thus obtain the result for your rotatedpoints as in your sample program with:

rotatedpoints = L1 @ np.transpose(R1)

Your rotatedpoints had as result:

>>> rotatedpoints
[[1.3394823640000002, 5.1280854950000005, 2.942537401], [2.93590806, -3.4805357580000003, 1.956096764]]

The matrix multiplication has as result:

>>> L1 @ np.transpose(R1)
array([[ 1.33948236,  5.1280855 ,  2.9425374 ],
       [ 2.93590806, -3.48053576,  1.95609676]])

With L1 a list of lists of floats with shape 1'000'000×3, and for 10 runs, we get as benchmarks:

>>> timeit(f, number=10)
5.256122357001004

We thus can rotate 1'000'000 points on average in 525 milliseconds (this includes converting L1 and R1 to numpy arrays), or approximately 0.5μs per vector.

Upvotes: 1

altunyurt
altunyurt

Reputation: 2946

EDIT:

numpy operates on np arrays much faster. Consider converting your lists to numpy arrays.

In [72]: L1                                                                                     
Out[72]: [[1.1, 2.3, -5.5], [3.4, 2.0, 3.0]]

In [73]: R1                                                                                     
Out[73]: 
[[0.99214145, -0.09280282, -0.08392241],
 [-0.09280282, -0.09592336, -0.99105315],
 [0.08392241, 0.99105315, -0.10378191]]

In [75]: %timeit np.dot(L1, R1)                                                                 
7.81 µs ± 30 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [76]: L2 = np.array(L1)                                                                      

In [78]: R2 = np.array(R1)                                                                      

In [79]: %timeit np.dot(L2, R2)                                                                 
1.51 µs ± 7.72 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [80]: %timeit L2 @ R2                                                                        
3.35 µs ± 12.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

OLD ANSWER:

You may consider applying your own dot product function too.

In [8]: from operator import mul

In [11]: %timeit sum(map(mul, L1[0], R1[0])) # just to  see how long it takes                                                    
873 ns ± 1.82 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [6]: %timeit np.dot(L1[0], R1)                                                               
5.63 µs ± 29.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

I'm not into numpy much, there might be more optimal solutions though, but one thing for sure is np shines where you have huge amounts of data to operate on. If you're dealing with relatively small arrays etc, handmade solutions might be better options.

Upvotes: 1

Related Questions