С развитием информационных технологий профессия DS стала чрезвычайно популярна. Сейчас почти каждый может имея ПК и установленный на нем стандартный пакет Python, анализировать данные и строить на их основе прогнозы.

Во многих случаях достаточно просто скачать библиотеку для анализа данных, и получить неплохие результаты. При этом процессы, происходящие внутри используемых пользователем библиотек, остаются за пределами понимания, что зачастую влечет за собой неспособности поверхностного пользователя правильно интерпретировать полученные данные, особенно если это нейросеть.

В статье представлен пример реализации спектрального анализа функции на примере реальных данных. Этот математический метод позволяет провести более глубокий анализ изменения функции переменной во времени, найти периодические составляющие. Его применение способно существенно повлиять на результат предсказания целевой переменной, поскольку позволяет учитывать сезонные и другие периодические колебания.

Предположим, перед аналитиком стоит задача исследовать информацию о количестве людей на сайте в определенное время в определенный день, имея выборку по посещению сайта за несколько месяцев каждые 30 минут. И сделать прогноз посещения на будущий период.

Данные по посещениям представлены на графике ниже

Как видно из графика, характер данных имеет явную периодическую составляющую. Разложим наши данные в ряд Фурье по следующей формуле.

Ниже представлена функция, которая принимает в качестве аргумента датафрейм с исходными данными. Эта функция использует только самые простые библиотеки, чтобы мы могли использовать декоратор компиляции. Расчет при большом объёме данных может занять значительное время, а компилятор ускоряет скорость расчета в 100 раз.

@numba.jit (nopython = True)
def period(df['SA']):
    a , b = [] , []
    a.append(dfv.mean())
    b.append(0)
    for i in range(1 , len(dfv)//2 + 1):
        p = 0
        q = 0
       for j in range(1, len(dfv)+1):
p = p + dfv[j - 1] * math.cos(2 * math.pi * i * j / len(dfv))
q = q + dfv[j - 1] * math.sin(2 * math.pi * i * j / len(dfv))
       a.append(2 / len(dfv) * p)
       b.append(2 / len(dfv) * q)
    gramma = []
    for i in range(len(a)):
k = (a[i] ** 2 + b[i] ** 2) * len(dfv) / 2
gramma.append( k )
    return a, b, gramma

Результатом работы этой функции являются три списка, два с коэффициентами a и b из формулы выше для разложения в ряд Фурье и один с квадратами амплитуды для построения графика периодограммы.

Ниже на графике представлены две кривые, одна - реальные данные, другая - это прогноз, использующий разложения данных в ряд Фурье с учетом всех гармонических составляющих (N/2), где N - число наблюдений. Как мы можем видеть, прогноз полностью совпадает с реальными данными.

Для определения наиболее значащих гармоник необходимо построить периодограмму. По оси х - это порядковый номер гармоники от 0 до Т/2, по оси Y - значение квадратов амплитуды, полученных из функции выше.

Полученный график периодограммы показывает какие гармоники являются наиболее значимыми, то есть оказывают наибольшее влияние на значение функции.

Для прогнозирования и анализа данных нам нужны только гармоники с высокой амплитудой, иначе нельзя будет использовать для прогнозирования, так как это приведёт к переобучению модели – точному соответствию тренировочной выборке и слабому результату на тестовой.

Реализовать выбор гармоник с самой высокой амплитудой можно следующим образом:

zn = [0,4,8,20,24,28]
for i in range(len(a)):
if i not in zn:
a[i] , b[i] = 0,0
prog = []
for i in range(1 , len(df) + 1):
    r = 0
    for j in range(len(a)):
        r = r + a[j] * cos(2 * pi * j * i/len(df)) + b[j] * sin(2 * pi * j * i/len(df))
prog.append(r)

y1 = df['SA']
y2 = prog
fig , ax = plt.subplots()
plt.plot(x, y1 , c = 'hotpink' , linewidth = 4 ,label ='Данные')
plt.plot(x, y2, c = 'Black', linewidth = 3,label ='Прогноз')
ax.legend(loc = 'upper center' , fontsize = 25 , ncol = 2 )
fig.set_figwidth(20)
fig.set_figheight(6)
fig.suptitle("Посещение сайта")
plt.show()

Как видно из графика выше, применение описанного метода позволяет получить очень хороший прогноз с использованием всего шести наиболее значимых гармоник. В нашем примере это 0,4% от всех 1344 гармоник.

Таким образом, результатом применения описанного метода является новая независимая переменная, позволяющая существенно улучшить прогноз.

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

Комментарии (11)


  1. Andy_U
    05.08.2021 11:05
    +1

    Скажите, пожалуйста, почему Вы не использовали scipy.fft?


    1. NewTechAudit Автор
      06.08.2021 07:00

      Добрый день, чтобы применить низкоуровневые библиотеки, и использовать декоратор функции Numba


      1. Andy_U
        06.08.2021 10:22

        Что такое "низкоуровневые" библиотеки? Вы, я вижу, используете:

        • math

        • pandas

        • matplotlib

        • numba

        Они все "низкоуровневые"? Так тогда numpy/scipy такие же...

        Сколько волка не корми, а время вычисления "вашим" способом пропорционально N^2, а FFT - N*log(N). Ну и под капотом у scipy код на С или даже еще фортране.

        Далее, про точность вашей модели. Вам тут уже намекали, что по одному графику ничего не определишь. Хотя - нет. Вы предсказываете отрицательные числа в выходные дни по ночам. Да и в рабочие дни тоже :( Максимальное количество посещений в рабочие дни недооценивается, а в выходные дни переоценивается.

        Т.е. будь я вашим заказчиком, я бы потребовал a) график residuals vs. time и b) гистограмму распределения этих остатков по величине.

        P.S. У вас во втором примере кода отступы съехали.


  1. GospodinKolhoznik
    05.08.2021 11:55
    +3

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

    Возможно в DS так принято, на глаз оценивать качество прогноза. В традиционной статистике принято заниматься всякими глупостями вроде расчета критерия достоверности и анализа отклонений прогноза от реальных данных.


    1. E11E
      05.08.2021 11:59
      -3

      На картинке наложения графиков реальных данных и прогноза - всё видно, всё исследовано.


      1. GospodinKolhoznik
        05.08.2021 12:00

        Что именно видно?


        1. E11E
          05.08.2021 12:39
          -2

          "отклонений прогноза от реальных данных "


          1. GospodinKolhoznik
            05.08.2021 13:37
            +2

            По графику трудно о чем либо судить, это дело субъективного восприятия. Вот как я вижу, на пиках отклонения вверх всегда гораздо больше, чем отклонения вниз на минимумах. То есть отклонения носят регулярный характер. Такой сильный звоночек о том, что модель кривенькая. Ибо отклонения должны примерно одинаковыми что в плюс, что а минус, а тут явный перекос в плюс, и этот перекос наблюдается с постоянной периодичностью.

            Если бы отклонения реально исследовались, это сразу стало бы очевидно.


          1. E11E
            06.08.2021 10:44

            Вот сейчас не понял? Что субъектвно у вас ан графике со шкалами и цифрами? Вы цифры шкал не видите? Или субъективно их воспринимаете?


            1. Andy_U
              06.08.2021 12:04

              По приведенному графику невозможно оценить зависимость residuals от времени и их статистичесое распределение.

              Единственно, что видно, так это то, что модель предсказывает отрицательное число посещений сайта по ночам.


  1. E11E
    05.08.2021 12:02
    +2

    Автор: А вот порог расчетных гармоник по мощности, думаю надо бы еще отбирать, например, среднеквадратичным отклонением, чтобы включить не самые пиковые, а просто все, которые влияют до определенного предела на результат, а иначе, с топовыми гармониками у вас в низших точках получились слишком сильные отклонения в прогнозах, именно из-за нехватки числа гармоник в среднем ряду.