numpy.log过滤小值仍触发除零RuntimeWarning问题排查
问题:numpy中使用np.where规避log(0)仍触发除零警告的原因及解决方案
给定数组samplex:
In [22]: samplex Out[22]: array([0. , 0.00204082, 0.00408163, 0.00612245, 0.00816327, 0.01020408, 0.0122449 , 0.01428571, 0.01632653, 0.01836735, 0.02040816, 0.02244898, 0.0244898 , 0.02653061, 0.02857143, 0.03061224, 0.03265306, 0.03469388, 0.03673469, 0.03877551, 0.04081633, 0.04285714, 0.04489796, 0.04693878, 0.04897959, 0.05102041, 0.05306122, 0.05510204, 0.05714286, 0.05918367, 0.06122449, 0.06326531, 0.06530612, 0.06734694, 0.06938776, 0.07142857, 0.07346939, 0.0755102 , 0.07755102, 0.07959184, 0.08163265, 0.08367347, 0.08571429, 0.0877551 , 0.08979592, 0.09183673, 0.09387755, 0.09591837, 0.09795918, 0.1 ])
使用代码np.where(samplex>1e-8, np.log(samplex), 0)尝试避免计算log(0),但仍触发警告:
<ipython-input-18-e5dde8c65402>:1: RuntimeWarning: divide by zero encountered in log np.where(samplex>1e-8,np.log(samplex),0) Out[18]: array([ 0. , -6.19440539, -5.50125821, -5.0957931 , -4.80811103, -4.58496748, -4.40264592, -4.24849524, -4.11496385, -3.99718081, -3.8918203 , -3.79651012, -3.70949874, -3.62945603, -3.55534806, -3.48635519, -3.42181667, -3.36119205, -3.30403363, -3.24996641, -3.19867312, -3.14988295, -3.10336294, -3.05891118, -3.01635156, -2.97552957, -2.93630885, -2.89856853, -2.86220088, -2.82710956, -2.79320801, -2.76041819, -2.72866949, -2.69789783, -2.66804487, -2.63905733, -2.61088645, -2.58348748, -2.55681923, -2.53084374, -2.50552594, -2.48083332, -2.45673577, -2.43320528, -2.41021576, -2.3877429 , -2.36576399, -2.34425779, -2.32320438, -2.30258509])
尽管numpy已完成计算,但警告仍出现,请问原因是什么?有没有规避除零错误的优选方案?
原因分析
numpy的np.where函数执行逻辑是先完整计算所有参数的结果,再根据条件选择对应位置的值。也就是说,np.log(samplex)会被全量计算一遍,包括数组中的0元素,此时会触发divide by zero警告;之后where才会根据条件把0位置的结果替换成0,所以警告无法避免。
优选解决方案
方案1:使用numpy掩码数组
通过掩码屏蔽掉不符合条件的元素,仅对有效元素计算log,最后填充默认值:
import numpy.ma as ma masked_x = ma.masked_where(samplex <= 1e-8, samplex) log_x = ma.log(masked_x).filled(0)
掩码数组会自动跳过被屏蔽的元素,不会触发除零警告。
方案2:临时关闭指定numpy警告
用上下文管理器临时忽略除零警告,计算完成后恢复警告状态:
import numpy as np with np.errstate(divide='ignore'): log_x = np.where(samplex > 1e-8, np.log(samplex), 0)
这种方式仅在上下文范围内生效,不会影响其他代码的警告输出。
方案3:预先过滤计算
先筛选出符合条件的元素计算log,再将结果填充到目标数组的对应位置:
log_x = np.zeros_like(samplex) non_zero_mask = samplex > 1e-8 log_x[non_zero_mask] = np.log(samplex[non_zero_mask])
从根源上避免了对0元素的log运算,不会触发任何警告。
内容的提问来源于stack exchange,提问作者WestCoastProjects
相关产品推荐
相关产品推荐

