不同地切片numpy数组的不同行

时间:2014-11-21 18:35:54

标签: python arrays numpy indexing

我正在研究蒙特卡罗辐射传输代码,该代码模拟通过介质发射光子并对其随机行走进行统计建模。它一次慢慢地发射一个光子,所以我想对它进行矢量化并一次运行1000个光子。

我将我的平板分开,光子通过该平板进入光学深度nlayers0之间的depth切片。实际上,这意味着我有nlayers + 2个区域(nlayers加上板块上方的区域和板块下方的区域)。在每一步,我都要跟踪每个光子通过的层。

假设我已经知道两个光子从第0层开始。一个步骤结束,第二个结束,另一个步骤结束,第六层结束。这表示为数组pastpresent看起来像这样:

[[ 0 2]
 [ 0 6]]

我想生成一个数组traveled_through,其中包含(nlayers + 2)列和2行,描述光子i是否通过了层j(包含端点)。它看起来像这样(nlayers = 10):

[[ 1 1 1 0 0 0 0 0 0 0 0 0]
 [ 1 1 1 1 1 1 1 0 0 0 0 0]]

我可以通过迭代光子并单独生成traveled_through的每一行来做到这一点,但这相当慢,并且有点击败了同时运行多个光子的点,所以我&#39 ;而不是那样做。

我尝试按如下方式定义数组:

traveled_through = np.zeros((2, nlayers)).astype(int)
traveled_through[ : , np.min(pastpresent, axis = 1) : np.max(pastpresent, axis = 1) + ] = 1

这个想法是,在一个给定的光子行中,从起始层到包括结束层的索引将被设置为1,其他所有其他值保持为0.但是,我得到以下错误:< / p>

traveled_through[ : , np.min(pastpresent, axis = 1) : np.max(pastpresent, axis = 1) + 1 ] = 1
IndexError: invalid slice

我最好的猜测是numpy不允许使用此方法对数组的不同行进行不同的索引。有没有人建议如何为任意数量的光子和任意数量的层生成traveled_through

2 个答案:

答案 0 :(得分:2)

如果两个光子总是从0开始,你可以按如下方式构造你的数组。

首先设置变量......

>>> pastpresent = np.array([[0, 2], [0, 6]])
>>> nlayers = 10

...然后构建数组:

>>> (pastpresent[:,1][:,np.newaxis] + 1 > np.arange(nlayers+2)).astype(int)
array([[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]])

或者光子是否有任意起始层:

>>> pastpresent2 = np.array([[1, 7], [3, 9]])
>>> (pastpresent2[:,0][:,np.newaxis] < np.arange(nlayers+2)) & 
    (pastpresent2[:,1][:,np.newaxis] + 1 > np.arange(nlayers+2)).astype(int)       
array([[0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0]])

答案 1 :(得分:1)

我喜欢这种事情的一个小技巧涉及accumulate ufunc的logical_xor方法:

>>> a = np.zeros(10, dtype=int)
>>> b = [3, 7]
>>> a[b] = 1
>>> a
array([0, 0, 0, 1, 0, 0, 0, 1, 0, 0])
>>> np.logical_xor.accumulate(a, out=a)
array([0, 0, 0, 1, 1, 1, 1, 0, 0, 0])

请注意,这会将1中的位置设置为b,第一个包含索引,最后一个索引包含,因此您必须处理1个错误,具体取决于您的确切位置。

有几行,您可以将其设为:

>>> a = np.zeros((3, 10), dtype=int)
>>> b = np.array([[1, 7], [0, 4], [3, 8]])
>>> b[:, 1] += 1  # handle the off by 1 error
>>> a[np.arange(len(b))[:, None], b] = 1
>>> a
array([[0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
       [1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 0, 0, 0, 1]])
>>> np.logical_xor.accumulate(a, axis=1, out=a)
array([[0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 1, 1, 1, 1, 1, 0]])