기본적으로 (1,2,3,...)
의 범위를 다음 non-NaN
까지 만듭니다. 아래 그림과 같이 이러한 경우를 해결하기 위해, 우리는 각 행에 대한 몇 가지 diff
+ cumsum
마법을 사용할 수 있습니다 -
def closest_distance_per_row(a):
m0 = np.ones(a.shape,dtype=int)
mask = ~np.isnan(a)
for i,item in enumerate(a):
idx = np.flatnonzero(mask[i])
if len(idx)>0:
m0[i,:idx[0]] = 0
m0[i,idx[1:]] = idx[:-1] - idx[1:] +1
out = np.full(a.shape,np.nan,dtype=float)
out[:,1:] = m0[:,:-1].cumsum(1)
out[out==0] = np.nan
out[~mask.any(1)] = np.nan
return out
샘플 실행 -
In [353]: a
Out[353]:
array([[ 1., 3., 5., 8., 6.],
[ 3., nan, nan, 5., 6.],
[ nan, 6., 7., nan, 2.]])
In [354]: closest_distance_per_row(a)
Out[354]:
array([[ nan, 1., 1., 1., 1.],
[ nan, 1., 2., 3., 1.],
[ nan, nan, 1., 1., 2.]])
In [343]: a
Out[343]:
array([[ nan, nan, nan, nan, nan, nan, 4., nan, 3., 1.],
[ nan, nan, 6., nan, nan, nan, nan, nan, nan, nan],
[ 0., nan, 2., nan, 1., nan, 0., nan, nan, nan],
[ 3., nan, 2., nan, 8., 6., nan, 4., 2., nan],
[ nan, 0., nan, nan, nan, nan, nan, nan, nan, nan],
[ nan, nan, 2., nan, 0., nan, nan, 1., nan, nan]])
In [344]: closest_distance_per_row(a)
Out[344]:
array([[ nan, nan, nan, nan, nan, nan, nan, 1., 2., 1.],
[ nan, nan, nan, 1., 2., 3., 4., 5., 6., 7.],
[ nan, 1., 2., 1., 2., 1., 2., 1., 2., 3.],
[ nan, 1., 2., 1., 2., 1., 1., 2., 1., 1.],
[ nan, nan, 1., 2., 3., 4., 5., 6., 7., 8.],
[ nan, nan, nan, 1., 2., 1., 2., 3., 1., 2.]])
런타임 테스트 -
In [4]: a = np.random.randint(0,9,(5000,5000)).astype(float)
In [5]: a.ravel()[np.random.choice(a.size, int(a.size*0.5), replace=0)] = np.nan
In [6]: %timeit two_loops(a)
1 loops, best of 3: 16.7 s per loop
In [7]: %timeit closest_distance_per_row(a)
1 loops, best of 3: 339 ms per loop
In [8]: 16700/339.0 # Speedup with one loop (proposed in this post) over two loops
Out[8]: 49.26253687315634
당신이 더 빠르지는 않겠지 만, 목록을 작성한 다음 변환하는 대신에'distance' 함수에 배열을 미리 할당하여 꽤 많이 내 솔루션의 런타임을 향상시킬 수 있습니다 배열로. – JohanL
@JohanL 코드를 업데이트하려는 경우 타이밍을 업데이트 해 주어서 기쁩니다. 너 한테 알려줘. – Divakar
그레이트 솔루션! 두 가지 해결책이 모두 포함되어 있으므로 최선의 답변으로 표시하겠습니다. @ JohanL, 만약 당신의 업데이 트를 얻을 것이라고, 나는이 대답뿐만 아니라 편집 할 수있을 것 같아요. 둘 다 감사합니다! – Kristof