给出两个大的numpy数组,一个用于3D点列表,另一个用于转换矩阵列表。假设两个列表之间存在1对1的对应关系,我正在寻找计算由其相应矩阵转换的每个点的结果数组的最佳方法。
我这样做的解决方案是使用切片(参见下面的示例代码中的“test4”),它适用于小型数组,但由于我的方法浪费多少而导致大型数组失败:)
import numpy as np
COUNT = 100
matrix = np.random.random_sample((3,3,)) # A single matrix
matrices = np.random.random_sample((COUNT,3,3,)) # Many matrices
point = np.random.random_sample((3,)) # A single point
points = np.random.random_sample((COUNT,3,)) # Many points
# Test 1, result of a single point multiplied by a single matrix
# This is as easy as it gets
test1 = np.dot(point,matrix)
print 'done'
# Test 2, result of a single point multiplied by many matrices
# This works well and returns a transformed point for each matrix
test2 = np.dot(point,matrices)
print 'done'
# Test 3, result of many points multiplied by a single matrix
# This works also just fine
test3 = np.dot(points,matrix)
print 'done'
# Test 4, this is the case i'm trying to solve. Assuming there's a 1-1
# correspondence between the point and matrix arrays, the result i want
# is an array of points, where each point has been transformed by it's
# corresponding matrix
test4 = np.zeros((COUNT,3))
for i in xrange(COUNT):
test4[i] = np.dot(points[i],matrices[i])
print 'done'
使用小数组,这很好用。对于大型数组,(COUNT = 1000000)测试#4有效,但速度相当慢。
有没有办法让测试#4更快?假设不使用循环?
答案 0 :(得分:2)
您可以使用numpy.einsum
。这是一个包含5个矩阵和5个点的例子:
In [49]: matrices.shape
Out[49]: (5, 3, 3)
In [50]: points.shape
Out[50]: (5, 3)
In [51]: p = np.einsum('ijk,ik->ij', matrices, points)
In [52]: p[0]
Out[52]: array([ 1.16532051, 0.95155227, 1.5130032 ])
In [53]: matrices[0].dot(points[0])
Out[53]: array([ 1.16532051, 0.95155227, 1.5130032 ])
In [54]: p[1]
Out[54]: array([ 0.79929572, 0.32048587, 0.81462493])
In [55]: matrices[1].dot(points[1])
Out[55]: array([ 0.79929572, 0.32048587, 0.81462493])
上面的内容正在matrix[i] * points[i]
(即在右侧相乘),但我只是重新阅读了问题,发现您的代码使用了points[i] * matrix[i]
。您可以通过切换einsum
:
In [76]: lp = np.einsum('ij,ijk->ik', points, matrices)
In [77]: lp[0]
Out[77]: array([ 1.39510822, 1.12011057, 1.05704609])
In [78]: points[0].dot(matrices[0])
Out[78]: array([ 1.39510822, 1.12011057, 1.05704609])
In [79]: lp[1]
Out[79]: array([ 0.49750324, 0.70664634, 0.7142573 ])
In [80]: points[1].dot(matrices[1])
Out[80]: array([ 0.49750324, 0.70664634, 0.7142573 ])
答案 1 :(得分:0)
拥有多个变换矩阵没有多大意义。您可以像this question中一样组合转换矩阵:
如果我想应用矩阵A,那么B,然后是C,我将以相反的顺序乘以矩阵np.dot(C,np.dot(B,A))
因此,您可以通过预先计算该矩阵来节省一些内存空间。然后应该将一堆矢量应用于一个变换矩阵应该很容易处理( in reason )。
我不知道为什么你需要在一百万个载体上进行一百万次转换,但我建议购买更大的RAM。
修改强> 没有办法减少操作,没有。除非您的转换矩阵具有特定属性,例如稀疏性,对角性等,否则您将不得不运行所有乘法和求和。但是,处理这些操作的方式可以跨核心和/或使用GPU上的向量操作进行优化。
另外,python显然很慢。您可以尝试使用NumExpr在您的核心之间拆分numpy。或者也许在C ++上使用BLAS框架(特别是快速;))