Разница в производительности при вычислении среднего значения
Столкнулся с интересной ситуацией. Написал код, чтобы проверить, так ли это.
Нам надо посчитать среднее арифметическое некоторых значений. Условие в том, что мы не знаем, сколько значений у нас будет в итоге. И прикол в том, что добавлять числа в массив и считать сумму массива после быстрее, чем считать сумму сразу, без добавления в массив.
import time
t0 = time.time()
for j in range(100000):
sm = 0
cn = 0
for i in range(150):
cn += 1
sm += i * (i + 1)
l = sm / cn
print('%.6f' % (time.time() - t0))
t0 = time.time()
for j in range(100000):
a = []
for i in range(150):
a.append(i * (i + 1))
l = sum(a) / len(a)
print('%.6f' % (time.time() - t0))
Вывод такой:
2.146408 - с суммой
1.838875 - с массивом
Вопрос, а почему второе быстрее?
Ответы (3 шт):
Потому что в первом случае на одно действие больше: ещё есть cn += 1. На это тоже тратится время.
Если для вас важна скорость выполнение - воспользуйтесь Numpy:
import numpy as np # pip install numpy
def orig1(N):
sm = 0
cn = 0
for i in range(N):
cn += 1
sm += i * (i + 1)
return sm / cn
def orig2(N):
a = []
for i in range(N):
a.append(i * (i + 1))
return sum(a) / len(a)
def np1(N):
return np.mean(np.arange(N) * np.arange(1, N+1))
сначала проверим правильность вычислений:
In [302]: orig1(150)
Out[302]: 7499.666666666667
In [303]: orig2(150)
Out[303]: 7499.666666666667
In [304]: np1(150)
Out[304]: 7499.666666666667
теперь скорость:
In [305]: %timeit orig1(150)
13.5 µs ± 71.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [306]: %timeit orig2(150)
13.3 µs ± 68.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [307]: %timeit np1(150)
7.72 µs ± 109 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Numpy покажет себя во всей красе для более крупных массивов - возьмем 1500 элементов вместо 150:
In [308]: %timeit orig1(1500)
177 µs ± 2.51 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [309]: %timeit orig2(1500)
153 µs ± 1.03 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [310]: %timeit np1(1500)
10.7 µs ± 147 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
тут уже разница не в разы, а на порядки)
Проверяем тезис о лишней операции cn += 1 в первом опыте:
import time
t0 = time.time()
for j in range(100000):
sm = 0
cn = 0
for i in range(150):
cn += 1
sm += i * (i + 1)
l = sm / cn
print('%.6f' % (time.time() - t0))
t0 = time.time()
for j in range(100000):
sm = 0
cn = 0
for i in range(150):
sm += i * (i + 1)
l = sm / (i+1)
print('%.6f' % (time.time() - t0))
t0 = time.time()
for j in range(100000):
a = []
for i in range(150):
a.append(i * (i + 1))
l = sum(a) / len(a)
print('%.6f' % (time.time() - t0))
Результаты соответственно:
2.877234
2.094582
2.381735
Т.е. убрали ненужную операцию, и скорость сразу стала лучше чем в вашем втором примере.