Jak zwrócić 0 przez podzielenie przez zero

101

Próbuję wykonać mądry podział elementu w Pythonie, ale jeśli napotkano zero, potrzebuję, aby iloraz był równy zero.

Na przykład:

array1 = np.array([0, 1, 2])
array2 = np.array([0, 1, 1])

array1 / array2 # should be np.array([0, 1, 2])

Zawsze mógłbym po prostu użyć pętli for w moich danych, ale aby naprawdę wykorzystać optymalizacje numpy, potrzebuję funkcji dzielenia, która zwraca 0 po dzieleniu przez zero, zamiast ignorować błąd.

O ile czegoś nie brakuje, nie wydaje się, że numpy.seterr () może zwracać wartości w przypadku błędów. Czy ktoś ma jakieś inne sugestie, w jaki sposób mogę uzyskać najlepsze wyniki z numpy, ustawiając własną obsługę błędów dzielenia przez zero?

hlin117
źródło
W mojej wersji Pythona (Python 2.7.11 | Continuum Analytics, Inc.) jest to dokładnie taki wynik, jaki otrzymujesz. Z ostrzeżeniem.
Ramon Martinez,
Najbardziej zwięzła poprawna odpowiedź to stackoverflow.com/a/37977222/2116338
mrplants

Odpowiedzi:

187

W Numpy 1.7 + możesz skorzystać z opcji „where” dla ufuncs . Możesz robić rzeczy w jednej linii i nie musisz zajmować się menedżerem kontekstu errstate.

>>> a = np.array([-1, 0, 1, 2, 3], dtype=float)
>>> b = np.array([ 0, 0, 0, 2, 2], dtype=float)

# If you don't pass `out` the indices where (b == 0) will be uninitialized!
>>> c = np.divide(a, b, out=np.zeros_like(a), where=b!=0)
>>> print(c)
[ 0.   0.   0.   1.   1.5]

W tym przypadku oblicza dzielenie wszędzie tam, gdzie „b” nie jest równe zero. Kiedy b jest równe zero, to pozostaje niezmienione w stosunku do wartości, którą pierwotnie podałeś w argumencie „out”.

DStauffman
źródło
4
Jeśli ai / lub bmogą być tablicami całkowitymi, to jest to ta sama koncepcja, wystarczy jawnie ustawić prawidłowy typ wyjścia:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
DStauffman
out=np.zeros_like(a)jest krytyczny, jak stwierdzono w komentarzu.
Jonatan Öström
1
Jeśli używam np.divide(a, b, out=np.zeros_like(a), where=b!=0), pojawia się błąd Assigning to function call which doesn't return. Dziwne jest to, że używam go dwukrotnie i błąd pojawia się tylko raz.
Jelmer Mulder
46

Opierając się na odpowiedzi @Franck Dernoncourt, naprawiając -1/0:

def div0( a, b ):
    """ ignore / 0, div0( [-1, 0, 1], 0 ) -> [0, 0, 0] """
    with np.errstate(divide='ignore', invalid='ignore'):
        c = np.true_divide( a, b )
        c[ ~ np.isfinite( c )] = 0  # -inf inf NaN
    return c

div0( [-1, 0, 1], 0 )
array([0, 0, 0])
denis
źródło
Dzięki, nawet nie złapałem tego błędu w kodzie @Frank Dernoncourt.
hlin117
Cześć, próbuję wykonać obliczenia tablicowe i chcę, aby 0/0 dawało 0, ale chcę też zignorować np.NaN w moich obliczeniach. Czy to zadziała? Próbuję też zrozumieć. Co robi c [~ np.isfinite (c)] = 0? Nigdy nie używałem ~ w Pythonie. Po co to jest? Dziękuję
user20408
@ user20408, ~odwraca Truei Falsew NumPy tablic: print ~ np.array([ True, False, False ]). c[ ~ np.isfinite( c )] = 0oznacza: znajdź pozycje, w których cjest skończone, odwróć je na NIE skończone z ~i ustaw niekończone wartości na 0. Zobacz także stackoverflow.com/search?q=[numpy]+"boolean+indexing "
denis
43

Opierając się na innych odpowiedziach i ulepszając:

Kod:

import numpy as np

a = np.array([0,0,1,1,2], dtype='float')
b = np.array([0,1,0,1,3], dtype='float')

with np.errstate(divide='ignore', invalid='ignore'):
    c = np.true_divide(a,b)
    c[c == np.inf] = 0
    c = np.nan_to_num(c)

print('c: {0}'.format(c))

Wynik:

c: [ 0.          0.          0.          1.          0.66666667]
Franck Dernoncourt
źródło
2
Dobra robota zarówno przy sprawdzaniu, 0/0jak i 1/0błędach.
hlin117
Wypróbowałem twoją metodę z przykładowymi tablicami podanymi w odpowiedzi DStauffman i wydaje się, że skutkuje bardzo wysokimi liczbami zamiast np.inf, co pozostaje na ostatecznym wyniku
Gal Avineri
Odradzam takie podejście. Jeśli jedno alub drugie bzawiera NaN, Twoje rozwiązanie nagle daje 0wynik. Może to łatwo ukryć błędy w kodzie i jest absolutnie nieoczekiwane.
DerWeh
Zgodnie z ostatnią instrukcją numpy nan_to_num () przyjmuje wartości zastępujące dodatnie inf i ujemne inf. numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)to podpis.
Craig Hicks
19

One-linier (rzuca ostrzeżenie)

np.nan_to_num(array1 / array2)
Ulf Aslak
źródło
13

Spróbuj zrobić to w dwóch krokach. Najpierw dziel, potem zamień.

with numpy.errstate(divide='ignore'):
    result = numerator / denominator
    result[denominator == 0] = 0

Ta numpy.errstatelinia jest opcjonalna i po prostu zapobiega informowaniu przez numpy o "błędzie" dzielenia przez zero, ponieważ już zamierzasz to zrobić i zająć się tym przypadkiem.

Pi Marillion
źródło
5
Prawdopodobnie powinieneś dokonać podziału w kontekścienp.errstate(divide='ignore'):
Warren Weckesser
@WarrenWeckesser Fair point. Zredagowałem odpowiedź, aby uwzględnić kontekst. divide='warn'mogłoby się również przydać, gdyby nadal chciał być powiadamiany.
Pi Marillion
2

Możesz również zamienić na podstawie inf, tylko jeśli dtypy tablicy są zmiennoprzecinkowe, zgodnie z tą odpowiedzią :

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> c = a / b
>>> c
array([ inf,   2.,   1.])
>>> c[c == np.inf] = 0
>>> c
array([ 0.,  2.,  1.])
atomh33ls
źródło
0

Jedną z odpowiedzi, jaką znalazłem podczas wyszukiwania powiązanego pytania, było manipulowanie danymi wyjściowymi w oparciu o to, czy mianownik był zerowy, czy nie.

Załóżmy arrayAi arrayBzostały zainicjowane, ale arrayBma kilka zer. Możemy wykonać następujące czynności, jeśli chcemy arrayC = arrayA / arrayBbezpiecznie obliczyć .

W takim przypadku ilekroć mam w jednej z komórek dzielenie przez zero, ustawiam komórkę na równą myOwnValue, co w tym przypadku będzie równe zero

myOwnValue = 0
arrayC = np.zeros(arrayA.shape())
indNonZeros = np.where(arrayB != 0)
indZeros = np.where(arrayB = 0)

# division in two steps: first with nonzero cells, and then zero cells
arrayC[indNonZeros] = arrayA[indNonZeros] / arrayB[indNonZeros]
arrayC[indZeros] = myOwnValue # Look at footnote

Przypis: Z perspektywy czasu ta linia i tak jest niepotrzebna, ponieważ arrayC[i]jest tworzona na zero. Ale gdyby tak było myOwnValue != 0, ta operacja by coś zrobiła.

hlin117
źródło
0

Inne rozwiązanie, o którym warto wspomnieć:

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> b_inv = np.array([1/i if i!=0 else 0 for i in b])
>>> a*b_inv
array([0., 2., 1.])
T. Gwen
źródło