Автор оригинала: Harshit Tyagi.
Сравнение производительности различных парадигм реализации в python
Для любой дисциплины, требующей больших объемов данных, одним из основных накладных расходов является ускорение научных и численных вычислений. С критически важным для производительности приложением и конвейером обработки данных возникает необходимость в оптимальной реализации парадигмы и выборе правильного набора библиотек. После работы над научными(метаболомика) и финансовыми проектами я решил собрать эти советы и рекомендации, которые я разработал и изучил.
Мотивация всего этого поста-это строка, которую мой наставник в Прояснить попросил меня усвоить и применить на практике:
Существует разница между написанием кода на python и написанием питонического кода.
В этом посте собраны лучшие(спорные) практики, касающиеся некоторых наиболее часто используемых операций обработки данных. Например, оценка сложных математических выражений, инициализация массивов с использованием реализации векторизации numpy, параллельные вычисления и многопоточность.
Функции, определяющие математические выражения
Работа с большим массивом чисел всегда является сложной задачей, и если есть числовая операция, которую нужно выполнить над этими элементами, история полностью меняется.
Допустим, существует математическое выражение, которое должно быть вычислено по массиву из 100 000 чисел: y = ⎷|sin(x) + cos(x)|
Создание списка чисел с помощью функции диапазона,
n = 1000000 data_num = range(n)
Давайте рассмотрим разнообразие реализаций и сравним все это в конце, используя библиотеку timeit:
- Очень простой и понятный подход заключается в циклическом переборе всего набора данных и добавлении выходных данных функции f(x)(определенной выше)к объекту списка выходных данных.
otpt = [] for x in data_list: otpt.append(f(x))
- Мы можем использовать итераторы:
return [f(x) for x in data_list]
- То же самое можно сделать с помощью метода eval() python:
exp = 'abs(cos(x) + sin(x)) ** 0.5' return [eval(exp) for x in data_list]
- Мы можем реализовать тот же алгоритм, используя тактику векторизации numpy.
import numpy as np data_np = np.arange(1000000) def f4(data_np): """using the numpy vectorization """ return (np.abs(np.cos(data_np) + sin(data_np)) ** 0.5)
- Другой библиотекой, которая специализируется на оценке таких числовых выражений, является numexpr. Причина, по которой эта библиотека оказывается очень удобной, заключается в встроенной поддержке многопоточности.
import numexpr as ne ex = 'abs(cos(a) + sin(a)) ** 0.5' ne.set_num_threads(5) return ne.evaluate(ex)
Мы перечислили 5 различных парадигм для выполнения одной и той же операции. Пришло время проверить, привели ли они к одному и тому же результату или нет.
Запись выходных данных каждой функции в виде tpt1, tpt2 и так далее и тому подобное.
Мы можем использовать метод numpy allclose() для проверки двух объектов ndarray.
np.allclose(otpt1, otpt2) np.allclose(otpt1, otpt3) np.allclose(otpt1, otpt4) np.allclose(otpt1, otpt5)
Все они должны вернуться к истине, чтобы мы могли взглянуть на самый важный вопрос, который является фокусом этого блога:
Как каждая из этих различных парадигм сравнивается с точки зрения времени обработки. Вот функция, которая поможет нам получить тайминги каждой функции.
После передачи необходимых аргументов в приведенную выше функцию, которая использует время, которое она повторяет, чтобы оценить время и отсортировать наблюдаемые значения.
function_list = ['f1', 'f2', 'f3', 'f4', 'f5'] data_com_list = ['data_num', 'data_num', 'data_num', 'data_np', 'data_np'] record_comp_time(function_list, data_com_list)
Мы получаем следующие скорости производительности.
Как видно из результатов сравнения, функция, использующая numexpr , выдает результат в рекордно короткие сроки, за которым следует функция 4, которая является функцией, использующей библиотеку numpy.
Вот ссылка на мой репозиторий GitHub для всей базы кода:
коды харшита/python_paradigms __A руководство по: Как сравнить различные парадигмы реализации в python? – коды харшита/python_paradigms_github.com
Вывод
Для каждой операции, требующей больших объемов данных, у python есть несколько способов повысить производительность вашего кода. Учитывая проблему, над оптимальностью можно работать, используя правильную комбинацию различных парадигм и выбор библиотек. Помимо парадигм, есть несколько очень полезных библиотек, которые улучшают скорость выполнения кода python.
Точно так же, как numexpr имеет большой спектр операций, которые делают численную оценку более плавной и быстрой, есть
- Cython который объединяет легкость написания python со скоростью C.
- Numba ,- он динамически компилирует код python для процессора.
- Встроенный модуль Python многопроцессорная обработка для параллельной обработки
И считать…
В следующих постах я поделюсь некоторыми советами и рекомендациями по операциям ввода-вывода с использованием панд, параллельных вычислений и компиляции.
Оставайтесь с нами для получения дополнительной информации…