Алгоритм сглаживания значений временных рядов методом прокатки шара

Пример реальной задачи из своего опыта

Нужно проанализировать значения индекса NDVI для для конкретной географической точки. NDVI (Normalized Difference Vegetation Index - это индекс, который рассчитывается по данным спутниковой съёмки, и отражает здоровье растений, которые попали на снимок.

Скачиваем готовые или рассчитываем сами значения индекса NDVI с космического спутника за год. Если визуализировать полученные значения, то получится такой график:

Значения NDVI за год

Из графика видно, что в период с 100 по 280 день значения индекса скачут от нуля до 0,8. Зная то, как индекс NDVI ведёт себя фундаментально, можно уверенно пометить значения ниже основного тренда как ошибочные. Например, на фотографии со спутника в этом месте было облако.

Задача: сгладить значения индексов и получить примерно такой тренд:

Целевые NDVI за год

Другие примеры задач:

Теоретическое описание алгоритма

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

Пример визуализации:

Прокатка шара

Алгоритм является подмножеством алгоритмов сглаживания по максимальным точкам.

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

Как это работает

Последовательно проходимся по значениям временного ряда:

Выбор следующей точки

Самая сложная часть проектирования алгоритма - выбор следующей точки, которой коснётся шар.

Вариант решения наивным способом через геометрические формулы:

Выбор следующей точки по углу

Это угол считается сложением двух углов:

Оба угла рассчитываются на базе формул из школьного курса геометрии:

Расчёт угла

Пример реализации

Ниже представлен листинг кода на Python который реализует алгоритм расчёта угла на основе:

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

import math

# Основная функция для расчёта угла
def calculate_angle_to_circle_center_from_measurement(curr_metric_value, curr_date, next_metric_value, next_date, radius_days, radius_metric, on_top=True):
    days_to_metric_coversion_ratio = radius_metric/radius_days
    
    x1 = 0
    y1 = 0
    
    x2 = (next_date - curr_date).days * days_to_metric_coversion_ratio
    y2 = float(next_metric_value - curr_metric_value)
    
    radius_metric_value = radius_days * days_to_metric_coversion_ratio
    try:
        return calculate_angle_to_circle_center(x1,y1,x2,y2,radius=radius_metric_value, on_top=on_top)
    except ValueError:
        # Заглушка на случай, если "шар" не касается следующей точки
        return -1000

    
def calculate_angle_to_circle_center(x1, y1, x2, y2, radius, on_top):
    chord_to_x_angle = math.atan((y2-y1)/(x2-x1))
   
    chord_length = calculate_chord_length(x1,y1,x2,y2)
    chord_lenth = math.sqrt((x2-x1)**2 + (y2-y1)**2)
    chord_to_circle_center_angle = math.acos(chord_lenth/2/radius)
    if on_top:
        angle_to_circle_center = chord_to_x_angle + chord_to_circle_center_angle
    else:
        angle_to_circle_center = -(chord_to_x_angle - chord_to_circle_center_angle)
    return angle_to_circle_center

def calculate_chord_length(x1, y1, x2, y2):
    x_delta = x2 - x1
    y_delta = y2 - y1
    chord_lenth = math.sqrt(x_delta**2 + y_delta**2)
    return chord_lenth

Примеры работы алгоритма

Возьмём за базу те значения NDVI, которые мы исследовали в начале статьи и визуализируем результаты сглаживания алгоритмом:

Категории: Data ScienceMachine Learning

© 2016–2020 Creative Commons BY-NC-ND 4.0
Powered by Hugo & GitLab

comments powered by Disqus