【问题标题】:Pythonic way to replace list values with upper and lower bound (clamping, clipping, thresholding)?用上限和下限(钳位、剪裁、阈值)替换列表值的 Pythonic 方法?
【发布时间】:2017-05-10 19:50:32
【问题描述】:

我想替换列表中的大纲。因此我定义了一个上限和下限。现在upper_bound 以上和lower_bound 以下的每个值都替换为绑定值。我的方法是使用 numpy 数组分两步执行此操作。

现在我想知道是否可以一步完成,因为我想它可以提高性能和可读性。

有没有更短的方法可以做到这一点?

import numpy as np

lowerBound, upperBound = 3, 7

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

arr[arr > upperBound] = upperBound
arr[arr < lowerBound] = lowerBound

# [3 3 3 3 4 5 6 7 7 7]
print(arr)

【问题讨论】:

  • 虽然很高兴有一个已编译的clip 方法,但您的代码并没有什么不符合pythonic 的地方。这是对numpy 的完美使用,并且具有可读性(对于有经验的用户)。把这个概念放在你的工具箱里;它适用于不太适合 clip 模型的情况。
  • 这个操作一般叫做clampingclipping或者阈值
  • 您应该使用clip 方法,但除了速度之外还有另一个原因;您的代码很优雅,但使用 arr &gt; upperBound 创建了一个中间数组,如果数组变大,这可能是一个问题。
  • @hpaulj 感谢您的评论。术语“pythonic”是指短而快。我知道我的解决方案不是非pythonic,但clip() 方法对于我的特殊用例来说已经足够了。步骤 1) 自己做 2) 理解概念和 3) 使用库是一个很好的方法:)

标签: python arrays numpy clip clamp


【解决方案1】:

对于不依赖 numpy 的替代方案,您总是可以这样做

arr = [max(lower_bound, min(x, upper_bound)) for x in arr]

如果你只是想设置一个上限,你当然可以写arr = [min(x, upper_bound) for x in arr]。或者类似地,如果你只是想要一个下限,你可以使用max

在这里,我刚刚应用了这两个操作,写在一起。

编辑:这里有一个更深入的解释:

给定数组的一个元素 x(并假设您的 upper_bound 至少和您的 lower_bound 一样大!),您将遇到以下三种情况之一:

  1. x &lt; lower_bound
  2. x &gt; upper_bound
  3. lower_bound &lt;= x &lt;= upper_bound

在情况 1 中,max/min 表达式首先计算为 max(lower_bound, x),然后解析为 lower_bound

在情况 2 中,表达式首先变为 max(lower_bound, upper_bound),然后变为 upper_bound

在情况 3 中,我们得到 max(lower_bound, x),它解析为 x

在所有三种情况下,输出都是我们想要的。

【讨论】:

  • 只是我的抱怨(没有投票),当我看到最大/最小组合并发现它们不那么可读时,我倾向于真的认真思考。
  • @djechlin 当然,我不同意这一点。另一方面,这一点的另一个答案使用numpy.clip,如果我在某个地方遇到它,我不会立即阅读它——我可能想仔细检查 numpy 文档,或者只是猜测什么确实如此,希望作者做对了。
  • 奇怪的是嵌套。这是一个非常对称的操作,由“剪辑一次,”剪辑两次。这是“剪辑一次,然后再剪辑一次”。
  • @djechlin 嗯……嗯。我猜对我来说,“剪辑一次,剪辑两次”听起来与“剪辑一次,然后再剪辑一次”非常相似,所以我不确定我是否完全理解你的反对意见。但我同意同时使用 max/min 会带来一些认知负担……或者,需要一些解释。所以我试图给出一个(简短的)解释以及代码。 (但是,我在 cmets 中说的比我在回答中说的要多,所以这表明我的回答可能有点太简短了!)
  • 不错的单线!有替代解决方案总是好的 - 我必须说它缺乏可读性
【解决方案2】:

你可以使用numpy.clip

In [1]: import numpy as np

In [2]: arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [3]: lowerBound, upperBound = 3, 7

In [4]: np.clip(arr, lowerBound, upperBound, out=arr)
Out[4]: array([3, 3, 3, 3, 4, 5, 6, 7, 7, 7])

In [5]: arr
Out[5]: array([3, 3, 3, 3, 4, 5, 6, 7, 7, 7])

【讨论】:

  • 嗨@arthur,谢谢这正是我想要的!不知怎的漏掉了clip这个关键词,自己也没找到方法……
  • 不知道clip是怎么写的。它可以做同样的事情,只是包装在一个函数调用中。
  • @hpaulj 你发现了吗?
  • AFAICT 看起来像是在 C 中。
  • 像许多其他函数一样,np.clip 是 python,但它遵循 arr.clip 方法。对于编译该方法的常规数组,会更快(大约 2 倍)。
猜你喜欢
  • 1970-01-01
  • 2019-02-18
  • 2020-10-05
  • 2019-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多