Come restituire 0 con divisione per zero


100

Sto cercando di eseguire una divisione saggia degli elementi in Python, ma se viene incontrato uno zero, ho bisogno che il quoziente sia zero.

Per esempio:

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

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

Potrei sempre usare un ciclo for attraverso i miei dati, ma per utilizzare davvero le ottimizzazioni di numpy, ho bisogno che la funzione divide restituisca 0 in caso di divisione per zero errori invece di ignorare l'errore.

A meno che non mi manchi qualcosa, non sembra che numpy.seterr () possa restituire valori in caso di errori. Qualcuno ha altri suggerimenti su come ottenere il meglio da numpy impostando la mia divisione per zero gestione degli errori?


Nella mia versione di Python (Python 2.7.11 | Continuum Analytics, Inc.) questo è esattamente l'output che ottieni. Con un avvertimento.
Ramon Martinez

La risposta corretta è più succinta stackoverflow.com/a/37977222/2116338
mrplants

Risposte:


182

In numpy v1.7 +, puoi sfruttare l'opzione "where" per ufuncs . Puoi fare le cose in una riga e non devi avere a che fare con il gestore di contesto 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]

In questo caso, esegue il calcolo della divisione ovunque "dove" b non è uguale a zero. Quando b è uguale a zero, rimane invariato rispetto al valore originariamente assegnato nell'argomento "out".


3
Se ae / o bpotrebbero essere array interi, allora è lo stesso concetto, devi solo impostare esplicitamente il tipo di output corretto:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
DStauffman

out=np.zeros_like(a)è fondamentale, come affermato nella riga commentata.
Jonatan Öström

1
Se lo uso np.divide(a, b, out=np.zeros_like(a), where=b!=0), ottengo l'errore Assigning to function call which doesn't return. La cosa strana è che lo uso due volte e l'errore compare solo una volta.
Jelmer Mulder,

46

Basandosi sulla risposta di @Franck Dernoncourt, fissando -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])

Grazie, non ho nemmeno rilevato quel bug con il codice di @Frank Dernoncourt.
hlin117

Ciao, sto provando a fare la matematica degli array e voglio che 0/0 risulti 0 ma voglio anche ignorare np.NaN nei miei calcoli. Funzionerà per quello? Inoltre, sto cercando di capire. Cosa fa c [~ np.isfinite (c)] = 0? Non ho mai usato ~ in Python. Cosa serve? Grazie
user20408

@ user20408, ~inverte Truee Falsein matrici numpy: print ~ np.array([ True, False, False ]). c[ ~ np.isfinite( c )] = 0significa: trova le posizioni in cui cè finito, inverti quelle con NON finito ~e imposta i valori non finiti a 0. Vedi anche stackoverflow.com/search?q=[numpy”+"boolean+indexing "
denis

43

Basandosi sulle altre risposte e migliorando:

Codice:

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

Produzione:

c: [ 0.          0.          0.          1.          0.66666667]

2
Buon lavoro per il controllo 0/0e gli 1/0errori.
hlin117

Ho provato il tuo metodo con gli array di esempio forniti nella risposta di DStauffman e sembra produrre numeri molto alti invece di np.inf, che rimane al risultato finale
Gal Avineri

Scoraggerei questo approccio. Se uno ao più bcontiene NaN, la tua soluzione dà improvvisamente 0come risultato. Questo può nascondere facilmente gli errori nel codice ed è assolutamente inaspettato.
DerWeh

Secondo il recente manuale numpy, nan_to_num () assume valori per sostituire anche inf positivo e inf negativo. numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)è la firma.
Craig Hicks,

18

One-liner (lancia un avvertimento)

np.nan_to_num(array1 / array2)

13

Prova a farlo in due passaggi. Prima la divisione, poi la sostituzione.

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

La numpy.errstatelinea è facoltativa e impedisce solo a numpy di dirti dell '"errore" di divisione per zero, dal momento che hai già intenzione di farlo e di gestire quel caso.


5
Probabilmente dovresti eseguire la divisione nel contestonp.errstate(divide='ignore'):
Warren Weckesser

@ WarrenWeckesser Fair point. Ho modificato la risposta per includere il contesto. divide='warn'potrebbe anche essere utile se desidera essere comunque avvisato.
Pi Marillion

2

Puoi anche sostituire in base a inf, solo se gli array dtypes sono float, come da questa risposta :

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

Una risposta che ho trovato cercando una domanda correlata era manipolare l'output in base al fatto che il denominatore fosse zero o meno.

Supponiamo arrayAe arrayBsiano stati inizializzati, ma arrayBha degli zeri. Potremmo fare quanto segue se vogliamo calcolare in arrayC = arrayA / arrayBmodo sicuro.

In questo caso, ogni volta che ho una divisione per zero in una delle celle, imposto la cella uguale a myOwnValue, che in questo caso sarebbe 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

Nota a piè di pagina: in retrospettiva, questa riga non è comunque necessaria, poiché arrayC[i]è istanziata a zero. Ma se fosse così myOwnValue != 0, questa operazione farebbe qualcosa.


0

Un'altra soluzione degna di nota:

>>> 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.])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.