python - 标量的奇怪 numpy 划分行为

标签 python numpy

我一直在尝试升级一个包含大量标量几何运算的库,这样它们也可以与 numpy 数组一起使用。在执行此操作时,我注意到 numpy divide 有一些奇怪的行为。

在原始代码中,如果两个变量都不为零,则检查变量之间的归一化差异,然后切换到 numpy,最终看起来像这样:

import numpy as np

a = np.array([0, 1, 2, 3, 4])
b = np.array([1, 2, 3, 0, 4])

o = np.zeros(len(a))
o = np.divide(np.subtract(a, b), b, out=o, where=np.logical_and(a != 0, b != 0))
print(f'First implementation: {o}')

对于无法计算的实例,我传入了一个初始化为零的输出缓冲区;这返回:

First implementation: [ 0.         -0.5        -0.33333333  0.          0.        ]

我不得不为标量稍微修改一下,因为 out 需要一个数组,但它看起来没问题。

a = 0
b = 4
o = None if np.isscalar(a) else np.zeros(len(a))
o = np.divide(np.subtract(a, b), b, out=o, where=np.logical_and(b != 0, a != 0))
print(f'Modified out for scalar: {o}')

返回

Modified out for scalar: 0.0.

然后通过一些测试功能运行它,发现其中很多都失败了。深入研究,我发现第一次使用 where 设置为 False 的标量调用除法时,函数返回零,但如果我再次调用它,第二个时间它返回一些不可预测的东西。

a = 0
b = 4
print(f'First divide: {np.divide(b, a, where=False)}')
print(f'Second divide: {np.divide(b, a, where=False)}')

返回

First divide: 0.0
Second divide: 4.0

查看文档,它说“其中条件为 False 的位置将保持未初始化状态”,所以我猜 numpy 是一些内部缓冲区,它最初设置为零,然后它最终会保留一个较早的中间值。

我正在努力了解如何在有或没有 where 子句的情况下使用 divide;如果我使用 where 我会得到不可预知的输出,如果我不使用,我将无法防止被零除。在这些情况下,我是不是遗漏了什么,或者我只需要有不同的代码路径?我意识到我已经使用 out 变量进入了不同的代码路径。

如有任何建议,我将不胜感激。

最佳答案

在我看来这像是一个错误。但是我认为无论如何出于性能原因,您都希望在标量的情况下将对 ufuncs 的调用短路,因此这是一个试图防止它过于困惑的问题。由于 ab 可能是标量,因此您需要同时检查它们。将该检查放入有条件地返回输出数组或 None 的函数中,您可以这样做

def scalar_test_np_zeros(a, b):
    """Return np.zeros for the length of arguments unless both
    arguments are scalar, then None."""
    if a_is:=np.isscalar(a) and np.isscalar(b):
        return None
    else:
        return np.zeros(len(a) if a_is else len(b))

a = 0
b = 4
if o := scalar_test_np_zeros(a, b) is None:
    o = (a-b)/b if a and b else 0.0
else:
    np.divide(np.subtract(a, b), b, out=o, 
        where=np.logical_and(b != 0, a != 0))

标量测试在其他有类似问题的代码中很有用。

关于python - 标量的奇怪 numpy 划分行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74187097/

相关文章:

python - 在 Python 中搜索和替换字符串中的一些文本?

python - 如何根据两个条件在嵌套字典中创建键列表?

python - 在 keras fit_generator 训练的第二个时期结束时无法将模型历史写入 json 文件

python - 如何将 python 脚本分成几部分并循环导入这些部分?

python - 我正在尝试学习 Flask,但 UserMixin 似乎不起作用

python - 加快计算不同列的数量

python - 滚动统计性能: pandas vs. numpy strides

python - 将列表元素与元组元素合并

python - 绕过 "Array is too big"python错误

python - Django 在密码重置时收到意外的关键字参数 uidb36