Como retornar 0 com divisão por zero


100

Estou tentando realizar uma divisão inteligente de elemento em python, mas se um zero for encontrado, preciso que o quociente seja apenas zero.

Por exemplo:

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

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

Eu sempre poderia usar um loop for em meus dados, mas para realmente utilizar as otimizações de numpy, preciso que a função divide retorne 0 sobre erros de divisão por zero em vez de ignorar o erro.

A menos que esteja faltando alguma coisa, não parece que numpy.seterr () pode retornar valores em caso de erros. Alguém tem alguma outra sugestão sobre como eu poderia tirar o melhor proveito do numpy enquanto definia minha própria divisão por zero de tratamento de erros?


Na minha versão python (Python 2.7.11 | Continuum Analytics, Inc.), essa é exatamente a saída que você obtém. Com um aviso.
Ramon Martinez

A resposta correta mais sucinta é stackoverflow.com/a/37977222/2116338
mrplants

Respostas:


181

No numpy v1.7 +, você pode tirar proveito da opção "onde" para ufuncs . Você pode fazer as coisas em uma linha e não precisa lidar com o gerenciador de contexto 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]

Nesse caso, ele faz o cálculo de divisão em qualquer lugar 'onde' b não é igual a zero. Quando b for igual a zero, ele permanecerá inalterado de qualquer valor que você forneceu originalmente no argumento 'out'.


3
E se a e / ou bpuderem ser matrizes inteiras, então é o mesmo conceito, você só precisa definir explicitamente o tipo de saída correto:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
DStauffman

out=np.zeros_like(a)é crítica, conforme indicado na linha comentada.
Jonatan Öström

1
Se eu usar np.divide(a, b, out=np.zeros_like(a), where=b!=0), recebo o erro Assigning to function call which doesn't return. O estranho é que eu uso duas vezes e o erro só aparece uma vez.
Jelmer Mulder

45

Com base na resposta de @Franck Dernoncourt, corrigindo -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])

Obrigado, eu nem peguei aquele bug com o código de @Frank Dernoncourt.
hlin117

Olá, estou tentando fazer matemática de matriz e quero que 0/0 resulte em 0, mas também desejo ignorar np.NaN em meus cálculos. Isso funcionará para isso? Além disso, estou tentando entender. O que c [~ np.isfinite (c)] = 0 faz? Eu nunca usei ~ em python. Para que serve? Obrigado
user20408

@ user20408, ~inverte Truee Falseem matrizes numpy: print ~ np.array([ True, False, False ]). c[ ~ np.isfinite( c )] = 0significa: encontre as posições onde cé finito, inverta-os para NÃO finito com ~e defina os valores não finitos para 0. Veja também stackoverflow.com/search?q=[numpy]+"boolean+indexing "
denis

42

Com base nas outras respostas e melhorando:

Código:

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

Resultado:

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

2
Bom trabalho para verificação 0/0e também para 1/0erros.
hlin117 de

Eu tentei seu método com os arrays de exemplo fornecidos na resposta de DStauffman e parece resultar em números muito altos em vez de np.inf, que permanece no resultado final
Gal Avineri

Eu desencorajaria essa abordagem. Se aou bcontiver NaN, sua solução repentinamente dará 0um resultado. Isso pode facilmente ocultar erros em seu código e é absolutamente inesperado.
DerWeh

De acordo com o manual numpy recente, nan_to_num () usa valores para substituir inf positivo e inf negativo também. numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)é a assinatura.
Craig Hicks

18

One-liner (lança um aviso)

np.nan_to_num(array1 / array2)

13

Tente fazer isso em duas etapas. Divida primeiro, depois substitua.

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

A numpy.errstatelinha é opcional e apenas evita que numpy informe sobre o "erro" de dividir por zero, uma vez que você já pretende fazer isso e cuidar desse caso.


5
Você provavelmente deve realizar a divisão no contextonp.errstate(divide='ignore'):
Warren Weckesser

@WarrenWeckesser Ponto justo. Eu editei a resposta para incluir o contexto. divide='warn'também pode ser útil se ele / ela ainda quiser ser notificado.
Pi Marillion,

2

Você também pode substituir com base em inf, apenas se os tipos da matriz forem flutuantes, de acordo com esta resposta :

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

Uma resposta que encontrei ao pesquisar uma questão relacionada foi manipular a saída com base no denominador zero ou não.

Suponha arrayAe arrayBforam inicializados, mas arrayBtem alguns zeros. Poderíamos fazer o seguinte se quisermos computar arrayC = arrayA / arrayBcom segurança.

Neste caso, sempre que tenho uma divisão por zero em uma das células, eu defino a célula para ser igual a myOwnValue, que neste caso seria 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 de rodapé: Em retrospecto, esta linha é desnecessária de qualquer maneira, pois arrayC[i]é instanciada em zero. Mas se fosse esse o caso myOwnValue != 0, essa operação faria alguma coisa.


0

Outra solução que vale a pena mencionar:

>>> 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.])
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.