简体   繁体   English

以不同方式切片numpy数组的不同行

[英]Slicing different rows of a numpy array differently

I'm working on a Monte Carlo radiative transfer code, which simulates firing photons through a medium and statistically modelling their random walk. 我正在研究蒙特卡洛(Monte Carlo)辐射转移代码,该代码可以模拟通过介质激发光子并对其随机游动进行统计建模。 It runs slowly firing one photon at a time, so I'd like to vectorize it and run perhaps 1000 photons at once. 它一次运行缓慢地发射一个光子,所以我想对其进行矢量化处理,一次运行1000个光子。

I have divided my slab through which the photons are passing into nlayers slices between optical depth 0 and depth . 我将光子穿过的nlayers分成了光学深度0depth之间的n nlayers切片。 Effectively, that means that I have nlayers + 2 regions ( nlayers plus the region above the slab and the region below the slab). 有效地,这意味着我具有nlayers + 2区域( nlayers加上平板上方的区域和平板下方的区域)。 At each step, I have to keep track of which layers each photon passes through. 在每一步中,我都必须跟踪每个光子穿过的层。

Let's suppose that I already know that two photons start in layer 0. One takes a step and ends up in layer 2, and the other takes a step and ends up in layer 6. This is represented by an array pastpresent that looks like this: 让我们假设我已经知道两个光子从第0层开始。一个光子pastpresent第2层,另一个pastpresent第6层。这由数组pastpresent表示,如下所示:

[[ 0 2]
 [ 0 6]]

I want to generate an array traveled_through with (nlayers + 2) columns and 2 rows, describing whether photon i passed through layer j (endpoint-inclusive). 我要生成的阵列traveled_through(nlayers + 2)列和2行,描述是否光子i通过层传递j (端点包)。 It would look something like this (with nlayers = 10 ): 看起来像这样( 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]]

I could do this by iterating over the photons and generating each row of traveled_through individually, but that's rather slow, and sort of defeats the point of running many photons at once, so I'd rather not do that. 我可以通过遍历光子并分别生成每一行traveled_through来做到这一点,但这相当慢,并且无法同时运行多个光子,因此我宁愿不这样做。

I tried to define the array as follows: 我试图定义数组如下:

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

The idea was that in a given photon's row, the indices from the starting layer through and including the ending layer would be set to 1, with all others remaining 0. However, I get the following error: 这个想法是,在给定的光子行中,从起始层到结束层(包括结束层)的索引将设置为1,所有其他索引都保持为0。但是,出现以下错误:

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

My best guess is that numpy does not allow different rows of an array to be indexed differently using this method. 我最好的猜测是numpy不允许使用此方法对数组的不同行进行不同的索引。 Does anyone have suggestions for how to generate traveled_through for an arbitrary number of photons and an arbitrary number of layers? 是否有人建议如何为任意数量的光子和任意数量的层生成traveled_through

If the two photons always start at 0, you could perhaps construct your array as follows. 如果两个光子始终从0开始,则可以按以下方式构造阵列。

First setting the variables... 首先设置变量...

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

...and then constructing the array: ...然后构造数组:

>>> (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]])

Or if the photons have an arbitrary starting layer: 或者,如果光子具有任意的起始层:

>>> 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]])

A little trick I kind of like for this kind of thing involves the accumulate method of the logical_xor ufunc: 对于这种事情,我有点喜欢的技巧涉及logical_xor ufunc的accumulate方法:

>>> 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])

Note that this sets to 1 the entries between the positions in b , first index inclusive, last index exclusive, so you have to handle off by 1 errors depending on what exactly you are after. 请注意,这会将b的位置(包括第一个索引,包括最后一个索引)中的位置之间的条目设置为1 ,因此您必须根据所要执行的操作来处理1个错误。

With several rows, you could make it work as: 通过几行,您可以使其工作如下:

>>> 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]])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM