Python:检查数组的列是否在边界内,如果不在边界内则选择一个随机数

Python: check if columns of array are within boundaries, if not pick a random number within the boundary

我有一个

形式的数组
a = np.array([[1,2],[3,4],[5,6]])

我有一个 "domain" 或边界,它又是一个形式为

的数组
b = np.array([[0, 4], [3,7]])

基本上我想检查 a[:,0]b 的第一行内,a[:,1]b 的第二行内。例如在这个例子中 a[:,0]=[1,3,5] 我们可以看到它们都有效,除了大于 4 的 5。类似地 a[:,1] = [2,4,6] 所以我们看到 2 失败,因为 2<3.

所以基本上我想要 0 <= a[:,0] <= 43 <= a[:,1]<=7。当一个数字超出这个边界时,我想基本上用边界内的随机数替换它。

我的尝试

a[:,0][~np.logical_and(b[0][0] <= a[:,0], a[:,0] <= b[0][1])] = np.random.uniform(b[0][0], b[0][1])

a[:,1][~np.logical_and(b[1][0] <= a[:,1], a[:,1] <= b[1][1])] = np.random.uniform(b[1][0], b[1][1])

有faster/better方法吗?

方法 #1: 这是一种方法 -

# Invalid mask where new values are to be put
mask = (a < b[:,0]) | (a > b[:,1])

# Number of invalid ones per column of a
count = mask.sum(0)

# Get lengths for range limits set by b
lens = b[:,1] - b[:,0]

# Scale for uniform random number generation
scale = np.repeat(lens, count)

# Generate random numbers in [0,1)
rand_num = np.random.rand(count.sum())

# Get offset for each set of random numbers. Scale and add offsets to get
#equivalent of all the original code uniform rand number generation
offset = np.repeat(b[:,0], count)
put_num = rand_num*scale + offset

# Finally make a copy as a float array and assign using invalid mask
out = a.copy().astype(float)
out.T[mask.T] = put_num

样本运行-

In [1004]: a
Out[1004]: 
array([[1, 2],
       [7, 4],
       [5, 6]])

In [1005]: b
Out[1005]: 
array([[ 2,  6],
       [ 5, 12]])

In [1006]: out
Out[1006]: 
array([[ 2.9488404 ,  8.97938277],
       [ 4.51508777,  5.69467752],
       [ 5.        ,  6.        ]])
# limits:  [2, 6]       [5, 12]

方法 #2: 另一种方法是生成与 a 形状相同的缩放和偏移随机数,并简单地使用 np.where 和在生成的随机数和 a 之间进行选择的无效掩码。实现会更简单,像这样 -

rand_nums = np.random.rand(*a.shape)*(b[:,1] - b[:,0]) + b[:,0]
mask = (a < b[:,0]) | (a > b[:,1])
out = np.where(mask, rand_nums, a)
import numpy as np
a = np.array([[1,2],[3,4],[5,6]])
b = np.array([[0,4], [3,7]])
for iter in range(np.size(a,1)):
    index = np.where(np.logical_or(a[:,iter]<b[0,iter], a[:,iter]>b[1,iter]))
    if len(index)!=0:
        a[index,iter] = np.random.random_integers(b[0,iter], b[1,iter], size=[len(index),1])

这应该能满足您的需求:)