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.