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.