如何避免尝试将元素归零的下溢
How to avoid underflow trying to zero out elements
我有一个大的 numpy 二维数组 F
,它有复数 (np.complex64
)。它有很多非常小的数字。为了我的计算,我只需要 ~1e-6 - 1e-9 的精度。由于这个矩阵非常大,我尝试使用稀疏矩阵表示。所以我尝试这样做:
np.seterr(all="raise")
...
F = getF()
F[np.abs(F) < EPSILON] = 0
# EPSILON = 1e-9. It is supposed to be in between 1e-6 and 1e-9
return csr_matrix(F)
但是计算绝对值会出现下溢错误(numpy 设置为引发错误):
FloatingPointError: underflow encountered in absolute
如果 seterr
未完成,Numpy 不会引发错误,而只会输出 NaN,这会导致问题,因为此矩阵 F 是一系列计算的起点。
根据我的阅读,下溢主要是通过获取日志并直接使用日志值而不是主要值来处理的,但是在这种情况下,我还是想将它们全部丢弃。有这样做的理智的方法吗?我想到了 np.clip
但我有复杂的数字数据,所以使用它不是很简单。
所以我的问题是是否存在一种优雅的(希望是规范的)处理方式?
首先,我可以重现你的错误。
正如 dawg 所指出的,如果您使用 float
而不是 complex
,则不会发生这种情况。
这也是选项 B 起作用的原因,因为 real 和 imag 部分都是浮点数数组。
另一种选择 (C) 是使用更多位来表示您的数据,我想 complex128 是 numpy 的默认设置。
import numpy as np
np.seterr(all="raise")
eps = 1e-9
def get_F(n=100):
# generate some random data with some really small values
r, i = np.random.random((2, n, n))**50
F = r + 1j*i
return F.astype('complex64')
# A: fails
F = get_F()
F[np.abs(F) < eps] = 0
# B: clip real and imag separatly
F = get_F()
F.real[np.abs(F.real) < eps] = 0
F.imag[np.abs(F.imag) < eps] = 0
# C: use more bits to represent your data
F = get_F()
F = F.astype('complex128')
F[np.abs(F) < eps] = 0
print('nonzeros in F:', np.count_nonzero(F))
我有一个大的 numpy 二维数组 F
,它有复数 (np.complex64
)。它有很多非常小的数字。为了我的计算,我只需要 ~1e-6 - 1e-9 的精度。由于这个矩阵非常大,我尝试使用稀疏矩阵表示。所以我尝试这样做:
np.seterr(all="raise")
...
F = getF()
F[np.abs(F) < EPSILON] = 0
# EPSILON = 1e-9. It is supposed to be in between 1e-6 and 1e-9
return csr_matrix(F)
但是计算绝对值会出现下溢错误(numpy 设置为引发错误):
FloatingPointError: underflow encountered in absolute
如果 seterr
未完成,Numpy 不会引发错误,而只会输出 NaN,这会导致问题,因为此矩阵 F 是一系列计算的起点。
根据我的阅读,下溢主要是通过获取日志并直接使用日志值而不是主要值来处理的,但是在这种情况下,我还是想将它们全部丢弃。有这样做的理智的方法吗?我想到了 np.clip
但我有复杂的数字数据,所以使用它不是很简单。
所以我的问题是是否存在一种优雅的(希望是规范的)处理方式?
首先,我可以重现你的错误。
正如 dawg 所指出的,如果您使用 float
而不是 complex
,则不会发生这种情况。
这也是选项 B 起作用的原因,因为 real 和 imag 部分都是浮点数数组。
另一种选择 (C) 是使用更多位来表示您的数据,我想 complex128 是 numpy 的默认设置。
import numpy as np
np.seterr(all="raise")
eps = 1e-9
def get_F(n=100):
# generate some random data with some really small values
r, i = np.random.random((2, n, n))**50
F = r + 1j*i
return F.astype('complex64')
# A: fails
F = get_F()
F[np.abs(F) < eps] = 0
# B: clip real and imag separatly
F = get_F()
F.real[np.abs(F.real) < eps] = 0
F.imag[np.abs(F.imag) < eps] = 0
# C: use more bits to represent your data
F = get_F()
F = F.astype('complex128')
F[np.abs(F) < eps] = 0
print('nonzeros in F:', np.count_nonzero(F))