关于python:如何将NumPy数组的元素逐位舍入到第一个非零数字?

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

我想通过以下方式对numpy数组的元素进行"四舍五入"(不是精确的数学舍入):

给出一个数值介于0.00001至9.99999之间的Nump NxN或NxM 2D数组,例如

1
2
3
4
5
 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]]
    )

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

1
2
3
4
5
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]]
        )

感谢您的帮助!


您想要做的是保持固定数量的有效数字。

此功能未集成到NumPy中。

要仅获取1个有效数字,可以查看@PaulPanzer或@darcamo答案(假设您只有正值)。

如果您希望某件作品能够达到指定数量的有效数字,则可以使用以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()


您可以使用np.logspacenp.seachsorted确定每个元素的数量级,然后进行底数划分并相乘

1
2
3
4
5
6
7
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的幂

1
powers = np.floor(np.log10(a))

在您的示例中,这给了我们

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

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

那么完整的解决方案只是下面的代码

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

大于或等于10的数字呢?

为此,您可以简单地获取数组中原始值的np.floor。我们可以戴着口罩轻松做到这一点。您可以如下修改答案

1
2
3
4
5
powers = np.floor(np.log10(a))
result = 10**powers * np.floor(a/10**powers)

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

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