Make numpy matrix more sparse

2019-02-26 05:54发布

问题:

Suppose I have a numpy array

np.array([
    [3, 0, 5, 3, 0, 1],
    [0, 1, 2, 1, 5, 2],
    [4, 3, 5, 3, 1, 4],
    [2, 5, 2, 5, 3, 1],
    [0, 1, 2, 1, 5, 2],
])

Now, I want to randomly replace some elements with 0. So that I have an output like this

np.array([
    [3, 0, 0, 3, 0, 1],
    [0, 1, 2, 0, 5, 2],
    [0, 3, 0, 3, 1, 0],
    [2, 0, 2, 5, 0, 1],
    [0, 0, 2, 0, 5, 0],
])

回答1:

We can use np.random.choice(..., replace=False) to randomly select a number of unique non-zero flattened indices and then simply index and reset those in the input array.

Thus, one solution would be -

def make_more_sparsey(a, n):
    # a is input array
    # n is number of non-zero elements to be reset to zero
    idx = np.flatnonzero(a) # for performance, use np.flatnonzero(a!=0)
    np.put(a, np.random.choice(idx, n, replace=False),0)
    return a

Sample run -

In [204]: R = np.array([
     ...:     [3, 0, 5, 3, 0, 1],
     ...:     [0, 1, 2, 1, 5, 2],
     ...:     [4, 3, 5, 3, 1, 4],
     ...:     [2, 5, 2, 5, 3, 1],
     ...:     [0, 1, 2, 1, 5, 2],
     ...: ])

In [205]: make_more_sparsey(R, n=5)
Out[205]: 
array([[3, 0, 5, 3, 0, 1],
       [0, 1, 0, 0, 5, 2],
       [4, 3, 5, 3, 1, 4],
       [2, 5, 0, 5, 3, 1],
       [0, 1, 0, 1, 0, 2]])


回答2:

Use np.ravel or the ravel method to create a flattened. Note that the flatten method always creates a copy, so mutating won't work.

a = np.array([
    [3, 0, 5, 3, 0, 1],
    [0, 1, 2, 1, 5, 2],
    [4, 3, 5, 3, 1, 4],
    [2, 5, 2, 5, 3, 1],
    [0, 1, 2, 1, 5, 2],
])
r = a.ravel()
r[random.randrange(0, len(r))] = 0