假设我有一个float
s的NumPy数组,有正值和负值。我有两个数字,假设它们是a
和b
,a <= 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]
1条答案
按热度按时间omqzjyyz1#
您可以使用
np.clip
给定一个区间,区间外的值将被裁剪到区间边缘。例如,如果指定的间隔为[0,1],则小于0的值变为0,大于1的值变为1。
这比广播快。
代码示例:
性能基准