2017-06-22 11 views
5

Mam tablicę takiego: tmp.shape = (128, 64, 64)dodać tylko wartość, jeśli wartość jest większa od zera w Pythonie wielowymiarowej tablicy

Liczę wszystkie zera wzdłuż osi 128 tak:

nonzeros = np.count_nonzero(tmp, axis=0) // shape = (64, 64) 

Mam tablicowej c.shape = (64, 64)

teraz chcę dodać wartości od C do tmp wzdłuż osi 128, ale tylko wtedy, gdy wartości są tmp> 0:

for i in range(tmp.shape[0]): 
    axis1 = tmp[i,:,:] 
    tmp[i, :, :] += (c/nonzeros) // only if tmp[i, :, :] > 0 

Czy można to zrobić w krótkim czasie? Czy muszę używać wielu pętli? Mam nadzieję, że ktoś może zaproponować rozwiązanie bez innej pętli

Coś jak to nie działa:

tmp[i, tmp > 0.0, tmp > 0.0] += (c/nonzeros) 

IndexError: too many indices for array

wersja długa

for i in range(tmp.shape[0]): 
    for x in range(tmp.shape[1]): 
     for y in range(tmp.shape[2]): 
      pixel = tmp[i, x, y] 
      if pixel != 0: 
       pixel += (c[x,y]/nonzeros[x,y]) 
+0

Czy którykolwiek z zamieszczonymi rozwiązań pracować dla Ciebie? – Divakar

+0

Tak, przepraszam, byłem ostatnio bardzo zajęty, więc nie odpowiedziałem od razu. – thigi

Odpowiedz

1

Cóż, zasadniczo dodajesz do nadawanej tablicy, z wyjątkiem miejsc, w których element tmp wynosi zero. Tak więc, jednym podejściem byłoby przechowywanie maski z góry, dodając w końcu c/nonzeros i wreszcie użyć maski do zresetowania elementów tmp.

Stąd realizacja byłaby -

mask = tmp==0 
tmp+= c/nonzeros 
tmp[mask] = 0 

Test Runtime

Podejścia -

# @DSM's soln 
def fast(tmp, c, nonzeros): 
    return tmp + np.where(tmp > 0, c/nonzeros, 0) 

# Proposed in this post 
def fast2(tmp, c, nonzeros): 
    mask = tmp==0 
    tmp+= c/nonzeros 
    tmp[mask] = 0 
    return tmp 

taktowania -

In [341]: # Setup inputs 
    ...: M,N = 128,64 
    ...: tmp = np.random.randint(0,10,(M,N,N)).astype(float) 
    ...: c = np.random.rand(N,N)*100 
    ...: nonzeros = np.count_nonzero(tmp, axis=0) 
    ...: 
    ...: # Make copies for testing as input would be edited with the approaches 
    ...: tmp1 = tmp.copy() 
    ...: tmp2 = tmp.copy() 
    ...: 

In [342]: %timeit fast(tmp1, c, nonzeros) 
100 loops, best of 3: 2.22 ms per loop 

In [343]: %timeit fast2(tmp2, c, nonzeros) 
1000 loops, best of 3: 1.61 ms per loop 

Krótsza alternatywa

Jeśli szukasz kompaktowego kodu, oto kolejny stosując maskę non-0s zrobić nadawanego elementu mnożenie z c/nonzeros i dodać do tmp a tym samym mieć rozwiązanie jednego-liner jak tak -

tmp += (tmp!=0)*(c/nonzeros) 

Uwaga: Aby uniknąć dzielenia przez 0, możemy edytować nonzeros na jego 0s niczym innym niż 0, powiedzmy 1 a następnie użyć zamieszczonych podejścia, tak jak -

nonzeros = np.where(nonzeros > 0, nonzeros, 1) 
+0

poprawne jest to, co powiedziałeś, ale otrzymuję to: 'RuntimeWarning: dziel przez zero napotkany w true_divide tmp + = np.where (tmp> 0, c/nonzeros, 0)' Nie otrzymuję tego z moją metodą. – thigi

+0

Czy możesz dodać to do swojego rozwiązania: nonzeros = 'np.where (nonzeros> 0, nonzeros, 1)'? Nie chcę tego edytować, ponieważ jest to twoja odpowiedź i nie chcę brać kredytu. – thigi

+0

@thigi Dzięki! Edytowane. – Divakar

1

Można użyć np.where i nadawanie. Po zamocowaniu swój przykładowy kod (dodanie do piksela nie będą modyfikować TMP),

def fast(tmp, c, nonzeros): 
    return tmp + np.where(tmp > 0, c/nonzeros, 0) 

daje mi

In [6]: tmp = np.random.randint(0, 5, (128, 64, 64)).astype(float) 
    ...: c = np.random.randint(10, 15, (64, 64)).astype(float) 
    ...: nonzeros = np.count_nonzero(tmp, axis=0) 
    ...: 

In [7]: %time slow_result = slow(tmp, c, nonzeros) 
CPU times: user 488 ms, sys: 16 ms, total: 504 ms 
Wall time: 553 ms 

In [8]: %time fast_result = fast(tmp, c, nonzeros) 
CPU times: user 4 ms, sys: 4 ms, total: 8 ms 
Wall time: 16.4 ms 

In [9]: np.allclose(slow_result, fast_result) 
Out[9]: True 

Alternatywnie, można często zastąpić np.where z mnożenia, coś jak tmp + (tmp > 0) * (c/nonzeros).

Modyfikowanie kodu w celu ochrony przed sytuacją, w której element nonzeros wynosi zero, pozostawia się jako ćwiczenie dla czytnika. ;-)

Powiązane problemy