Вы не предоставили никаких подробностей о том, насколько велика test
, поэтому для оценки методов, которые я использовал, в ней есть 1000 элементов. Следующая важная часть состоит в том, чтобы фактически профилировать код. Вы не можете сказать, что это медленно (или быстро), пока не найдутся убедительные цифры, подтверждающие это. Ваш код работает на моем компьютере около 1,49 мс.
Вы можете часто получать улучшения с помощью numpy, удаляя циклы python и заменяя их на numpy функции.
Таким образом, вместо того, чтобы тестировать каждый элемент по отдельности (множество условий if
может замедлить процесс), я поместил все это в сравнение с одним массивом, а затем использовал all
, чтобы проверить, что каждый элемент соответствует.
check = array([False, True, False])
sum([(test[i:i+3]==check).all() for i in range(len(test) - 2)])
Профилирование показывает, что оно работает за 1,91 мс.
Это на самом деле шаг назад. Итак, что может быть причиной замедления? Что ж, доступ к массиву с использованием []
создает новый объект массива, который может быть его частью. Лучшим подходом может быть создание одного большого массива со смещениями, а затем использование трансляции для сравнения.
sum((c_[test[:-2], test[1:-1], test[2:]] == check).all(1))
На этот раз check
сравнивается с каждой строкой массива c_[test[:-2], test[1:-1], test[2:]]
. Аргумент оси (1) all
используется только для подсчета строк, которые соответствуют каждому элементу. Это работает в 40.1us. Это огромное улучшение.
Конечно, создание массива для широковещательной передачи будет сопряжено с большими затратами с точки зрения копирования элементов. Почему бы не сделать сравнения напрямую?
sum(all([test[i:len(test)-2+i]==v for i, v in enumerate(check)], 0))
Это работает в 18.7us.
Последняя идея ускорить процесс - это as_strided
. Это продвинутый трюк для изменения шагов массива, чтобы получить массив смещений без копирования каких-либо данных. Обычно это не стоит усилий, но я привожу их сюда просто для удовольствия.
sum((np.lib.index_tricks.as_strided(test, (len(test) - len(check) + 1, len(check)), test.strides + (1, )) == check).all(1))
Это также работает около 40us. Таким образом, дополнительные усилия ничего не добавляют в этом случае.