Установить 0 x% ненулевых значений в массиве numpy 2d

#python-3.x #numpy

#python-3.x #numpy

Вопрос:

Я пробовал разные способы, но мне кажется невозможным сделать это эффективно без цикла.

Входные данные — это массив y и процент x.

например, входные данные

 y=np.random.binomial(1,1,[10,10])
x=0.5
  

вывод

 [[0 0 0 0 1 1 1 1 0 1]
 [1 0 1 0 0 1 0 1 0 1]
 [1 0 1 1 1 1 0 0 0 1]
 [0 1 0 1 1 0 1 0 1 1]
 [0 1 1 0 0 1 1 1 0 0]
 [0 0 1 1 1 0 1 1 0 1]
 [0 1 0 0 0 0 1 0 1 1]
 [0 0 0 1 1 1 1 1 0 0]
 [0 1 1 1 1 0 0 1 0 0]
 [1 0 1 0 1 0 0 0 0 0]]
  

Комментарии:

1. Я думаю, вам нужно предоставить немного больше информации: вы имеете в виду какие-либо случайные x%?

2. обновил его. спасибо за отзыв

3. Что вы ожидаете получить?

4. как вы имеете в виду ожидаемый результат или ожидаемый ответ переполнения стека?

Ответ №1:

Вот один из них, основанный на masking

 def set_nonzeros_to_zeros(a, setz_ratio):
    nz_mask = a!=0
    nz_count = nz_mask.sum()
    z_set_count = int(np.round(setz_ratio*nz_count))

    idx = np.random.choice(nz_count,z_set_count,replace=False)
    mask0 = np.ones(nz_count,dtype=bool)
    mask0.flat[idx] = 0
    nz_mask[nz_mask] = mask0
    a[~nz_mask] = 0
    return a
  

Мы пропускаем генерацию всех индексов с np.argwhere/np.nonzero в пользу индекса на основе маскировки, чтобы сосредоточиться на производительности.

Пример запуска —

 In [154]: np.random.seed(0)
     ...: a = np.random.randint(0,3,(5000,5000))

# number of non-0s before using solution
In [155]: (a!=0).sum()
Out[155]: 16670017

In [156]: a_out = set_nonzeros_to_zeros(a, setz_ratio=0.2) #set 20% of non-0s to 0s

# number of non-0s after using solution
In [157]: (a_out!=0).sum()
Out[157]: 13336014

# Verify
In [158]: 16670017 - 0.2*16670017
Out[158]: 13336013.6
  

Ответ №2:

Есть несколько векторизованных методов, которые могут вам помочь, в зависимости от того, что вы хотите сделать:

 # Flatten the 2D array and get the indices of the non-zero elements
c = y.flatten()
d = c.nonzero()[0]
# Shuffle the indices and set the first 100x % to zero
np.random.shuffle(d)
x = 0.5
c[d[:int(x*len(d))]] = 0
# reshape to the original 2D shape
y = c.reshape(y.shape)
  

Без сомнения, здесь необходимо внести некоторые улучшения в эффективность.