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?


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”.


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])

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]

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


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.


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.])

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.


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.])
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.