如何让数组中的所有值都落入一个范围内?

Ξέν*_*νος 2 python arrays numpy python-3.x

假设我有一个 NumPy 数组float,有正值和负值。我有两个数字,假设它们是a和b,a <= b并且[a, b]是一个(封闭的)数字范围。

\n

我想让所有数组都落入 range [a, b],更具体地说,我想用相应的终端值替换范围之外的所有值。

\n

我并不是试图缩放值以使数字适合一个范围,在 Python 中,这将是:

\n
mina = min(arr)\nscale = (b - a) / (max(arr) - mina)\n[a + (e - mina) * scale for e in arr]\n
Run Code Online (Sandbox Code Playgroud)\n

或者在 NumPy 中:

\n
mina = arr.min()\nscale = (b - a) / (arr.max() - mina)\na + (arr - mina) * scale \n
Run Code Online (Sandbox Code Playgroud)\n

我试图替换所有低于awith的值a和所有高于bwith 的值b,同时保持所有其他值不变,我可以在 Python 中的单个列表理解中完成此操作:

\n
[e if a <= e <= b else (a if e < a else b) for e in arr]\n
Run Code Online (Sandbox Code Playgroud)\n

我可以对两个广播执行相同的操作:

\n
arr[arr < a] = a\narr[arr > b] = b\n
Run Code Online (Sandbox Code Playgroud)\n

尽管 NumPy 比 Python 快得多,但上面是两个循环,而不是一个,该方法效率低下但可以编译。

\n

什么是更快的方法?

\n
\n

我测量过多次,Python 确实比预期慢很多:

\n
In [1]: import numpy as np\n\nIn [2]: numbers = np.random.random(4096) * 1024\n\nIn [3]: %timeit numbers[numbers < 256]\n16.1 \xc2\xb5s \xc2\xb1 219 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 100,000 loops each)\n\nIn [4]: %timeit numbers[numbers > 512]\n20.9 \xc2\xb5s \xc2\xb1 526 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 10,000 loops each)\n\nIn [5]: %timeit [e if 256 <= e <= 512 else (256 if e < 256 else 512) for e in numbers]\n927 \xc2\xb5s \xc2\xb1 101 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1,000 loops each)\n\nIn [6]: %timeit [e if 256 <= e <= 512 else (256 if e < 256 else 512) for e in numbers.tolist()]\n684 \xc2\xb5s \xc2\xb1 38.2 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1,000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n
\n

编辑

\n

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

\n
\n

另一个编辑

\n

再想一想,我原来的Python代码效率并不高,只需两次比较就可以完成,而原来使用了三个:

\n
[a if e < a else (b if e > b else e) for e in arr]\n
Run Code Online (Sandbox Code Playgroud)\n

Sha*_*m09 5

您可以使用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)
Run Code Online (Sandbox Code Playgroud)

性能基准

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

Run Code Online (Sandbox Code Playgroud)

在此输入图像描述