3

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

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

然后,我发现对大型数组使用追加需要更多时间,然后我更改了如下代码:

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],[],[],[]....[]], 
        [[],[],[],[]....[]],
        [[],[],[],[]....[]]......,
        [[],[],[],[]....[]] ])
4

3 回答 3

2

问题中新轴版本的解释:这些不是矩阵乘法,ndarray 乘法是逐个元素乘法与广播. 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 的数组的次数与另一个数组的对应维度一样多”。这会以一种非常有效的方式产生一个形状为 (num_steps x num_points x num_dimensions) 的 ndarray;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 x num_dimensions 的 ndarray 沿轴 = 1 求和产生具有 num_points 的结果,这是正确的。

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

于 2012-11-16T13:14:00.827 回答
1

我不是通过理解你写的所有东西,但我已经可以告诉你一些事情;也许他们有帮助。

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

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

>>> array([ 7,8,9 ])[:,newaxis]
array([[7],
       [8],
       [9]])
>>> array([ 7,8,9 ])[newaxis,:]
array([[7, 8, 9]])

(多维值的维度当然是用数组的嵌套来表示的。)

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

于 2012-11-16T11:02:01.520 回答
0

newaxis 以这样的方式重塑数组,以便当您乘以 numpy 时使用广播。这是一个很好的广播教程

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

于 2012-11-17T03:56:12.163 回答