【Python・NumPy】初期設定だと0除算でも例外が発生しない話

【Python・NumPy】初期設定だと0除算でも例外が発生しない話


# numpy # python

Numpyでは0除算は無限大として処理される

Pythonのみで記載している場合は、例外:ZeroDivisionErrorが発生します。

しかし、NumPyを使用した際には、下記のように値が返されます。

  • 0以外の値は0で除算した際は、inf(無限大)
  • 0を0で除算した際はnan(定義できないため非数を返却)
// Python
array = [1,2,3]
divide_by_zero = [val / 0 for val in array]
print(divide_by_zero)

>> Traceback (most recent call last):
>> ZeroDivisionError: division by zero

// Numpy
import numpy as np

np_array = np.array([0, 1, 2, 3])
divide_by_zero = np_array / 0
print(list(divide_by_zero))
>> [nan, inf, inf, inf]

うっかり高速化だ!とか言ってPythonのコードをそのままNumPyにしたりすると、今までZeroDivisionErrorで捕まえてたものを取り逃すことになったりするので要注意。 なお、nanは非数なので計算はできなくなりますが、infは通常の計算はほぼ機能しなくなるものの、その後の計算も出来てしまうので要注意

例外を返すように設定する

Webアプリケーション等での計算はinf(無限大)では成り立たないためか、例外を返すようにする設定があります。

import numpy as np
np.seterr(divide='raise')
np_array = np.array([0, 1, 2, 3])
divide_by_zero = np_array / 0
print(list(divide_by_zero))

>> Traceback (most recent call last):
>> FloatingPointError: divide by zero encountered in true_divide

基本的にはnumpyを読み込んだ際にはこの設定を付けておいたほうが無難だと思います… 参考)https://docs.scipy.org/doc/numpy-1.16.1/reference/generated/numpy.seterr.html?highlight=seterr#numpy.seterr

おまけ)inf(無限大)は計算ができる

inf以外の数値とは計算結果は異なるものの、各種の演算子を使用することが出来ます。 しかし、通常のアプリケーションでこのような値を使用していいことはないので、対策をすることが殆となります。

inf = float('inf')
// inf = np.inf でも同様
type(inf)
<class 'float'>

inf - inf
>> nan

inf + inf
>> inf

inf * inf
>> inf

inf / inf
>> nan

inf + 1
>> inf

inf - 1
>> inf

inf * 2
>> inf

inf / 10
>> inf

inf ** inf 
>> inf

inf ** 0
>> 1.0

inf / 0
>> Traceback (most recent call last):
>> ZeroDivisionError: float division by zero

 

NumPy等は便利ですが、気をつけて実装しないと思わぬバグを潜めそうで怖い。