web-dev-qa-db-ja.com

Python:ゼロ除算を回避する

浮動小数点数の大きなデータセットがあります。それらを繰り返し処理し、それぞれについてnp.log(x)を評価します。私は得る

RuntimeWarning: divide by zero encountered in log

これを回避し、このエラーが発生した場合は0を返します。

私は新しい関数を定義することを考えています:

def safe_ln(x):
    #returns: ln(x) but replaces -inf with 0
    l = np.log(x)
    #if l = -inf:
    l = 0
    return l

基本的に、出力が-infであることをテストする方法が必要ですが、処理方法がわかりません。ご協力ありがとうございました!

18
Julia

x=0logはマイナスの無限大なので、入力値がゼロであるかどうかを確認し、必要なものを返します。

def safe_ln(x):
    if x <= 0:
        return 0
    return math.log(x)

[〜#〜] edit [〜#〜]:小さな編集:0以下のすべての値をチェックする必要があります。

EDIT 2np.logは、numpy配列で計算する関数です。単一の値の場合は、math.logを使用する必要があります。これは、numpyで上記の関数がどのように見えるかです:

def safe_ln(x, minval=0.0000000001):
    return np.log(x.clip(min=minval))
23
Constantinius

あなたはnp関数を使用しているので、numpy配列で作業していると安全に推測できますか?これを行う最も効率的な方法は、forループの代わりにwhere関数を使用することです

myarray= np.random.randint(10,size=10)
result = np.where(myarray>0, np.log(myarray), 0)

それ以外の場合は、単にログ関数を使用してから、ホールにパッチを適用できます。

myarray= np.random.randint(10,size=10)
result = np.log(myarray)
result[result==-np.inf]=0

Np.log関数は、値0で使用すると-infを正しく返します。したがって、0を返しますか?どこかで元の値に戻す必要がある場合は、ゼロを1に変更する問題が発生します...

32
EnricoGiampieri

あなたはこれを行うことができます。

def safe_ln(x):
   try:
      l = np.log(x)
   except ZeroDivisionError:
      l = 0
   return l
3
Jeff

例外処理を使用します。

In [27]: def safe_ln(x):
    try:
        return math.log(x)
    except ValueError:       # np.log(x) might raise some other error though
        return float("-inf")
   ....:     

In [28]: safe_ln(0)
Out[28]: -inf

In [29]: safe_ln(1)
Out[29]: 0.0

In [30]: safe_ln(-100)
Out[30]: -inf
1

Enricoの答えは素晴らしいですが、どちらのソリューションでも警告が出ます:

RuntimeWarning: divide by zero encountered in log

別の方法として、where関数を引き続き使用できますが、適切な場合にのみメインの計算を実行します。

# alternative implementation -- a bit more typing but avoids warnings.
loc = np.where(myarray>0)
result2 = np.zeros_like(myarray, dtype=float)
result2[loc] =np.log(myarray[loc])

# answer from Enrico...
myarray= np.random.randint(10,size=10)
result = np.where(myarray>0, np.log(myarray), 0)

# check it is giving right solution:
print(np.allclose(result, result2))

私のユースケースは除算用でしたが、原則は明らかに同じです:

x = np.random.randint(10, size=10)
divisor = np.ones(10,)
divisor[3] = 0 # make one divisor invalid

y = np.zeros_like(divisor, dtype=float)
loc = np.where(divisor>0) # (or !=0 if your data could have -ve values)
y[loc] = x[loc] / divisor[loc]
0
Bonlenfum

あなたができる:

def safe_ln(x):
    #returns: ln(x) but replaces -inf with 0
    try:
        l = np.log(x)
    except RunTimeWarning:
        l = 0
    return l
0
Cameron Sparr