【问题标题】:Round in numpy to Nearest Step在numpy中四舍五入到最近的步骤
【发布时间】:2023-12-26 07:42:01
【问题描述】:

我想知道如何将 numpy 中的数字舍入到上限或下限,这是预定义步长的函数。希望以更清晰的方式说明,如果我有数字 123 和等于 50 的步长,我需要将 123 舍入到最接近的 150 或 100,在本例中为 100。我得出了下面的函数但我想知道是否有更好、更简洁的方法来做到这一点。

提前致谢,

保罗

def getRoundedThresholdv1(a, MinClip):
    import numpy as np
    import math
    digits = int(math.log10(MinClip))+1
    b = np.round(a, -digits)
    if b > a:  # rounded-up
        c = b - MinClip
        UpLow = np.array((b,c))
    else:  # rounded-down
        c = b + MinClip
        UpLow = np.array((c,b))
    AbsDelta = np.abs(a - UpLow)
    return UpLow[AbsDelta.argmin()]




getRoundedThresholdv1(143, 50)

【问题讨论】:

  • 您的代码不起作用,例如 getRoundedThresholdv1(143, 50) 返回 50 而不是 150
  • 现在可以使用 - 需要 int(math.log10(MinClip))+1 而不是 int(math.log10(a))+1 - 感谢您指出这一点

标签: python numpy rounding


【解决方案1】:

我认为你不需要numpy

def getRoundedThresholdv1(a, MinClip):
    return round(float(a) / MinClip) * MinClip

这里a是一个单一的数字,如果你想对这个函数进行向量化,你只需要将round替换为np.roundfloat(a)替换为np.array(a, dtype=float)

【讨论】:

  • 不错的答案:当然,如果您非常关心中途情况的确切舍入方式,那么生活会变得很多更加困难。
  • @MarkDickinson: 好吧,现在它四舍五入到最近,例如getRoundedThresholdv1(150, 100): 舍入到 200,因为 150 比 100 更接近 100,因为 0.5 更接近 1 而不是 0 (round代数)。如果您想更改逻辑,可以尝试使用ceilfloor
  • true,举个简单的例子。但是,如果您尝试使用它来舍入到 0.1 的倍数(例如),您将遇到数值错误的问题,将计算结果推送到真实结果的一侧或另一侧,以便输出从半途而废的情况基本上变得不可预测。
  • 另外,numpy 的 round 和 Python 的 round 处理中途情况的方式是有区别的。例如,使用 numpy、Python 2.x 和 Python 3.x 尝试 round(2.5)
  • @MarkDickinson:天哪! “Numpy 四舍五入到最接近的偶数值”
【解决方案2】:

请注意,round() 在 Ruggero Turra 中,他的答案四舍五入到最接近的偶数。含义:

a= 0.5
round(a)

Out: 0

这可能不是您所期望的。

如果你想要“经典”舍入,你可以使用这个函数,它支持标量和 Numpy 数组:

import Numpy as np

def getRoundedThresholdv1(a, MinClip):
    scaled = a/MinClip
    return np.where(scaled % 1 >= 0.5, np.ceil(scaled), np.floor(scaled))*MinClip

或者,您可以使用 Numpy 的方法 digitize。它要求您定义步骤数组。 digitize 将有点像 ceil 您对下一步的价值。因此,为了以“经典”方式进行舍入,我们需要一个中间步骤。

你可以用这个:

import Numpy as np
    
def getRoundedThresholdv1(a, MinClipBins):
    intermediate = (MinClipBins[1:] + MinClipBins[:-1])/2
    return MinClipBins[np.discritize(a, intermediate)]

你可以这样称呼它:

bins = np.array([0,  50, 100, 150])
test1 = getRoundedThresholdv1(74, bins)
test2 = getRoundedThresholdv1(125, bins)

这给出了:

test1 = 50
test2 = 150 

【讨论】:

    【解决方案3】:

    总结:这是正确的做法,最佳答案有不起作用的案例:

    def round_step_size(quantity: Union[float, Decimal], step_size: Union[float, Decimal]) -> float:
    """Rounds a given quantity to a specific step size
    :param quantity: required
    :param step_size: required
    :return: decimal
    """
    precision: int = int(round(-math.log(step_size, 10), 0))
    return float(round(quantity, precision))
    

    我的声誉太低,无法对 Ruggero Turra 的最佳答案发表评论并指出问题所在。但是它有一些不起作用的情况,例如:

    def getRoundedThresholdv1(a, MinClip):
        return round(float(a) / MinClip) * MinClip
    
    getRoundedThresholdv1(quantity=13.200000000000001, step_size=0.0001)
    

    无论使用 numpy 还是标准库回合,都立即返回 13.200000000000001。我什至没有通过对功能进行压力测试来发现这一点。它只是在生产代码中使用它时出现并吐出错误。

    请注意,此答案的全部功劳来自一个开源 github 存储库,该存储库不是我的 here

    【讨论】:

      最近更新 更多