Подход № 1
Вот один с np.argpartition
для повышения производительности -
N = 3
newval = 0
np.put_along_axis(a,np.argpartition(a,N,axis=1)[:,N:],newval,axis=1)
Объяснение: Мы разбиваем входной массив, чтобы получить индексы, которые разделены по для аргумента kth
в np.argpartition
. Итак, в основном рассмотрим это как два раздела, первый для наименьших N элементов вдоль этой оси, а другой для остальных. Нам нужно сбросить второй раздел, который мы выбираем с помощью [:,N:]
, и мы используем np.put_along_axis
для выполнения сброса.
Пример выполнения -
In [144]: a # input array
Out[144]:
array([[1, 2, 3, 4, 5],
[4, 3, 6, 1, 0],
[6, 5, 3, 1, 2]])
In [145]: np.put_along_axis(a,np.argpartition(a,3,axis=1)[:,3:],0,axis=1)
In [146]: a
Out[146]:
array([[1, 2, 3, 0, 0],
[0, 3, 0, 1, 0],
[0, 0, 3, 1, 2]])
Approach # 2
Вот еще один вариант с np.argpartition
, но просто нарезая N-й наименьший элемент на строку и затем сбрасывая все больше, чем он. Таким образом, если есть дубликаты для N-го наименьшего элемента, мы сохраним все те с этим методом. Вот реализация -
a[a>=a[np.arange(len(a)), np.argpartition(a,3,axis=1)[:,3],None]] = 0
Синхронизация в увеличенной версии -
In [184]: a = np.array([[1,2,3,4,5],[4,3,6,1,0],[6,5,3,1,2]])
In [185]: a = np.repeat(a,10000,axis=0)
In [186]: %timeit np.put_along_axis(a,np.argpartition(a,3,axis=1)[:,3:],0,axis=1)
1.78 ms ± 5.89 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [187]: a = np.array([[1,2,3,4,5],[4,3,6,1,0],[6,5,3,1,2]])
In [188]: a = np.repeat(a,10000,axis=0)
In [189]: %timeit a[a>=a[np.arange(len(a)), np.argpartition(a,3,axis=1)[:,3],None]] = 0
1.54 ms ± 54.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)