учитывая массив целых чисел, таких как
[1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5]
Мне нужно замаскировать элементы, которые повторяются больше, чем N
раз. Чтобы уточнить: основная цель состоит в том, чтобы получить массив логических масок, чтобы использовать его позже для вычисления биннинга.
Я придумал довольно сложное решение
import numpy as np
bins = np.array([1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5])
N = 3
splits = np.split(bins, np.where(np.diff(bins) != 0)[0]+1)
mask = []
for s in splits:
if s.shape[0] <= N:
mask.append(np.ones(s.shape[0]).astype(np.bool_))
else:
mask.append(np.append(np.ones(N), np.zeros(s.shape[0]-N)).astype(np.bool_))
mask = np.concatenate(mask)
например,
bins[mask]
Out[90]: array([1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5])
Есть ли лучший способ сделать это?
РЕДАКТИРОВАТЬ, № 2
Большое спасибо за ответы! Вот тонкая версия эталонного сюжета MSeifert. Спасибо за указание на меня simple_benchmark
. Показаны только 4 самых быстрых варианта:
Вывод
Идея, предложенная Флорианом Н и модифицированная Полом Панцером, кажется отличным способом решения этой проблемы, поскольку она довольно прямолинейна и numpy
единственна. Однако, если вы в порядке с использованием numba
, решение MSeifert превосходит другие.
Я решил принять ответ MSeifert в качестве решения, так как это более общий ответ: он правильно обрабатывает произвольные массивы с (неуникальными) блоками последовательных повторяющихся элементов. В случае numba
, если нет, ответ Divakar также стоит посмотреть!
Ответы:
Я хочу представить решение с использованием numba, которое должно быть довольно простым для понимания. Я предполагаю, что вы хотите «замаскировать» последовательные повторяющиеся элементы:
Например:
Представление:
Использование
simple_benchmark
- однако я не включил все подходы. Это логарифмическая шкала:Кажется, что решение numba не может превзойти решение от Paul Panzer, которое кажется немного быстрее для больших массивов (и не требует дополнительной зависимости).
Однако оба, кажется, превосходят другие решения, но они возвращают маску вместо «фильтрованного» массива.
источник
out
аргумент (или, возможно, функциональная форма оператора), поэтому я не смог сохранить эту копию. Кстати мне очень нравитсяsimple_benchmark
.simple_benchmark
! спасибо за это и спасибо, конечно, за ответ. Так как я использую иnumba
для других вещей, я склонен также использовать это здесь и сделать это решением. между камнем и наковальней ...Отказ от ответственности: это только более надежная реализация идеи @ FlorianH:
Для больших массивов это имеет огромное значение:
источник
[1,1,1,1,2,2,1,1,2,2]
.Подход № 1: Вот векторизованный способ -
Пробный прогон -
Подход № 2: немного более компактная версия -
Подход № 3: Использование сгруппированных подсчетов и
np.repeat
(хотя не даст нам маску) -Подход № 4: С помощью
view-based
метода -Подход № 5. С помощью
view-based
метода без индексов изflatnonzero
-источник
Вы можете сделать это с помощью индексации. Для любого N код будет:
вывод:
источник
timeit
прогонами.Гораздо приятнее было бы использовать
numpy
sunique()
-функцию. Вы получите уникальные записи в вашем массиве, а также количество их появления:вывод:
источник
Вы можете использовать цикл while, который проверяет, равен ли элемент массива N позициям назад текущему. Обратите внимание, что это решение предполагает, что массив упорядочен.
источник
len(question)
наlen(bins)
Вы можете использовать grouby общих элементов группы и список фильтров, которые больше чем N .
источник
Решение
Вы могли бы использовать
numpy.unique
. Переменнаяfinal_mask
может использоваться для извлечения элементов traget из массиваbins
.Выход :
источник
bins
и верно?final_values
непосредственно, вы можете раскомментировать единственным комментировала линию в растворе и в этом случае вы можете отказаться три линии:mask = ...
,final_mask = ...
иbins[final_mask]
.