这个网站里提供里很好的讨论和指导https://www.codenong.com/26248654/
下面分别展示了三种处理除以0的方法,以个人愚见:
- 第一种方法比较普遍和通用(这个通用指换到其他语言或者脱离numpy,这个思路也感觉是可以的)
- 第二种方法是最好的处理方法,对NaN和inF分别进行了处理
- 第三种方法是最简洁的处理方法,只要一行,在对错误的情况理解比较清楚的时候,用这个也不错。
除以0会导致的两种错误
import numpy as np
# 计算的被除数A,以及除数B
arrayA = np.arange(9).reshape(3,3)
arrayA[0,2]=0
arrayA[2,0]=-2
arrayB = np.array([[1,4,0],
[5,0,6],
[0,7,2]])
arrayC = arrayA / arrayB
print("arrayA:\n", arrayA)
print("arrayB:\n", arrayB)
print("*****************")
print("arrayA / arrayB\n",arrayC)
arrayA:
[[ 0 1 0]
[ 3 4 5]
[-2 7 8]]
arrayB:
[[1 4 0]
[5 0 6]
[0 7 2]]
*****************
arrayA / arrayB
[[0. 0.25 nan]
[0.6 inf 0.83333333]
[ -inf 1. 4. ]]
D:\Anaconda\lib\site-packages\ipykernel_launcher.py:8: RuntimeWarning: divide by zero encountered in true_divide
D:\Anaconda\lib\site-packages\ipykernel_launcher.py:8: RuntimeWarning: invalid value encountered in true_divide
首先我们展示在除法计算的过程中,出现错误的类型主要可以分为两种0/0,以及1/0
- 对于0/0 的类型,得到的结果是Nan
- 对于1/0 的类型,得到的结果是Inf(注意还有-inf)
思路一:分而治之
这个方法主要是提取了零元素和非零元素的位置,然后对非零元素进行计算,对零元素直接置约定的值。
但这个方法没有对两种除以0的错误类型分别进行操作,如果需要分开,则需要再进一步细分,分为三步:
- 对A和B都是非零元素操作
- 对A是非零,B是零元素进行操作
- 对A是零元素,B也是零元素进行操作
myOwnValue = 0 # 设置除数为0需要赋的值
arrayC = np.zeros(arrayA.shape)
idxNonZeros = np.where(arrayB!=0) # 得到一个2x7的矩阵,分别对应了7个非零元素的位置
idxZeros = np.where(arrayB==0) # 得到一个2x2的矩阵,分别对应2个零元素的位置
# 除法按两步进行操作,首先是非零元素,随后计算零元素
# division in two steps: first with nonzero cells, and then zero cells
arrayC[idxNonZeros] = arrayA[idxNonZeros] / arrayB[idxNonZeros]
arrayC[idxZeros] = myOwnValue # 若约定为0是不需要这一步的,但如果约定不为0,例如为一极大值,则是必须的
print("*****************")
print("arrayA / arrayB\n",arrayC)
*****************
arrayA / arrayB
[[0. 0.25 0. ]
[0.6 0. 0.83333333]
[0. 1. 4. ]]
思路二 先计算再解决(设计警告处理)
第一行的errstate是对浮点数错误的处理方式进行操作的上下文管理器
Context manager for floating-point error handling
顺手记录一下里面可以写的错误类型:
- divide 除数为0的错误
- invalid 无效浮点数的错误
- over 浮点数溢出
- under 浮点数向下溢出(under-flow)
with np.errstate(divide='ignore', invalid='ignore'):
arrayC = arrayA / arrayB
# 可以参考的对错误处理的方式
# arrayC[arrayC == np.inf] = 0 # 对inf的错误进行修正,不会修正-inf
arrayC[~ np.isfinite(arrayC)] = 0 # 对 -inf, inf, NaN进行修正,置为0
# arrayC = np.nan_to_num(arrayC) # 对-inf, inf, NaN的错误进行修正了果置0,对inf置大数,
# 但返回的为浮点数,不是True_division
print("*****************")
print("arrayA / arrayB\n",arrayC)
*****************
arrayA / arrayB
[[0. 0.25 0. ]
[0.6 0. 0.83333333]
[0. 1. 4. ]]
思路三 调用numpy的除法函数
事实上,numpy早就帮你考虑到除法问题了,所以提供了一个针对矩阵的除法函数,numpy.divide()
但这个方法依然只能统一处理两种除法为0错误,无法识别inf的问题,但是最简洁。
若输出处out,不指定dtype类型为浮点数,会出现错误(把浮点数赋给整数,精度丢失)
这里如果不指定out也会出现一样的结果,但不确定函数内部是不是默认初始值为0
arrayC = np.divide(arrayA, arrayB, out=np.zeros_like(arrayA, dtype=np.float64), where=arrayB!=0)
print("*****************")
print("arrayA / arrayB\n",arrayC)
*****************
arrayA / arrayB
[[0. 0.25 0. ]
[0.6 0. 0.83333333]
[0. 1. 4. ]]