Numpy: 给定标量条件列表的1-D数组np.select

1 投票
3 回答
688 浏览
提问于 2025-04-17 19:09

我想实现这样的功能:

def choozer(my_1D_array):
    newArray = np.zeros((len(my_1D_array), 5))
    for x in enumerate(my_1D_array):
        if x[1]<3:
            y = np.array([1,1,1,1,1]) #the y's can be any array of random values
        elif 3<=x[1]<=5:
            y = np.array([2,2,2,2,2])# don't need to be repeated
        elif x[1]>5:
            y = np.array([3,3,3,3,3])
        newArray[x[0]] = y
    return newArray

这个方法有效……但对我来说感觉有点绕,而且在我的应用中效率很重要。所以我想到可以用np.select来做个比较:

def np_choozer(my_1D_array):
    condlist = [my_1D_array<3, 
                np.logical_and((3<=my_1D_array),(my_1D_array<=5)), 
                my_1D_array>5]
    choicelist = [np.array([1,1,1,1,1]),
                  np.array([2,2,2,2,2]),
                  np.array([3,3,3,3,3])]
    return np.select(condlist, choicelist)

……但没有成功。它在轴1上返回了选择列表的值。有没有更好的方法来解决我上面提到的问题呢?

提前谢谢你。

3 个回答

0

这个,

import numpy as np

a = np.arange(10)

one = np.ones((5,a.shape[0]))
two = 2 * one
thr = 3 * one

def choozer(a):
    condlist = [a<3, np.logical_and((3<=a),(a<=5)), a>5]
    choicelist = [one,two,thr]
    return np.select(condlist, choicelist).T

print choozer(a)

会得到这个,

[[ 1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.]
 [ 2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.]
 [ 3.  3.  3.  3.  3.]
 [ 3.  3.  3.  3.  3.]
 [ 3.  3.  3.  3.  3.]
 [ 3.  3.  3.  3.  3.]]
1

也许可以用 np.select 写得更好,但你总是可以这样做:

newArray = np.zeros(my_1D_array.shape + (5,))
newArray[np.where(my_1D_array < 3)] = 1
newArray[np.where((my_1D_array >= 3) & (my_1D_array <= 5)] = 2
newArray[np.where(my_1D_array > 5)] = 3

这是一个例子:

>>> a = np.random.rand(10) * 10
>>> b = np.empty(a.shape + (5,))
>>> b[np.where(a < 3)] = 1
>>> b[np.where((a >= 3) & (a <= 5))] = 2
>>> b[np.where(a > 5)] = 3
>>> b
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 2.,  2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 3.,  3.,  3.,  3.,  3.]])

编辑 上面的代码利用了赋值中的广播功能,不过 123 可以用一个包含5个元素的列表或数组来替代。使用和上面例子相同的 ab

>>> b[np.where(a < 3)] = np.arange(5)
>>> b[np.where((a >= 3) & (a <= 5))] = np.arange(5) + 10
>>> b[np.where(a > 5)] = np.arange(5) + 20
>>> b
array([[  0.,   1.,   2.,   3.,   4.],
       [ 20.,  21.,  22.,  23.,  24.],
       [ 10.,  11.,  12.,  13.,  14.],
       [ 20.,  21.,  22.,  23.,  24.],
       [  0.,   1.,   2.,   3.,   4.],
       [ 20.,  21.,  22.,  23.,  24.],
       [ 20.,  21.,  22.,  23.,  24.],
       [ 20.,  21.,  22.,  23.,  24.],
       [  0.,   1.,   2.,   3.,   4.],
       [ 20.,  21.,  22.,  23.,  24.]])
0

np_choozermy_1D_array.reshape(-1,1) 的结果是正确的。谢谢你们的帮助……不过我还是想看看有没有其他人能想出更好的方法。

撰写回答