2016-12-20 91 views
2

我需要对numpy数组进行逻辑迭代,其值取决于其他数组的元素。我已经编写了下面的代码来澄清我的问题。任何建议来解决这个问题,而不是循环?在numpy数组中无循环迭代

Code 
a = np.array(['a', 'b', 'a', 'a', 'b', 'a']) 
b = np.array([150, 154, 147, 126, 148, 125]) 
c = np.zeros_like(b) 
c[0] = 150 
for i in range(1, c.size): 
    if a[i] == "b": 
     c[i] = c[i-1] 
    else: 
     c[i] = b[i] 

回答

2

下面是使用的np.maximum.accumulatenp.where的组合来创建阶梯式指数将被以一定的间隔停止,然后简单地进行索引b会给我们所需的输出的方法。

因此,实现将是 -

mask = a!="b" 
idx = np.maximum.accumulate(np.where(mask,np.arange(mask.size),0)) 
out = b[idx] 

样一步一步的运行 -

In [656]: # Inputs 
    ...: a = np.array(['a', 'b', 'a', 'a', 'b', 'a']) 
    ...: b = np.array([150, 154, 147, 126, 148, 125]) 
    ...: 

In [657]: mask = a!="b" 

In [658]: mask 
Out[658]: array([ True, False, True, True, False, True], dtype=bool) 

# Crux of the implmentation happens here : 
In [696]: np.where(mask,np.arange(mask.size),0) 
Out[696]: array([0, 0, 2, 3, 0, 5]) 

In [697]: np.maximum.accumulate(np.where(mask,np.arange(mask.size),0)) 
Out[697]: array([0, 0, 2, 3, 3, 5])# Stepped indices "intervaled" at masked places 

In [698]: idx = np.maximum.accumulate(np.where(mask,np.arange(mask.size),0)) 

In [699]: b[idx] 
Out[699]: array([150, 150, 147, 126, 126, 125]) 
1

你可以使用一个更加量化的方法,像这样:

np.where(a == "b", np.roll(c, 1), b) 

如果条件为,np.where将采用np.roll(c, 1)中的元素如果条件是False,则需要从bnp.roll(c, 1)将“滚动”c的所有元素1,以便每个元素指的是c[i-1]

这些类型的操作使numpy非常宝贵。如果可能的话,应该避免循环。

+0

这是一个简单而简洁的解决方案。但是,为什么它返回[150 0 147 126 0 125]?它不会从'b'数组中得到值,其中a [i] =“b”。 –

+0

我误解了这个问题,如果你已经拥有所有'c'的元素,但是你通过循环来填充它,所以它比这更复杂一点 – pbreach

0

如果您不需要环绕缘有一个非常简单的解决方案:

a = np.array(['a', 'b', 'a', 'a', 'b', 'a']) 
b = np.array([150, 154, 147, 126, 148, 125]) 
c = b.copy() #removes necessity of else case 
c[a[:-1]=='b'] = c[a[1:]=='b'] 

或相等:

a = np.array(['a', 'b', 'a', 'a', 'b', 'a']) 
b = np.array([150, 154, 147, 126, 148, 125]) 
c = b.copy() #removes necessity of else case 
mask = a == 'b' 
c[mask[:-1]] = c[mask[1:]] 

如果你想环绕保证金(a[0]=='b')那么它会变得更复杂一些,你可能需要使用roll,或者先用if来抓这个案例。