Почему стал таким медленным мой алгоритм, вычислив стандартное отклонение используя np.std?

Недавно спросите, как он мог улучшать скорость вычисления в программе, которая определяла средний показатель n периоды внутри списка, улучшался мой очень много разы, я использую этот же самый алгоритм и общую идею (или в это верю я), чтобы вычислять сейчас другой фактор, который: средняя стоимость + (n отклонения * стандартное отклонение средней стоимости) и скорость внизу очень много, я использую np.std, чтобы вычислять отклонение.

Это код, который вычисляет среднюю стоимость в n периоды:

from random import uniform
from time import time


cierre = []
for i in range(1000000):
    cierre.append(uniform(1, 2))

tiempo_inicial = time()
periodos = 20
suma = sum(cierre[1:periodos + 1])
sma = [cierre[periodos]] * periodos + [suma/periodos]

for i in range (periodos+1, len(cierre)):
    suma = suma - cierre[i - periodos] + cierre[i]
    sma.append(suma/periodos)

tiempo_total = time() - tiempo_inicial

print(tiempo_total)

Для 1 миллиона стоимости опоздай 0.76 секунд

Сейчас это мое пере-осуществление со стандартным вычислением отклонений и фактора, который я прокомментировал наверху:

from random import uniform
from time import time
import numpy as np 

cierre = []
for i in range(1000000):
    cierre.append(uniform(1, 2))

tiempo_inicial = time()

periodos = 20
desviaciones = 2

suma = sum(cierre[1:periodos + 1])
desv = np.std(cierre[1:periodos + 1])
media = [cierre[periodos]] * periodos + [suma/periodos]
alta = [cierre[periodos]] * periodos + [(suma/periodos) + (desviaciones * desv)]
baja = [cierre[periodos]] * periodos + [(suma/periodos) - (desviaciones * desv)]

for i in range (periodos+1, len(cierre)):
    suma = suma - cierre[i - periodos] + cierre[i]
    desv = np.std(cierre[i+1 - periodos:i + 1])
    media.append(suma/periodos)
    alta.append((suma/periodos) + (desviaciones * desv))
    baja.append((suma/periodos) - (desviaciones * desv))

tiempo_total = time() - tiempo_inicial
print(tiempo_total)

Для 1 миллиона данных опоздай 58.43 секунды: очень много! Как дело в том, что я это разложил? или под логикой, которую я продолжил, - нормальное это время. я думал, что время было бы в очень в 3 раза больше, чем первое вычисление, но это не было так.

Даже мой прошлый алгоритм, и который я думаю, - очень плохой я выравниваю время:

from random import uniform
from time import time
import numpy as np 

cierre = []
for i in range(1000000):
    cierre.append(uniform(1, 2))

tiempo_inicial = time()

sma = []
alta = []
baja = []
periodos = 20
desviaciones = 2
lista_inicial = []

for i in range(len(cierre)):
    if i > periodos:
        del lista_inicial[0]
        lista_inicial.append(cierre[i])
        media = sum(lista_inicial) / periodos
        desviacion_estandar = np.std(lista_inicial)
        sma.append(media)
        alta.append(media + (desviaciones * desviacion_estandar))
        baja.append(media - (desviaciones * desviacion_estandar))

    elif i < periodos:
        sma.append(cierre[periodos])
        alta.append(cierre[periodos])
        baja.append(cierre[periodos])
    else:
        for j in range(i, i - periodos, -1):
            lista_inicial.append(cierre[j])
        lista_inicial.reverse()
        media = sum(lista_inicial) / len(lista_inicial)
        desviacion_estandar = np.std(lista_inicial)
        sma.append(media)
        alta.append(media + (desviaciones * desviacion_estandar))
        baja.append(media - (desviaciones * desviacion_estandar))

tiempo_total = time() - tiempo_inicial

print(tiempo_total)

В чем я не удался?

Спасибо

1
задан 20.12.2016, 22:34
2 ответа

Поскольку он логичен, чтобы вычислять стандартное отклонение, мы нуждаемся в среднем показателе. Этот метод вычисляет активно средний показатель для твоего особенного случая, но проблема - что numpy.std() он не допускает, что мы перемещаем его средний показатель, который активно уже мы считаем исчисленным, и вновь вычисляет ее, что излишек, который мы не хотим.

Как ты сами комментируешь, что он существует statistics.pstdev() в стандартной библиотеке Пайтона, что, если он позволяет перемещать его как второй параметр предисчисленный средний показатель, но были гораздо более медленной, чем numpy.std() мы ничего не зарабатываем, даже теряем время.

Как я комментировал тебе, что решение состояло бы в том, чтобы вычислять стандартное отклонение мы сами, чтобы использовать средний показатель, который уже у нас есть. Я нашел возможное решение используя NumPy.

Мы знаем, что стандартное отклонение - только квадратный корень дисперсии. Дисперсия - средний показатель различий со средним показателем, поднятый до квадрата. Ну хорошо Numpy смоги делать это очень работоспособным. Если у нас есть средний показатель и array, мы можем вычислять различия как:

dif = numpy.array - происходи

Чтобы вычислять квадраты и Вашу сумму активно мы можем использовать numpy.dot():

cuadrados_dif = numpy.dot (dif, dif)

Сейчас мы вычисляем средний показатель квадратов различий деля из-за числа элементов (в твоем случае это переменная periodos) и мы вычисляем квадратный корень (используя math.sqrt() или поднимая 0.5).

Остался бы таким твой код:

from random import uniform
from time import time
import numpy as np
from math import sqrt

cierre = []
for i in range(1000000):
    cierre.append(uniform(1, 2))

tiempo_inicial = time()

periodos = 20
desviaciones = 2

suma = sum(cierre[1:periodos + 1])
desv = np.std(cierre[1:periodos + 1])
media = [cierre[periodos]] * periodos + [suma/periodos]
alta = [cierre[periodos]] * periodos + [(suma/periodos) + (desviaciones * desv)]
baja = [cierre[periodos]] * periodos + [(suma/periodos) - (desviaciones * desv)]

for i in range (periodos+1, len(cierre)):
    suma = suma - cierre[i - periodos] + cierre[i]
    med = suma/periodos
    aux = np.array(cierre[i+1 - periodos:i + 1]) - med
    desv = sqrt(np.dot(aux, aux)/periodos)
    media.append(med)
    alta.append(med + (desviaciones * desv))
    baja.append(med - (desviaciones * desv))

tiempo_total = time() - tiempo_inicial
print(tiempo_total)

Время для меня сокращается с 41.28 секунд до 8.96 секунд для array 1 миллиона целых чисел и происходит с 416.65 секунд до 90.25 секунд для одного из 10 миллионов, что представляет сокращение времени 78 %. Я думаю, что matemáticamente я не поместил лапу, я сравнил какие-то выводы случайным образом и оба кода они дают тот же результат, но подтверди результаты используя тот же array игры из-за тебя самого... :)

3
ответ дан 24.11.2019, 11:57
  • 1
    ¡ Ты má хина! большое спасибо, не conocí в эту funció n np.dot –  Samael Olascoaga 21.12.2016, 03:57

Проблема появляется с for что в Пайтоне медленный. Обычно, numpy он используется, чтобы мочь использовать операции vectorizadas, что позволяют предотвращать использование циклов.

Я сделал версию vectorizada из твоей проблемы, которую я не понимаю очень хорошо, потому что индексы мне кажутся перемещёнными, и сравнил ее с начальной твоей. Различие во времени вычисления бездонное и результаты кажутся сходными.

Использование np.random.uniform вместо random.uniform и ты можешь удалять зерно (np.random.seed), только это, чтобы мочь воспроизводить примеры.

from random import uniform
from time import time
import numpy as np 

cierre = np.random.uniform(1, 2, 1000000)

tiempo_inicial = time()

periodos = 20
desviaciones = 2

suma = sum(cierre[1:periodos + 1])
desv = np.std(cierre[1:periodos + 1])
media = [cierre[periodos]] * periodos + [suma/periodos]
alta = [cierre[periodos]] * periodos + [(suma/periodos) + (desviaciones * desv)]
baja = [cierre[periodos]] * periodos + [(suma/periodos) - (desviaciones * desv)]


def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

sumaarr = np.sum(rolling_window(cierre[2:], 20), axis=1)
desvarr = np.std(rolling_window(cierre[2:], 20), axis=1)

mediaarr = np.append(media, sumaarr/periodos)
altaarr = np.append(alta, (sumaarr/periodos) + (desviaciones * desvarr))
bajaarr = np.append(baja, (sumaarr/periodos) - (desviaciones * desvarr))

tiempo_total = time() - tiempo_inicial
print(tiempo_total)

######################################################################


tiempo_inicial = time()

periodos = 20
desviaciones = 2

suma = sum(cierre[1:periodos + 1])
desv = np.std(cierre[1:periodos + 1])
media = [cierre[periodos]] * periodos + [suma/periodos]
alta = [cierre[periodos]] * periodos + [(suma/periodos) + (desviaciones * desv)]
baja = [cierre[periodos]] * periodos + [(suma/periodos) - (desviaciones * desv)]

for i in range (periodos+1, len(cierre)):
    suma = suma - cierre[i - periodos] + cierre[i]
    desv = np.std(cierre[i+1 - periodos:i + 1])
    media.append(suma/periodos)
    alta.append((suma/periodos) + (desviaciones * desv))
    baja.append((suma/periodos) - (desviaciones * desv))

tiempo_total = time() - tiempo_inicial
print(tiempo_total)

######################################################################

print(mediaarr[-5:])
print(media[-5:])
print(altaarr[-5:])
print(alta[-5:])
print(bajaarr[-5:])
print(baja[-5:])

В первой части находится твой код vectorizado. Я сохраняю результаты в переменных nombreloqueseaarr. Во второй части estú твой первоначальный код. Результаты сохраняют в переменных nombreloquesea В третьей части кода сравниваются результаты.

Пример вывода:

0.4660000801086426
23.439000129699707
[ 1.35230779  1.31052786  1.30012336  1.30526097  1.35144369]
[1.3523077875441034, 1.3105278577699528, 1.3001233584787273, 1.3052609662130137,
 1.3514436884966892]
[ 1.81071186  1.70910241  1.71348813  1.72520832  1.82857868]
[1.8107118591261553, 1.7091024102156576, 1.7134881323550406, 1.7252083196496959,
 1.8285786831530464]
[ 0.89390372  0.91195331  0.88675858  0.88531361  0.87430869]
[0.89390371596205154, 0.91195330532424823, 0.88675858460241397, 0.88531361277633
147, 0.87430869384033194]

Где первая линия - время первой части, вторая линия - время второй части и остального звука результатов с обеими частями кода, чтобы видеть, сходные ли результаты.

P.D.: Функция rolling_window я достал ее отсюда, но панды есть много у функциональности rolling, что позволяет тебе приступать к этим проблемам простой формы.

2
ответ дан 24.11.2019, 11:57
  • 1
    Большое спасибо, он подал мне достаточно функциональность rolling –  Samael Olascoaga 22.12.2016, 01:02
  • 2
    Уже я это тестировал животный прогресс во временах, не sabí ни во что относительно rolling window, если он хотел изучить этого ¿ có mo podrí чтобы это делать? ¿ что я должен знать раньше, или который могу читать? –  Samael Olascoaga 22.12.2016, 01:30
  • 3
    rolling window является совсем не специальным. Только ты применяешь операции к окнам данных, нет многий, который читать. ЕСЛИ снопы cá lculos этого типа numpy он стоит тебе, но панды уже он приносит ее из серии. –  kikocorreoso 22.12.2016, 08:40

Теги

Похожие вопросы