不使用Python循环使numpy数组单调化

27

我有一个一维值数组,应该是单调的(假设是递减的),但存在随机区域其值会随索引增加。

我需要一个替换了每个区域值的数组,使得结果数组是有序的。

所以如果给出的数组是:

a = np.array([10.0, 9.5, 8.0, 7.2, 7.8, 8.0, 7.0, 5.0, 3.0, 2.5, 3.0, 2.0])

我希望你能把结果变成这样

b = np.array([10.0, 9.5, 8.0, 7.2, 7.2, 7.2, 7.0, 5.0, 3.0, 2.5, 2.5, 2.0])

这是一个图形化表示:

example

我知道如何使用Python循环来实现它,但是否有使用NumPy工具的方法呢?

为了清晰起见,以下是Python代码:

b = np.array(a)
for i in range(1, b.size):
    if b[i] > b[i-1]:
        b[i] = b[i-1]

为什么要关注“无循环”?无论您编写显式循环还是在某个模块/包中导入函数执行循环,它都存在。除非您想将整个循环完全展开成线性操作序列,否则没有太多方法可以对一系列值执行操作而不涉及循环,这种做法有许多缺点——可移植性、灵活性、代码大小等等。 - twalberg
2
@twalberg 我认为在使用NumPy时尽量避免Python循环是很常见的,因为如果迭代在C中实现的函数内部完成,则性能通常会提高。这也经常发生,代码更短更清晰。 - Lev Levitsky
这是在处理大数据集时一个有效的观点。然而,在这个例子中(并且没有任何迹象表明“真正”的问题规模更大),我认为将Python列表转换为C循环可以处理的数据结构,然后再将其转换回适当的Python数据结构的开销,可能会抵消不仅使用Python循环迭代十几个条目的潜在收益...最好在试图消除它之前先验证循环是否是一个问题... - twalberg
1
@twalberg 好的,我应该提到真实数据确实有数千个元素,并且已经以 NumPy 数组的形式存在。不过,这个问题也有教育目的。 - Lev Levitsky
1个回答

44

您可以使用np.minimum.accumulate在遍历数组时收集最小值:

>>> np.minimum.accumulate(a)
array([ 10. ,   9.5,   8. ,   7.2,   7.2,   7.2,   7. ,   5. ,   3. ,
         2.5,   2.5,   2. ])

对于数组中的每个元素,该函数返回到目前为止看到的最小值。

如果您想让数组单调递增,您可以使用np.maximum.accumulate

NumPy中的许多其他通用函数都有一个accumulate方法来模拟遍历数组、将函数应用于每个元素并将返回的值收集到一个相同大小的数组中。


2
哇,我不知道有 .accumulate!这非常接近 Python2 的 reduce(或 Python3 的 functools.reduce),我是对的吗? - Lev Levitsky
2
它们非常相似 - accumulate 存储对每个元素进行操作的结果并返回相同长度的数组,而 unfunc 的 reduce 方法只显示最终结果(折叠数组)。 - Alex Riley
哦,是的,你说得对。所以reduce基本上会返回accumulate返回的最后一个元素。 - Lev Levitsky

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