使用newaxis进行for循环的Python时间优化

时间:2012-11-16 09:49:22

标签: python time for-loop numpy

我需要沿着定义的线(3D)以相等的间距计算n个点(3D)。 我知道线的起点和终点。首先,我用了

for k in range(nbin):
  step = k/float(nbin-1)
  bin_point.append(beam_entry+(step*(beamlet_intersection-beam_entry)))

然后,我发现使用append for large arrays需要更多时间,然后我改变了代码:

bin_point = [start_point+((k/float(nbin-1))*(end_point-start_point)) for k in range(nbin)]

我得到一个建议,使用newaxis将进一步缩短时间。 修改后的代码看起来像这样。

step      = arange(nbin) / float(nbin-1)
bin_point = start_point + ( step[:,newaxis,newaxis]*((end_pint - start_point))[newaxis,:,:] )  

但是,我无法理解newaxis函数,我也怀疑,如果start_point和end_point的结构或形状发生了变化,相同的代码是否会起作用。同样,我如何使用newaxis mdoify以下代码

 for j in range(32):      # for all los
   line_dist[j] = sqrt([sum(l) for l in (end_point[j]-start_point[j])**2])

很抱歉这么笨重,更清楚start_point和end_point的结构是

array([ [[1,1,1],[],[],[]....[]], 
        [[],[],[],[]....[]],
        [[],[],[],[]....[]]......,
        [[],[],[],[]....[]] ])

3 个答案:

答案 0 :(得分:2)

问题中对newaxis版本的解释:这些是矩阵乘法,ndarray乘法是逐个元素乘以broadcasting。 step [:,newaxis,newaxis]为num_steps x 1 x 1,point [newaxis,:,:]为1 x num_points x num_dimensions。将形状(num_steps x 1 x 1)和(1 x num_points x num_dimensions)的ndarray一起广播将起作用,因为广播规则是每个维度应该是1或相同;它只是意味着“使用维度1重复数组的次数与其他数组的相应维度一样多”。这导致具有形状的ndarray(num_steps x num_points x num_dimensions)以非常有效的方式; i,j,k下标将是沿第j行的第i步的第k个坐标(由第j对起点和终点给出)。

操作实例:

>>> start_points = numpy.array([[1, 0, 0], [0, 1, 0]])
>>> end_points = numpy.array([[10, 0, 0], [0, 10, 0]])
>>> steps = numpy.arange(10)/9.0
>>> start_points.shape
(2, 3)
>>> steps.shape
(10,)
>>> steps[:,numpy.newaxis,numpy.newaxis].shape
(10, 1, 1)
>>> (steps[:,numpy.newaxis,numpy.newaxis] * start_points).shape
(10, 2, 3)
>>> (steps[:,numpy.newaxis,numpy.newaxis] * (end_points - start_points)) + start_points
array([[[  1.,   0.,   0.],
        [  0.,   1.,   0.]],
       [[  2.,   0.,   0.],
        [  0.,   2.,   0.]],
       [[  3.,   0.,   0.],
        [  0.,   3.,   0.]],
       [[  4.,   0.,   0.],
        [  0.,   4.,   0.]],
       [[  5.,   0.,   0.],
        [  0.,   5.,   0.]],
       [[  6.,   0.,   0.],
        [  0.,   6.,   0.]],
       [[  7.,   0.,   0.],
        [  0.,   7.,   0.]],
       [[  8.,   0.,   0.],
        [  0.,   8.,   0.]],
       [[  9.,   0.,   0.],
        [  0.,   9.,   0.]],
       [[ 10.,   0.,   0.],
        [  0.,  10.,   0.]]])

如您所见,这会产生正确答案:)在这种情况下,广播(10,1,1)和(2,3)会产生(10,2,3)。你所拥有的是广播(10,1,1)和(1,2,3),这是完全相同的,也产生(10,2,3)。

问题的距离部分的代码不需要newaxis:输入是num_points x num_dimensions,输出是num_points,因此必须删除一个维度。这实际上是你总结的轴。这应该有效:

line_dist = numpy.sqrt( numpy.sum( (end_point - start_point) ** 2, axis=1 )

这里numpy.sum(...,axis = 1)表示仅沿该轴的总和,而不是所有元素:形状为num_points的ndarray x沿轴= 1总和的num_dimensions产生带有num_points的结果,这是正确的。

编辑:删除没有广播的代码示例。 编辑:修正了索引的顺序。 编辑:添加了line_dist

答案 1 :(得分:1)

我不是通过理解你写的所有内容,而是我已经可以告诉你的一些事情;也许他们会帮忙。

newaxis是一个标记,而不是一个函数(事实上,它是普通的None)。它用于将(未使用的)维度添加到多维值。有了它,您可以使用2D值(甚至更多)制作3D值。输入值中已存在的每个维度必须由索引中的冒号:表示(假设您要使用所有值,否则它将超出我们的用例),要添加的维度由{{表示1}}。

例:
输入是一维向量(1D):1,2,3
输出应为矩阵(2D) 有两种方法可以实现这一目标;向量可以用每个值填充一行,或者向量可以只填充矩阵的第一行和唯一行。第一个由newaxis创建,第二个由vector[:,newaxis]创建。结果:

vector[newaxis,:]

(当然,多维值的维度由数组的嵌套表示。)

如果输入中有更多维度,请多次使用冒号(否则将忽略更深的嵌套维度,即将数组视为简单值)。我不会粘贴这里的表示,因为当使用嵌套括号在2D显示器上写入3D和4D值时,由于光学复杂性,它不会澄清事物。无论如何,我希望它变得清晰。

答案 2 :(得分:0)

newaxis以这样的方式重新整形数组,这样当你多次使用numpy时就会使用广播。 Here is a good tutorial on broadcasting

step[:, newaxis, newaxis]step.reshape((step.shape[0], 1, 1))相同(如果step为1d)。重塑的任何一种方法都应该非常快,因为在numpy中重新整形数组非常简单,它只是查看数组,特别是因为你应该只进行一次。