python中除以0的处理方法

CSDN-blog-除以0问题
> 这篇blog用于记录如何在python里处理除以0的问题。 > 遇到的问题:在写矩阵运算,机器学习的过程中,会遇到矩阵相除的问题,之前的处理方法是在除法之前对每个元素逐个检查,但这样会导致无法利用numpy的并行计算的能力,最终导致计算速度大幅下降。

这个网站里提供里很好的讨论和指导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的错误类型分别进行操作,如果需要分开,则需要再进一步细分,分为三步:

  1. 对A和B都是非零元素操作
  2. 对A是非零,B是零元素进行操作
  3. 对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.        ]]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值