Python Numpy 相当于没有循环的 if/else

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45768262/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 17:17:11  来源:igfitidea点击:

Numpy equivalent of if/else without loop

pythonnumpyvectorization

提问by pd shah

is there any pythonic way to remove for loop and if/else in the code below.

在下面的代码中是否有任何pythonic方法可以删除for循环和if/else。

this code iterating over a NumPy array and check a condition and according to the condition change the value.

此代码迭代 NumPy 数组并检查条件并根据条件更改值。

>>> import numpy as np
>>> x=np.random.randint(100, size=(10,5))
>>> x
array([[79, 50, 18, 55, 35],
       [46, 71, 46, 95, 52],
       [97, 37, 71,  2, 79],
       [80, 96, 60, 85, 72],
       [ 6, 52, 63, 86, 38],
       [35, 50, 13, 93, 54],
       [69, 21,  4, 40, 53],
       [83,  7, 30, 16, 78],
       [18, 34, 91, 67, 89],
       [82, 16, 16, 24, 80]])

>>> for i in range(x.shape[0]):
    for j in range(x.shape[1]):
        if x[i,j]>50:
            x[i,j]=0
        elif x[i,j]<50:
            x[i,j]=1


>>> x
array([[ 0, 50,  1,  0,  1],
       [ 1,  0,  1,  0,  0],
       [ 0,  1,  0,  1,  0],
       [ 0,  0,  0,  0,  0],
       [ 1,  0,  0,  0,  1],
       [ 1, 50,  1,  0,  0],
       [ 0,  1,  1,  1,  0],
       [ 0,  1,  1,  1,  0],
       [ 1,  1,  0,  0,  0],
       [ 0,  1,  1,  1,  0]])

I want to do same thing without loops and if statement. something like below dose not work, because of changes on the array:

我想在没有循环和 if 语句的情况下做同样的事情。由于阵列上的变化,以下内容不起作用:

>>> import numpy as np
>>> x=np.random.randint(100, size=(10,5))
>>> x
array([[ 2, 88, 27, 67, 29],
       [62, 44, 62, 87, 32],
       [80, 95, 31, 30, 33],
       [14, 41, 40, 95, 27],
       [53, 30, 35, 22, 98],
       [90, 39, 74, 28, 73],
       [10, 71,  0, 11, 37],
       [28, 25, 83, 24, 93],
       [30, 70, 15,  5, 79],
       [69, 43, 85, 68, 53]])
>>> x[x>50]=0
>>> x[x<50]=1
>>> x
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]])

UPDATEand what happend if there are more conditions like :

更新以及如果有更多条件会发生什么,例如:

   >>> import numpy as np
    >>> x=np.random.randint(100, size=(10,5))
    >>> x
    array([[87, 99, 70, 32, 28],
           [38, 76, 89, 17, 34],
           [28,  1, 40, 34, 67],
           [45, 47, 69, 78, 89],
           [14, 81, 46, 71, 97],
           [39, 45, 36, 36, 25],
           [87, 28,  1, 46, 99],
           [27, 98, 37, 36, 84],
           [55,  2, 23, 29,  9],
           [34, 79, 49, 76, 48]])
    >>> for i in range(x.shape[0]):
        for j in range(x.shape[1]):
            if x[i,j]>90:
                x[i,j]=9
            elif x[i,j]>80:
                x[i,j]=8
            elif x[i,j]>70:
                x[i,j]=7
            elif x[i,j]>60:
                x[i,j]=6
            elif x[i,j]>50:
                x[i,j]=5
            elif x[i,j]>40:
                x[i,j]=4
            else:
                x[i,j]=0


    >>> x
    array([[8, 9, 6, 0, 0],
           [0, 7, 8, 0, 0],
           [0, 0, 0, 0, 6],
           [4, 4, 6, 7, 8],
           [0, 8, 4, 7, 9],
           [0, 4, 0, 0, 0],
           [8, 0, 0, 4, 9],
           [0, 9, 0, 0, 8],
           [5, 0, 0, 0, 0],
           [0, 7, 4, 7, 4]])

回答by Divakar

One IF-ELIF

一个 IF-ELIF

Approach #1One approach -

方法 #1一种方法 -

keep_mask = x==50
out = np.where(x>50,0,1)
out[keep_mask] = 50


Approach #2Alternatively, for in-situ edit -

方法#2或者,对于原位编辑 -

replace_mask = x!=50
x[replace_mask] = np.where(x>50,0,1)[replace_mask]
# Or (x<=50).astype(int) in place of np.where(x>50,0,1)


Code-golf?If you actually want to play code-golf/one-liner -

代码高尔夫?如果你真的想玩代码高尔夫/单线 -

(x<=50)+(x==50)*49


Multiple IF-ELIFs

多个 IF-ELIF

Approach #1

方法#1

For a bit more generic case involving more if-elif parts, we could make use of np.searchsorted-

对于涉及更多 if-elif 部分的更通用的情况,我们可以使用np.searchsorted-

out_x = np.where(x<=40,0, np.searchsorted([40,50,60,70,80,90], x)+3)

回答by Daniel F

A one-liner that does everything your loops does:

一个单线,可以完成你的循环所做的一切:

x[x != 50] = x[x != 50] < 50

EDIT:

编辑:

For your extended question, you'd want something like:

对于您的扩展问题,您需要以下内容:

bins = [40, 50, 60, 70, 80, 90, 100]
out = np.digitize(x, bins, right = 1)
out[out.astype(bool)] += 3

回答by benjaminudoh10

np.where(x < 50, 0, 1)

This should be enough. You don't need to keep a mask value for 50 since 50 is neither less than nor greater than 50. Hope this helps.

这应该足够了。您不需要保留 50 的掩码值,因为 50 既不小于也不大于 50。希望这会有所帮助。

回答by MarcelF

Sorry for being late to the party, just wanted to share another approach to the problem.

抱歉迟到了,只是想分享另一种解决问题的方法。

One-Line Solution:

单线解决方案

x = np.where(x>=50, 50, 1) + np.where(x>50, -50, 0)

x = np.where(x>=50, 50, 1) + np.where(x>50, -50, 0)

Rationale:

理由

We can sum over the following two numpy.where-matrices:

我们可以总结以下两个 numpy.where-matrices:

  • For matrix A: if x[i,j] >= 50, then set value 50, otherwise 1 because we want x[i,j]<50 to be equal to 1.
  • For matrix B: if x[i,j] > 50, then set value -50, thus for x[i,j]>50 the sum over both matrices will yield value 0 for the corresponding elements.
  • 对于矩阵 A:如果 x[i,j] >= 50,则设置值 50,否则设置为 1,因为我们希望 x[i,j]<50 等于 1。
  • 对于矩阵 B:如果 x[i,j] > 50,则设置值 -50,因此对于 x[i,j]>50,两个矩阵的总和将为相应的元素产生值 0。

By calculating A+B, the values set for conditions x>50 (i.e. -50) and x>=50 (i.e. 50) yield the wanted values (0 and 50) and do not interfere with values set for x<50.

通过计算 A+B,为条件 x>50(即 -50)和 x>=50(即 50)设置的值产生想要的值(0 和 50)并且不会干扰为 x<50 设置的值。

Update for UPDATE

更新更新

x = np.where(x>40, 4, 0) + np.where(x>50, 1, 0) + np.where(x>60, 1, 0) + np.where(x>70, 1, 0) + np.where(x>80, 1, 0) + np.where(x>90, 1, 0)

Or shorter, if we can rely on the fact that values are always smaller than 100 (change dtype if you want integers):

或者更短,如果我们可以依赖值总是小于 100 的事实(如果你想要整数,请更改 dtype):

x = np.where(x>40, np.floor(x/10), 0)

For me this code is quite readable, but I may not be representative.

对我来说,这段代码可读性很强,但我可能不具有代表性。

回答by benjaminudoh10

np.where(x < 50, 0, 1)

This should be enough. You don't need to keep a mask value for 50 since 50 is neither less than nor greater than 50. Hope this helps.

这应该足够了。您不需要保留 50 的掩码值,因为 50 既不小于也不大于 50。希望这会有所帮助。

Update

更新

#update
np.where(x < 40, 0, x)
np.where(x > (x - (x % 10)), x // 10, x)