如何将 NumPy 数组按元素舍入到第一个非零数字?

How to do element-wise rounding of NumPy array to first non-zero digit?

我想 "round"(不是精确的数学舍入)以下方式的 numpy 数组的元素:

给定一个数字在 0.00001 到 9.99999 之间的 numpy NxN 或 NxM 二维数组,如

 a=np.array([[1.232, 1.872,2.732,0.123],
             [0.0019, 0.025, 1.854, 0.00017],
             [1.457, 0.0021, 2.34 , 9.99],
             [1.527, 3.3, 0.012 , 0.005]]
    )

我基本上想 "round" 通过选择每个元素的第一个非零数字(不管第一个非零数字后面的数字)来 "round" 这个 numpy 数组 给出输出:

output =np.array([[1.0, 1.0, 2.0, 0.1],
                 [0.001, 0.02, 1.0, 0.0001],
                 [1.0, 0.002, 2 , 9.0],
                 [1, 3, 0.01 , 0.005]]
        )

感谢您的帮助!

你可以使用np.logspacenp.seachsorted来确定每个元素的数量级然后floor divide and multiply back

po10 = np.logspace(-10,10,21)
oom = po10[po10.searchsorted(a)-1]
a//oom*oom
# array([[1.e+00, 1.e+00, 2.e+00, 1.e-01],
#        [1.e-03, 2.e-02, 1.e+00, 1.e-04],
#        [1.e+00, 2.e-03, 2.e+00, 9.e+00],
#        [1.e+00, 3.e+00, 1.e-02, 5.e-03]])

首先用

对数组中的每个数字求10的次方
powers = np.floor(np.log10(a))

在你的例子中,这给了我们

array([[ 0.,  0.,  0., -1.],
       [-3., -2.,  0., -4.],
       [ 0., -3.,  0.,  0.],
       [ 0.,  0., -2., -3.]])

现在,如果我们将数组中的第 i 个元素除以 10**power_i,我们实际上会将数组中的每个数字非零元素移动到第一个位置。现在我们可以简单地发言以删除其他非零数字,然后将结果乘以 10**power_i 以返回到原始比例。

完整的解决方案只有下面的代码

powers = np.floor(np.log10(a))
10**powers * np.floor(a/10**powers)

大于或等于 10 的数字呢?

为此,您只需取数组中原始值的 np.floor。我们可以使用面具轻松做到这一点。您可以修改答案如下

powers = np.floor(np.log10(a))
result = 10**powers * np.floor(a/10**powers)

mask = a >= 10
result[mask] = np.floor(a[mask])

您也可以使用掩码来避免计算稍后将被替换的数字的幂和对数。

你想要做的是保持固定数量的 significant figures

此功能未集成到 NumPy 中。

要仅获得 1 位有效数字,您可以查看 or 个答案(假设您只有正值)。

如果你想要一些有效数字有效的东西,你可以使用类似的东西:

def significant_figures(arr, num=1):
    # : compute the order of magnitude
    order = np.zeros_like(arr)  
    mask = arr != 0
    order[mask] = np.floor(np.log10(np.abs(arr[mask])))
    del mask  # free unused memory
    # : compute the corresponding precision
    prec = num - order - 1
    return np.round(arr * 10.0 ** prec) / 10.0 ** prec


print(significant_figures(a, 1))
# [[1.e+00 2.e+00 3.e+00 1.e-01]
#  [2.e-03 2.e-02 2.e+00 2.e-04]
#  [1.e+00 2.e-03 2.e+00 1.e+01]
#  [2.e+00 3.e+00 1.e-02 5.e-03]]

print(significant_figures(a, 2))
# [[1.2e+00 1.9e+00 2.7e+00 1.2e-01]
#  [1.9e-03 2.5e-02 1.9e+00 1.7e-04]
#  [1.5e+00 2.1e-03 2.3e+00 1.0e+01]
#  [1.5e+00 3.3e+00 1.2e-02 5.0e-03]]

编辑

对于截断的输出,在 return.

之前使用 np.floor() 而不是 np.round()