【问题标题】:Numpy select lazy versionNumpy 选择惰性版本
【发布时间】:2015-10-20 22:58:58
【问题描述】:

考虑下面的代码

 >>> x = np.array([0, 0, 1, 1])
 >>> np.select([x==0, True], [x+1, 1/x])
 array([ 1.,  1.,  1.,  1.])

它有两个问题。

首先,它并不懒惰。即使最终结果中不需要某些评估值,它也会急切地评估 x+1 和 1/x。

其次,numpy每次运行代码都会发出警告

RuntimeWarning: divide by zero encountered in true_divide

这与前一点有些相关,因为它正在尝试评估 1/x,即使最终答案中不需要这样做。

有没有一个懒惰的版本,不会遇到上述问题?

【问题讨论】:

  • np.select 不会计算 1/x,python 会。
  • 有什么理由不想使用y=x[:]; y[~x==0]=1/x[~x==0]; y[x==0]=x[x==0]+1
  • 这正是我想要的。谢谢。
  • 很高兴能帮上忙,我已将其添加为答案。
  • @FıratKıyak 我的也是;)

标签: python numpy select lazy-evaluation


【解决方案1】:

对于这两种情况,您可以通过显式屏蔽输出向量来避免评估:

y = x.copy()
mask = (x == 0)  # parentheses only necessary for readability
y[mask] = x[mask] + 1
y[~mask] = 1 / x[~mask]

以上是我强烈建议您执行的操作,因此您应该只继续阅读一个毫无意义的人为解决方案,该解决方案实际上解决了问题的“懒惰评估”部分。我不建议在实践中使用下面的 sn-p !您已收到警告。

我终于可以实现实际的惰性求值了,尽管它有点混乱并且给情况带来了不必要的复杂性(嗯,至少是这种情况;我可以想象在某些情况下这可能会派上用场)。本着“任何值得做的事情都值得过度”的精神:

xfun1 = [lambda xval=xval: xval + 1 for xval in x]
xfun2 = [lambda xval=xval: 1 / xval for xval in x]
[fun() for fun in np.select([x == 0, True], [xfun1, xfun2])]

这个想法是通过将1/x 的值隐藏在lambda 定义后面来保护它们不被评估。辅助数组xfun1xfun2x 的每个值定义了一个虚拟lambda;第一个返回x+1,第二个返回1/x。但是,在您将元素称为 xfun2[2]() 之前,不会计算这些元素。

所以我们使用select 调用从两个函数数组中选择元素,然后我们获得一个函数列表。为了获得数字返回值,我们需要使用列表推导来评估每个lambda

【讨论】:

  • 这是一个很好的解决问题的方法。然而,目标之一是保持 numpy 的效率,并且当说 x 有数百万个元素时能够做到这一点。您的实现依赖于一个非常慢的 python 函数列表。
  • @dzhelil 确实,这就是为什么我说这是一个不必要的并发症。我只想提供一个符合原始规范的解决方案;)
  • 感谢您的提问和回答。它给了我想要的东西,而且解决方案很棒:)
  • @David 我很高兴这些年来它仍然有用!但我确实希望你的意思是答案的第一部分:P
  • @Andras Deal 我愿意,尽管我发现第二部分很有趣 :)
猜你喜欢
  • 2018-08-10
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
  • 1970-01-01
  • 2013-08-28
  • 2022-12-06
相关资源
最近更新 更多