Removing p% of smallest numpy array

Viewed 69

I am using Python 3.7 and numpy 1.18. I have a multi-dimensional numpy array of shape (28, 28, 3) and within this np array, I want to remove the 20% of smallest weights. Removing the 20% of smallest weights means I mask such numbers with 0.

20% of (28, 28, 3) = 470.4 = 470 (after rounding-off).

So, for this np array, for the 470 smallest numbers, how can I mask them to zero?

Thanks!

1 Answers

For perf. efficiency, we can use np.argpartition -

# a is input ndarray
N = int(np.round(a.size*0.2))
a.flat[np.argpartition(a.flat,kth=N)[:N]] = 0

Sample case step-by-step run -

In [91]: np.random.seed(0)

In [92]: a = np.random.randint(10,100,(4,5))

In [93]: a
Out[93]: 
array([[54, 57, 74, 77, 77],
       [19, 93, 31, 46, 97],
       [80, 98, 98, 22, 68],
       [75, 49, 97, 56, 98]])

In [94]: n = 0.2 # ratio of total to be reset

In [95]: N = int(np.round(a.size*n)) # 4

In [96]: a.flat[np.argpartition(a.flat,kth=N)[:N]] = 0
# change 0 to new value to be set, if not zero

In [97]: a
Out[97]: 
array([[54, 57, 74, 77, 77],
       [ 0, 93,  0,  0, 97],
       [80, 98, 98,  0, 68],
       [75, 49, 97, 56, 98]])

Alternatively, we can get the threshold value and then compare and assign into masked one -

In [117]: threshold_val = a.flat[np.argpartition(a.flat,kth=N)[N]]

In [118]: a[a<threshold_val] = 0

In [119]: a
Out[119]: 
array([[54, 57, 74, 77, 77],
       [ 0, 93,  0,  0, 97],
       [80, 98, 98,  0, 68],
       [75, 49, 97, 56, 98]])

Or use np.percentile -

In [148]: a[a<np.percentile(a,20)] = 0

In [149]: a
Out[149]: 
array([[54, 57, 74, 77, 77],
       [ 0, 93,  0,  0, 97],
       [80, 98, 98,  0, 68],
       [75, 49, 97, 56, 98]])
Related