Почему statistics.mean() работает так медленно?
Я сравнил производительность функции mean
из модуля statistics
и простого метода sum(l)/len(l)
, и по какой-то причине функция mean
оказывается очень медленной. Я использовал модуль timeit
с двумя наборами кода ниже для сравнения, и меня интересует, что может вызывать значительную разницу в скорости выполнения. Я использую Python 3.5.
from timeit import repeat
print(min(repeat('mean(l)',
'''from random import randint; from statistics import mean; \
l=[randint(0, 10000) for i in range(10000)]''', repeat=20, number=10)))
Код выше выполняется примерно за 0.043 секунды на моем компьютере.
from timeit import repeat
print(min(repeat('sum(l)/len(l)',
'''from random import randint; from statistics import mean; \
l=[randint(0, 10000) for i in range(10000)]''', repeat=20, number=10)))
Код выше выполняется примерно за 0.000565 секунды на моем компьютере.
Почему наблюдается такая значительная разница в скорости работы этих двух методов?
2 ответ(ов)
Если скорость является вашим приоритетом, используйте numpy
, scipy
или pandas
вместо стандартных средств для вычисления усреднения.
Вот пример кода:
from random import randint
from statistics import mean
import numpy as np
# Генерируем список случайных чисел
l = [randint(0, 10000) for i in range(10**6)]
# Вычисляем среднее значение с помощью стандартной библиотеки
mean(l)
# Выдает: 5001.992355
# Замеряем время выполнения
%timeit mean(l)
# Примерный результат: 1 цикл, лучшее из 3: 2.01 с за цикл
# Преобразуем список в массив numpy
a = np.array(l)
# Вычисляем среднее значение с помощью numpy
np.mean(a)
# Выдает: 5001.9923550000003
# Замеряем время выполнения
%timeit np.mean(a)
# Примерный результат: 100 циклов, лучшее из 3: 2.87 мс за цикл
Вывод: Использование numpy
делает вычисление в десятки раз быстрее — в моем примере это было примерно 700 раз быстрее, хотя стоит отметить, что numpy
не использует алгоритм суммирования Кахана, что может немного повлиять на точность результата.
Обе функции len()
и sum()
являются встроенными функциями Python, написанными на C и, что более важно, оптимизированными для быстрой работы с некоторыми типами объектов, такими как списки.
Вы можете ознакомиться с их реализацией здесь:
https://hg.python.org/sandbox/python2.7/file/tip/Python/bltinmodule.c
Функция statistics.mean()
является высокоуровневой функцией, написанной на Python. Посмотрите, как она реализована:
https://hg.python.org/sandbox/python2.7/file/tip/Lib/statistics.py
Вы увидите, что она использует внутреннюю функцию _sum()
, которая выполняет несколько дополнительных проверок по сравнению с встроенными функциями.
Самый быстрый способ проверить наличие значения в списке
Как измерить прошедшее время в Python?
Наиболее эффективный способ применения функции к массиву NumPy
Нахождение среднего значения списка
Как узнать время, затраченное на каждый тест при использовании unittest?