Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy equivalent of if/else without loop

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

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

>>> 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:

>>> 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]]) 

UPDATE and 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]]) 
like image 656
pd shah Avatar asked Aug 19 '17 06:08

pd shah


1 Answers

One IF-ELIF

Approach #1 One approach -

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

Approach #2 Alternatively, for in-situ edit -

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

Approach #1

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

out_x = np.where(x<=40,0, np.searchsorted([40,50,60,70,80,90], x)+3) 
like image 107
Divakar Avatar answered Sep 19 '22 05:09

Divakar