什么是创建转换矩阵的numpy数组的正确方法

时间:2015-09-14 21:01:18

标签: python arrays performance numpy matrix

给出一个旋转角度列表(比如说X轴):

import numpy as np
x_axis_rotations = np.radians([0,10,32,44,165])

我可以创建一个匹配这些角度的矩阵数组:

matrices = []
for angle in x_axis_rotations:
    matrices.append(np.asarray([[1 , 0 , 0],[0, np.cos(angle), -np.sin(angle)], [0, np.sin(angle), np.cos(angle)]]))
matrices = np.array(matrices)

这样可以工作,但它没有利用numpy的优势来处理大型数组...所以如果我的角度数组是数百万,那么这样做也不会很快。

是否有更好(更快)的方法从输入数组创建变换矩阵数组?

2 个答案:

答案 0 :(得分:3)

这是一种直接而简单的方法:

c = np.cos(x_axis_rotations)
s = np.sin(x_axis_rotations)
matrices = np.zeros((len(x_axis_rotations), 3, 3))
matrices[:, 0, 0] =  1
matrices[:, 1, 1] =  c
matrices[:, 1, 2] = -s
matrices[:, 2, 1] =  s
matrices[:, 2, 2] =  c

时间,好奇:

In [30]: angles = 2 * np.pi * np.random.rand(1000)

In [31]: timeit OP(angles)
100 loops, best of 3: 5.46 ms per loop

In [32]: timeit askewchan(angles)
10000 loops, best of 3: 39.6 µs per loop

In [33]: timeit divakar(angles)
10000 loops, best of 3: 93.8 µs per loop

In [34]: timeit divakar_oneline(angles)
10000 loops, best of 3: 56.1 µs per loop

In [35]: timeit divakar_combine(angles)
10000 loops, best of 3: 43.9 µs per loop

所有这些都比你的循环快得多,所以请使用你最喜欢的那个:)

答案 1 :(得分:2)

您可以使用linear indexing来提供帮助,就像这样 -

# Get cosine and sine values in one-go
cosv = np.cos(x_axis_rotations)
sinv = np.sin(x_axis_rotations)

# Get size parameter
N = x_axis_rotations.size

# Initialize output array
out = np.zeros((N,3,3))

# Set the first element in each 3D slice as 1
out[:,0,0] = 1

# Calculate the first of positions where cosine valued elements are to be put
idx1 = 4 + 9*np.arange(N)[:,None]

# One by one put those 4 values in 2x2 blocks across all 3D slices
out.ravel()[idx1] = cosv
out.ravel()[idx1+1] = -sinv

out.ravel()[idx1+3] = sinv
out.ravel()[idx1+4] = cosv

或者,您可以在使用zeros初始化输出数组后一次性设置元素,并将每个切片中的第一个元素设置为1,如此 -

out.reshape(N,-1)[:,[4,5,7,8]] = np.column_stack((cosv,-sinv,sinv,cosv))

在上面提到的两种方法之间,还有两个 middleground 方法可以演变,再次在用零初始化并将每个3D切片中的第一个元素设置为1之后立即进行,就像这样 -

out.reshape(N,-1)[:,[4,8]] = cosv[:,None]
out.reshape(N,-1)[:,[5,7]] = np.column_stack((-sinv[:,None],sinv[:,None]))

最后一个是 -

out.reshape(N,-1)[:,[4,8]] = cosv[:,None]
out.reshape(N,-1)[:,5] = -sinv
out.reshape(N,-1)[:,7] = sinv