Як повернути 0 з діленням на нуль


100

Я намагаюся виконати роздільний елемент, що відповідає розуму, в python, але якщо зустрічається нуль, мені потрібний коефіцієнт, який просто дорівнює нулю.

Наприклад:

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

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

Я завжди міг просто використовувати цикл for-циклу через свої дані, але для того, щоб реально використовувати оптимізацію numpy, мені потрібна функція ділення, щоб повернути 0 при поділі на нуль помилок, а не ігнорувати помилку.

Якщо я чогось не пропускаю, це не здається numpy.seterr () може повертати значення при помилках. Чи є у когось якісь пропозиції щодо того, як я міг би отримати найкраще з нумету під час встановлення власного поділу на обробці нульових помилок?


У моїй версії python (Python 2.7.11 | Continuum Analytics, Inc.) саме такий результат ви отримаєте. З попередженням.
Рамон Мартінес

Найбільш ємний правильну відповідь stackoverflow.com/a/37977222/2116338
mrplants

Відповіді:


182

У numpy v1.7 + ви можете скористатися опцією "де" для ufuncs . Ви можете робити речі в один рядок, і вам не доведеться мати справу з менеджером контексту помилок.

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

У цьому випадку він робить розрахунок ділення де завгодно, де 'b не дорівнює нулю. Коли b дорівнює нулю, воно залишається незмінним порівняно з тим значенням, яке ви спочатку вказали в аргументі 'out'.


3
Якщо aта / або bможуть бути цілі масиви, то це та сама концепція, вам просто потрібно чітко встановити правильний тип виводу:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
DStauffman

out=np.zeros_like(a)є критичним, як зазначено в коментованому рядку.
Джонатан Естрем

1
Якщо я використовую np.divide(a, b, out=np.zeros_like(a), where=b!=0), я отримую помилку Assigning to function call which doesn't return. Дивна річ у тому, що я використовую його двічі, і помилка з’являється лише один раз.
Джелмер Малдер

46

Спираючись на відповідь @Franck Dernoncourt, фіксуючи -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])

Дякую, я навіть не вловив цю помилку з кодом @Frank Dernoncourt.
hlin117

Привіт, я намагаюся займатися математикою масиву, і я хочу, щоб 0/0 привів до 0, але я також хочу ігнорувати np.NaN у своїх розрахунках. Чи вдасться це для цього? Крім того, я намагаюся зрозуміти. Що робить c [~ np.isfinite (c)] = 0? Я ніколи не використовував ~ в python. Для чого це? Дякую
користувач20408

@ User20408, ~перевертає Trueі Falseв Numpy масивів: print ~ np.array([ True, False, False ]). c[ ~ np.isfinite( c )] = 0означає: знайдіть позиції, де cє кінцевими, інвертуйте їх, які НЕ обмежуються ~, і встановіть некінцеві значення на 0. Дивіться також stackoverflow.com/search?q= evidencenumpySense+ " boolean+indexing "
деніс

43

Спираючись на інші відповіді та вдосконалюючи:

Код:

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

Вихід:

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

2
Хороша робота для перевірки 0/0, а також 1/0помилок.
hlin117

Я спробував ваш метод на прикладах масивів, наведених у відповіді DStauffman, і, здається, це призводить до дуже великих цифр замість np.inf, що залишається остаточним результатом
Gal

Я б перешкоджав такому підходу. Якщо вони aабо bмістять NaN, ваше рішення раптово дає 0результат. Це може легко приховати помилки у вашому коді та абсолютно несподівано.
DerWeh

Згідно з недавнім керівництвом numpy nan_to_num () приймає значення, щоб замінити позитивний і негативний інф. numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)- це підпис.
Крейг Хікс


13

Спробуйте зробити це у два кроки. Спочатку поділ, потім заміна.

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

numpy.errstateЛінія НЕ є обов'язковим, і тільки заважає Numpy звіщати вам про «помилки» поділу на нуль, так як ви вже маєте намір зробити це, і регулювати цю справу.


5
Ви, мабуть, повинні виконати поділ у контекстіnp.errstate(divide='ignore'):
Уоррен Веккессер

@ Справедливий пункт WarrenWeckesser Я відредагував відповідь, щоб включити контекст. divide='warn'також може бути корисним, якщо він / він хотів все-таки отримувати повідомлення.
Пі-Мальйон

2

Ви також можете замінити на основі inf, лише якщо типи масиву є плаваючими, відповідно до цієї відповіді :

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

Одна з відповідей, яку я знайшов, шукаючи пов'язане з цим питання, - це маніпулювати результатом на основі того, чи знаменник дорівнює нулю чи ні.

Нехай arrayAі arrayBініціалізовані, але arrayBмає деякі нулі. Ми можемо зробити наступне, якщо хочемо arrayC = arrayA / arrayBбезпечно обчислювати .

У цьому випадку, коли в одній з комірок у мене ділиться на нуль, я встановлюю комірку рівною myOwnValue, що в цьому випадку буде нулем

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

Виноска: Ретроспективно цей рядок у будь-якому випадку непотрібний, оскільки arrayC[i]екземпляр дорівнює нулю. Але якби так було myOwnValue != 0, ця операція щось зробила б.


0

Інше рішення, яке варто згадати:

>>> 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.])
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.