우리는 대형 데이터 세트 및 메모리로 작업 한
접근 번호는 문제입니다, 그래서 루프 내에서 계산을 최적화하기 위해 노력할 것입니다. 이제, 우리는과 같이, np.argsort
과 실제 정렬 대신에 np.linalg.norm
부분 np.argpartition
를 대체 할 np.einsum
을 사용할 수 있습니다 -
가
out = np.empty((m,))
for i, ps in enumerate(p_fine):
subs = ps-p
sq_dists = np.einsum('ij,ij->i',subs,subs)
out[i] = data_coarse[np.argpartition(sq_dists,k)[:k]].sum()
out = out/k
접근 # 2
이제 다른 방법으로 우리는 또한 대한 Scipy's cdist
을 사용할 수 있습니다
그러나 여기에 메모리가 바인딩되어 있으므로 이러한 작업을 수행 할 수 있습니다. ns 청크. 기본적으로, 우리는 행이 수백만 개이고 cdist
을 사용하는 키가 큰 배열 p_fine
에서 행을 가져 와서 각 반복마다 단 하나의 스칼라가 아닌 출력 요소의 덩어리를 얻습니다. 이것으로 루프 카운트를 그 청크의 길이만큼 자른다.
out = np.empty((m,))
L = 10 # Length of chunk (to be used as a param)
num_iter = m//L
for j in range(num_iter):
p_fine_slice = p_fine[L*j:L*j+L]
out[L*j:L*j+L] = data_coarse[np.argpartition(cdist\
(p_fine_slice,p),k,axis=1)[:,:k]].mean(1)
런타임 테스트
설정 - -
# Setup inputs
m,n = 20000,100
p_fine = np.random.rand(m,3)
p = np.random.rand(n,3)
data_coarse = np.random.rand(n)
k = 5
def original_approach(p,p_fine,m,n,k):
data_fine = np.empty((m,))
for i, ps in enumerate(p_fine):
data_fine[i] = np.mean(data_coarse[np.argsort(np.linalg.norm\
(ps-p,axis=1))[:k]])
return data_fine
def proposed_approach(p,p_fine,m,n,k):
out = np.empty((m,))
for i, ps in enumerate(p_fine):
subs = ps-p
sq_dists = np.einsum('ij,ij->i',subs,subs)
out[i] = data_coarse[np.argpartition(sq_dists,k)[:k]].sum()
return out/k
def proposed_approach_v2(p,p_fine,m,n,k,len_per_iter):
L = len_per_iter
out = np.empty((m,))
num_iter = m//L
for j in range(num_iter):
p_fine_slice = p_fine[L*j:L*j+L]
out[L*j:L*j+L] = data_coarse[np.argpartition(cdist\
(p_fine_slice,p),k,axis=1)[:,:k]].sum(1)
return out/k
타이밍 -
In [134]: %timeit original_approach(p,p_fine,m,n,k)
1 loops, best of 3: 1.1 s per loop
In [135]: %timeit proposed_approach(p,p_fine,m,n,k)
1 loops, best of 3: 539 ms per loop
In [136]: %timeit proposed_approach_v2(p,p_fine,m,n,k,len_per_iter=100)
10 loops, best of 3: 63.2 ms per loop
In [137]: %timeit proposed_approach_v2(p,p_fine,m,n,k,len_per_iter=1000)
10 loops, best of 3: 53.1 ms per loop
In [138]: %timeit proposed_approach_v2(p,p_fine,m,n,k,len_per_iter=2000)
10 loops, best of 3: 63.8 ms per loop
,691
그래서, 마침내 우리는 지금 같은 구현을 할 것이다
그래서, 1000
에서 len_per_iter
PARAM 세트 달콤한 자리에서 두 번째로 원래의 접근 방식을 통해 약 2x
처음 제안 된 접근 방식 개선과 20x
있다. 바라기를 이것은 당신의 25 분 런타임을 조금 넘게 가져올 것입니다. 나는 그렇게 생각하지 않는다!
거기에 [가까운 이웃 회귀]를 사용할 수없는 이유가 있습니다. (http://scikit-learn.org/stable/modules/generated/sklearn.nei ghbors.KNeighborsRegressor.html) sklearn에 있습니까? 아마 손으로하는 것보다 훨씬 더 효율적입니다. – benten
미세 메쉬의 포인트를 넘는 루프는 벡터화 될 수 없기 때문에 numpy가 그런 종류의 일을 수행하는 좋은 모듈이 아니라고 생각합니다. 수작업으로 코드를 작성해야하는 경우 Cython을 사용하고 명시 적 for 루프로 작업하는 것이 좋습니다. –
정확하게 이해한다면'p'와'p_fine'은 메쉬입니다. 메쉬가 일반적으로 구조화되어 있기 때문에 공간 데이터 검색 속도가 빠른 다른 데이터 구조 (예 : kD 트리)로 전환하면 훨씬 빨라집니다. –