2016-12-20 3 views
2

numpy 배열보다 논리적 인 반복이 필요하다.이 값은 다른 배열의 요소에 의존한다. 내 문제를 명확히하기 위해 아래 코드를 작성했습니다. for 루프없이이 문제를 해결하기위한 제안이 있습니까?numpy 배열에서 for 루프없이 반복하기

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

여기 특정 간격 멈추고 단순히 우리가 원하는 출력을 제공 할 b로 인덱싱 따른다 단차 인덱스를 만드는 np.maximum.accumulatenp.where의 조합을 이용하는 방법이다.

따라서, 구현 될 것이다 -

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 인 경우 b에서 가져옵니다. np.roll(c, 1)은 각 요소가 c[i-1]을 가리 키도록 c의 모든 요소를 ​​1만큼 "롤"할 것입니다.

이러한 유형의 작업으로 인해 numpy가 매우 중요합니다. 가능하면 루핑을 피해야합니다.

+0

간단하고 간결한 솔루션입니다. 그러나 왜 그것이 [150 0 147 126 0 125]를 반환합니까? a [i] = "b"인 경우 '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과 함께 사용해야합니다.