numpy 如何使数组中的所有值都落在一个范围内?

vdzxcuhz  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(95)

假设我有一个float s的NumPy数组,有正值和负值。我有两个数字,假设它们是aba <= b[a, b]是一个(封闭的)数字范围。
我想让数组的所有值都落在[a, b]范围内,更具体地说,我想用相应的终值替换所有超出该范围的值。
我并不是试图缩放值来将数字放入一个范围,在Python中,这将是:

mina = min(arr)
scale = (b - a) / (max(arr) - mina)
[a + (e - mina) * scale for e in arr]

或者在NumPy中:

mina = arr.min()
scale = (b - a) / (arr.max() - mina)
a + (arr - mina) * scale

我尝试将所有低于a的值替换为a,将所有高于b的值替换为b,同时保持所有其他值不变,我可以在Python的单个列表解析中完成:

[e if a <= e <= b else (a if e < a else b) for e in arr]

我可以用两个广播做同样的事情:

arr[arr < a] = a
arr[arr > b] = b

尽管NumPy比Python快得多,但上面是两个循环,而不是一个,该方法效率低下,但已编译。
什么是更快的方法?
我已经做了多次测量,Python确实像预期的那样慢得多:

In [1]: import numpy as np

In [2]: numbers = np.random.random(4096) * 1024

In [3]: %timeit numbers[numbers < 256]
16.1 µs ± 219 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

In [4]: %timeit numbers[numbers > 512]
20.9 µs ± 526 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [5]: %timeit [e if 256 <= e <= 512 else (256 if e < 256 else 512) for e in numbers]
927 µs ± 101 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

In [6]: %timeit [e if 256 <= e <= 512 else (256 if e < 256 else 512) for e in numbers.tolist()]
684 µs ± 38.2 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

* 编辑 *

修复了将一个数字范围缩放到另一个范围的代码。当我问这个问题的时候,我没有想太多,因为它不相关,但是现在我重新考虑了一下,它显然是错误的,所以我纠正了它。

* 其他编辑 *

再想想,我原来的Python代码并没有那么高效,它只需要两次比较就可以完成,而原来的代码使用了三次:

[a if e < a else (b if e > b else e) for e in arr]
omqzjyyz

omqzjyyz1#

您可以使用np.clip
给定一个区间,区间外的值将被裁剪到区间边缘。例如,如果指定的间隔为[0,1],则小于0的值变为0,大于1的值变为1。
这比广播快。
代码示例:

import numpy as np

arr = np.array([-3, 5, 10, -7, 2, 8, -12, 15])

a = 0
b = 10

new_arr = np.clip(arr, a, b)
print(new_arr)

性能基准

For Array size of 1000
Method 1 (List comprehension) time: 0.0115 seconds
Method 2 (NumPy broadcasts) time: 0.0009 seconds
Method 3 (np.clip()) time: 0.0009 seconds

-----------------------------------------------------------------

For Array size of 10000
Method 1 (List comprehension) time: 0.1137 seconds
Method 2 (NumPy broadcasts) time: 0.0069 seconds
Method 3 (np.clip()) time: 0.0017 seconds

-----------------------------------------------------------------

For Array size of 100000
Method 1 (List comprehension) time: 1.3205 seconds
Method 2 (NumPy broadcasts) time: 0.1152 seconds
Method 3 (np.clip()) time: 0.0107 seconds

-----------------------------------------------------------------

For Array size of 1000000
Method 1 (List comprehension) time: 13.8250 seconds
Method 2 (NumPy broadcasts) time: 1.0064 seconds
Method 3 (np.clip()) time: 0.1973 seconds

相关问题