2016-12-21 2 views
0

나는 numpy에 상당히 새롭다.numpy에서 if 문을 포함하는 for 루프를 벡터화하는 방법은 무엇입니까?

import numpy as np 

def get_result(S,K,delS): 
    res=np.zeros(S.shape[0],dtype=np.float64) 
    for j in range(res.shape[0]): 
     if S[j]-K>delS: 
      res[j]+=np.floor((S[j]-K)/delS) 
      K+=np.floor((S[j]-K)/delS)*delS 
     elif S[j]-K<-delS: 
      res[j]+=np.ceil((S[j]-K)/delS) 
      K+=np.ceil((S[j]-K)/delS)*delS 
    return res 

S=np.array([1.0,1.05,1.1,1.12,1.09,1.14,1.21,1.6,1.05,1.0,0.95,0.90,0.87,0.77,0.63,0.85,0.91,0.76],dtype=np.float64) 

K=1.0 
delS=0.1 

l=get_result(S,K,delS) 

for j in range(S.shape[0]): 
    print("%d\t%.2f\t%.0f" % (j,S[j],l[j])) 

get_result 함수는가 루프 그러나, 따라서 큰 입력 어색 느린 S. 이러한 기능 NumPy와의 벡터화 가능 벡터 포함 I 내게 원하는 결과를 제공하는, 다음 코드가 -통사론? 어떤 도움을 주시면 감사하겠습니다. 어레이 또는 연산 2 개 이상의 조건을 처리

+0

나는 모든 기능은 코드의 단지 세 줄에 벡터화 할 수 있다는 인상을 첫 번째,하지만 K' 루프에서 변화'것으로 나타났습니다. K [j + 1]을 계산할 때 K [j]에 대한 지식이 필요하기 때문에 반복 사이의 종속 관계가 있고 루프를 벡터화 할 수 없습니다. 적어도 내 지식의 최고. – DyZ

+0

비슷한 문제에 대한이 [답변] (http://stackoverflow.com/a/41244906/2593236)을 참조하십시오. – pbreach

+0

'Python 2.x'를 사용한다면''range'' (list를 반환합니다)를'xrange' (generator를 반환)로 대체하면 상당한 속도 향상을 보입니다. – DerWeh

답변

1

일반적인 패턴은 부울 마스크를 구성하고, 그 마스크에 해당하는 요소에 대해 하나 개의 조치를 취할 수 있으며, 이는 거짓 상이한 여기서

res=np.zeros(S.shape[0],dtype=np.float64) 
mask - S-K>delS 
res[mask] = ...S[mask] 
res[~mask] = ...S[~mask] 

변형은 np.where(mask)으로 색인을 식별하는 것입니다.

하지만 계산이 복잡해 보이는 것은 테스트가 계속 변경된다는 것입니다. 즉 j+1의 경우 Kj의 계산에서 파생됩니다.

for j in range(res.shape[0]): 
    if S[j]-K>delS: 
     res[j]+=np.floor((S[j]-K)/delS) 
     K+=np.floor((S[j]-K)/delS)*delS 
    elif S[j]-K<-delS: 
     res[j]+=np.ceil((S[j]-K)/delS) 
     K+=np.ceil((S[j]-K)/delS)*delS 

는 우리가 일반적으로 np.cumsum 또는 기타 누적 ufunc 방법을 사용하려고 반복의 종류를 처리합니다.

일반적으로 numpy 코드는 계산이 배열 (또는 배열 집합)의 모든 요소에 '평행하게'적용될 수있을 때 - 즉 계산에 가장 많이 사용되는 방식으로 가장 빠르며 가장 쉽습니다. 반복의 순서. 그런 다음 배열 추가 및 곱셈과 같은 빠른 컴파일 numpy 함수에 작업을 위임 할 수 있습니다. 계산이 본질적으로 직렬 인 경우 (j에 대한 j의 값은 j-1에 따라 다름) 이것은 더 까다로워집니다.

대충 읽기가 어렵다면, if 문은 어렵지 않습니다. 루프의 직렬 특성입니다.

=========================

주위 재생, 나는 제거 할 수 있었다 if (가 실제로 3 subcase) 하지만 여전히 반복되어야한다 :

def get_result(S,K,delS): 
    S = S/delS 
    res=np.zeros(S.shape[0],dtype=np.float64) 
    for j in range(res.shape[0]): 
     x = S[j] - K/delS 
     xa = np.floor(np.abs(x)) * np.sign(x) 
     res[j] += xa 
     K += xa*delS   
    return res 
+0

예, 모든 의견이 정확하고 도움이됩니다. – user5507059

+0

결론은 이러한 유형의 함수를 쉽게 벡터화 할 수 없다는 것입니다. 특히 루프의 이전 값에 대한 종속성이 더욱 복잡해지면 특히 그러합니다. 참고로 for 루프를 cythonize 할 것이다. 이렇게하면 코드를 빠르게 읽을 수 있습니다. – user5507059

+1

네, 이것은 cython을위한 좋은 후보자처럼 보이는데, 특히 'floor','ceiling','abs' 등의 numpy 버전을 피할 수 있다면 좋습니다. – hpaulj