代码之家  ›  专栏  ›  技术社区  ›  a_guest

numpy-围绕任意边界包装值

  •  0
  • a_guest  · 技术社区  · 6 年前

    我有一个数组 x 其值包含在 [a, b] ( a 包容的, b 独家)。现在我想计算 x + y (随机 y )如此 x+y轴 仍然包含在 [甲,乙] 通过将生成的值环绕在左边界或右边界(以交叉的为准)。

    一个例子胜过千言万语:

    >>> a, b = -5, 5
    >>> x = np.array([-4, -2, 0, 2, 4])
    >>> wrap(x, 3)  # Compute x + 3.
    [-1, 1, 3, -5, -3]
    >>> wrap(x, -3)  # Compute x - 3.
    [3, -5, -3, -1, 1]
    

    我提出了以下的实现方案,但并不完全令人满意。

    def wrap(x, y):
        if y > 0:
            return (x - a + y) % (b - a) + a
        elif y < 0:
            return (x - b + y) % (a - b) + b
        else:
            return x
    
    1. 此函数没有正确获得包含/排除边界条件;对于 wrap(x, -3) 它又回来了 array([ 3, 5, -3, -1, 1]) 虽然 5 应该是 -5 是的。我不知道如何包含这个功能。
    2. 也就是说 if 子句看起来有些人为,我想知道是否可以用更一般的方式(小问题)处理它。

    有人知道如何解决这个问题吗?

    2 回复  |  直到 6 年前
        1
  •  1
  •   a_guest    6 年前

    通过“包装”,我认为结果应该与 x+y mod b-a 一致。(注意 b-a 是本例中的“窗口大小”

    考虑特殊情况 a==0 。我们有:

    定义包装(x,y):
    返回(x+y)%b
    

    直截了当,对吧?注意,Python中的 % 是floor模——结果的符号总是与除数的符号相同所以结果将在 [0..b[

    在更一般的情况下:

    定义包装(x,y):
    收益率(x+y-a)%(b-a)+a
    

    很容易证明返回值与 x+y mod b-a

    还要注意,这是OP代码中的第一种情况它对 y 的所有值都有效


    但是,如果 x 是numpy数组,则执行 len(x) % 操作,这可能会很慢。因此,可以执行以下操作:

    定义wrap2(x,y):
    y%=b-a
    x=x+y
    返回x-(b-a)*(x>=b)
    

    应该更快。 在线试用!

    说明:

    • y%=b-a :将 y 减小到范围 [0..b-a[ 。这不会影响结果。
    • x=x+y :将 y 添加到 x 在这一步之后, x 将包含正确的值,模 b-a x 中的所有值都应在范围 [a..b+(b-a)[
    • x-(b-a)*(x>=b) : (x>=b) (如果解释为整数)如果 x>=b ,则计算结果为 1 ,否则计算结果为 0 。从 x 中减去乘 b-a 将从所有值 >=b 中减去 b-a ,并保持这些值完好无损。
    esult始终与除数的符号相同。所以结果就在于 [0..b[ 是的。

    在更一般的情况下:

    def wrap(x, y):
        return (x + y - a) % (b-a) + a
    

    很容易证明返回值与 X+Y轴 国防部 B-A公司 是的。

    还要注意,这是OP代码中的第一种情况它对的所有值都有效 y .


    但是,如果 x 是一个numpy数组,它将执行 len(x) % 手术,可能会很慢。因此,可以执行以下操作:

    def wrap2(x, y):
        y %= b - a
        x = x + y
        return x - (b-a)*(x >= b)
    

    应该更快。 上网试试吧!

    说明:

    • y %= b-a :减少 是的 射程 [0..b-a[ . 这不会影响结果。
    • x = x + y :添加 是的 是的。在这一步之后 将包含正确的值,模 B-A公司 是的。中的所有值 应该在范围内 [a..b+(b-a)[ 是的。
    • x - (b-a)*(x >= b) : (x >= b) (如果解释为整数)计算结果为 1 如果 x >= b ,和 0 否则。减去乘法 B-A公司 将减去 B-A公司 从所有的价值观 >= b ,并保留这些 < b 完整的。
        2
  •  0
  •   David    6 年前

    假设您的输入数组已经在[a,b]范围内,那么我们可以重写 wrap 作为以下功能;

    def wrap(x,y,a,b):
        if y > 0:
            x += y
            x[x >=b] -= (b-a)
        elif y < 0:
            x += y
            x[x < a] += (b-a)
        return x