Numpy除以0的解决方法

5

假设我有两个数组

x = [1,2,3]
y = [0,1,0]

我需要使用numpy对数组进行逐元素划分。但是我的问题在于实现“安全划分”时遇到了困难。 当执行以下操作时:

np.divide(x,y).tolist()

我得到了输出:
[0.0, 2.0, 0.0]

我的问题是,当除以0时,我需要返回不为0的元素,使得理想输出如下:
[1.0, 2.0, 3.0]

有没有使用numpy的解决方法? 手动定义一个函数来完成这个任务,有没有更优化的方法来完成这个任务,而不需要创建一个自定义的除法函数(如下所示)并在每对元素上使用它?

def mydiv(x, y):
if y == 0:
    return x
else:
    return x / y

注意:我担心优化的原因是这将在云中运行,因此资源受限,在具有300+元素数组时,这样做似乎并不最优。


2
300个元素真的很少。你是否真的遇到了性能问题?你说你有数组,但实际上你有列表对象。我怀疑将你的列表转换为np.ndarray对象,然后再转回列表的成本是否值得对300左右的元素列表进行加速...事实上,我认为这样做会显著地变慢。 - juanpa.arrivillaga
我的问题是我有树形结构,最深达到7层,每个节点都包含这样的列表。在2500多棵树中为每个节点执行此类操作非常耗费资源,因此我正在尝试将计算成本降至最低。 - eXistanCe
是的,但我怀疑这样做不会更高效,我认为它可能会更低效。 - juanpa.arrivillaga
2个回答

5

你可以使用一个简单的技巧:

x / (y + (y==0))

实际应用:

x = np.array([1, 5, 3, 7])
y = np.array([0, 2, 0, 4])

print(x / (y + (y==0)))

# [1.   2.5  3.   1.75]

时间:

def chrisz(x, y):
  return x/(y+(y==0))

def coldspeed1(x, y):
  m = y != 0
  x[m] /= y[m]
  return x

def coldspeed2(x, y):
  m = ~(y == 0)
  x[m] /= y[m]
  return x

def coldspeed3(x, y):
  m = np.flatnonzero(y)
  x[m] /= y[m]
  return x

结果:

In [33]: x = np.random.randint(10, size=10000).astype(float)

In [34]: y = np.random.randint(3, size=10000).astype(float)

In [35]: %timeit chrisz(x, y)
29.4 µs ± 601 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [36]: %timeit coldspeed1(x, y)
173 µs ± 2 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [37]: %timeit coldspeed2(x, y)
184 µs ± 1.36 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [38]: %timeit coldspeed3(x, y)
179 µs ± 2.68 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

@eXistanCe 你是担心操作次数还是速度?顺便说一下,@chrisz,我发现在我的答案中使用~(y == 0)np.flatnonzero(y)可以挤出几个周期。 - cs95
我在运行计时之前将xy转换为浮点数组,是否有什么更新可以使它更准确? - user3483203
糟糕,我没看到。不,毫无疑问这些时间是绝对公平的,我记录了类似的结果(虽然有点不太极端,这确实取决于你的数据和你的机器)。感谢你的时间! - cs95
1
嘿,你昨晚分析了那个问题,现在轮到我了,公平起见 ;) - user3483203
1
是的,我对被接受的答案有点意见 :p 但没关系,再次感谢! - cs95
显示剩余4条评论

4
最简单/最快的方法是将对应非零 Y 值的值相除。
x = [1, 2, 3]
y = [0, 1, 0]

x, y = [np.array(arr, dtype=float) for arr in (x, y)]

m = y != 0  # ~(y == 0) # np.flatnonzero(y)
x[m] /= y[m]

print(x)
array([1., 2., 3.])

@chrisz 我认为这是 OP 打错了(2 / 1 = 2 ;-)) - cs95
@eXistanCe 这是一个好问题。我认为,从循环的角度来看,这可能会更短,但从一些快速测试中看来,chrisz的答案略微更快。我建议在您的数据上进行时间比较,这真的取决于情况。 - cs95
非常感谢,我将进行一些计时测试。正如我对评论问题的其他人所说,对于小数组来说不是问题,但对于数千个300/400甚至800多个元素来说,这成为了一个问题。 - eXistanCe
此外,如果我错了,请纠正我,但由于true_divide的性质,这对于非浮点数是行不通的。 - user3483203
@chrisz 是的,我确保将输入转换为浮点数,这样才能正常工作。否则,你需要使用 x[m] = x[m] / y[m],这样会强制转换 x - cs95

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接