Точность прогноза погоды зависит от многих факторов — в том числе от данных, на основе которых и проводятся вычисления. Поэтому мы постоянно добавляем новые источники информации, которые используем в Яндекс Погоде. Три года назад мы представили технологию Метеум 2.0, которая учитывала не только профессиональные метеостанции, но и подсказки пользователей наших приложений. С помощью «зонтиков» нам удалось повысить качество прогноза осадков в районах с низкой плотностью размещения метеостанций и радаров. 

Сегодня мы запускаем OmniCast — новую технологию в составе Метеума. Она повысит точность прогноза температуры с помощью пользовательских метеостанций, подключить которые может любой желающий по API. Благодаря новым источникам данных сервис стал в 36 раз чаще получать данные о температуре. В районах с плотным покрытием такими станциями Яндекс Погода сможет прогнозировать температуру с точностью до квартала. Если раньше мы прогнозировали температуру для ячеек с минимальным размером 2х2 километра, то теперь разрешение повысили в 16 раз — до 500х500 метров.  

Но одних данных недостаточно, чтобы построить более детализированный прогноз. Поэтому в этой статье мы расскажем о том, как при помощи фильтра Калмана и комбинации двунаправленной и однонаправленной LSTM-нейросетей нам удалось улучшить качество прогноза температуры. 

Какую проблему мы решаем

Для начала давайте напомним, как Яндекс Погода рассчитывает прогноз погоды. Прогнозирование температуры, влажности, давления, ветра и осадков на ближайшие 10 дней при помощи технологии Метеум производится так: на вход модели машинного обучения передаются численные прогнозы от мировых поставщиков и различные дополнительные фичи, например, высота солнца над горизонтом или тип подстилающей поверхности. В качестве таргета для обучения используются данные с профессиональных метеостанций. ML-модель обучается на архиве показаний с метеостанций и учится воспроизводить показания в точках метеостанций. Затем обученная модель применяется для каждой ячейки регулярной сетки, покрывающей весь мир. В итоге мы получаем прогноз на сетке 2×2 км над сушей и 10×10 км над океаном на 10 дней вперёд. 

Правильно показывать «погоду за окном сейчас» — важнейшая составляющая доверия к качеству погодного сервиса. И это не самая простая задача. Мы можем достаточно оперативно получать измерения с профессиональных метеостанций, настроенных специалистами. Основные проблемы в пространственном и временном разрешении — станций мало (обычно всего несколько штук на крупный город) и они редко осуществляют измерения: например, метеостанции в населённых пунктах — обычно раз в 3 часа, а метеостанции в аэропортах — раз в полчаса.

Первоначально информацию о текущей погоде мы брали с ближайшей доступной метеостанции, и в результате могли сильно ошибаться. Например, в Екатеринбурге две метеостанции: одна — в центре города, измеряет раз в 3 часа, другая — в аэропорту Кольцово в 20 км от центра, измеряет раз в полчаса. В утренние/вечерние часы или в мороз температура в аэропорту может отличаться от температуры в центре города на целых 13 (!) градусов (это явление называется «городским островом тепла»). В итоге метеостанция в центре города слишком редко обновляется и не успевает оперативно отслеживать изменения, поэтому мы использовали данные с метеостанции в аэропорту и могли ошибаться с текущей температурой и другими погодными параметрами.

Раз уж вариант показа измерений напрямую с метеостанций нам не подошёл, мы решили изменить свой подход. Выделили отдельную ML-модель, которая будет сконцентрирована именно на прогнозе на «сейчас», и добавили в наш стандартный вектор фичей актуальные измерения с метеостанций. Эксперимент основывался на том, что модель сама сможет выучить, когда стоит выдать прогноз ближе к результату измерения на станции, а когда больше полагаться на расчёты численных моделей. Мы пробовали развивать такой подход, добавив фичи расстояния до станции по пространству и времени, ввели корректировку температуры, если высота метеостанции отличалась от высоты точки прогноза. Но последующие замеры метрик показали, что добавление данных со станций в таком виде не даёт никакого статистически значимого преимущества, и мы отказались от такого подхода.

Параллельно мы занимались улучшением качества нашей базовой CatBoost-модели, которая прогнозирует температуру и на текущий момент, и на первые 72 часа. В конце концов, за счёт использования комбинации нескольких CatBoost-ов, тщательного подбора фичей и гиперпараметров, нам удалось достаточно хорошо улучшить качество прогноза температуры. Такая модель долгое время использовалась для расчёта «погоды за окном».

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

Технология OmniCast

Основная проблема использования измерений с метеостанций для «погоды за окном сейчас» была в том, что мы применяли интерполяцию методом ближайшего соседа. Проще говоря, измерения с метеостанции мы распространяли на все ячейки сетки 2×2 км, покрывающей интересующий нас город. Нам нужен другой алгоритм пространственной интерполяции, который бы учитывал: 

  • прогноз нашей ML-модели в каждой ячейке сетки; 

  • рельеф местности;

  • затухание влияния станции в зависимости от расстояния; 

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

Используемая нами технология интерполяции основывается на фильтре Калмана. Чтобы было проще объяснить саму идею алгоритма, давайте начнём с одномерного случая. Допустим, у нас есть динамическая модель системы $u_t$. Если мы знаем состояние системы $x_t$ на момент времени $t$, то динамическая модель сможет сделать прогноз того, как система будет выглядеть в момент времени $t\+1$. 

$x_{t+1} = x_t + u_t$

Так как модель может ошибаться, добавим в уравнение некоторую случайную величину $\xi_t$, характеризующую ошибку модели. В итоге получим $x_{t+1} = x_t + u_t + \xi_t$. 

С другой стороны, у нас есть возможность измерить состояние системы в момент времени $t\+1$ с некоторой погрешностью $\eta_t$. В итоге уравнение измерения системы выглядит так: 

$z_t = x_t + \eta_t$

Задача фильтра Калмана состоит в том, чтобы используя одновременно и смоделированное состояние системы в момент времени $t\+1$ и измерения этого состояния в момент $t\+1$ определить хорошее приближение для истинного состояния, учитывая ошибки модели и измерений. 

Теперь зададим вес $K$, который определяет, чему мы больше доверяем — модели или измерениям. Тогда уравнение для нахождения оптимального значения состояния системы в момент $t\+1$ будет выглядеть так: 

$x_{t+1}^{opt} = K * z_{t+1} + (1 - K) * (x_t^{opt} + u_t)$. 

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

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

Наша ML-модель умеет в каждой ячейке сетки вычислять прогноз температуры. Сложим все ячейки сетки в один большой вектор размерности $k = {количество широт * количество долгот}$. Обозначим этот вектор как $x_b$, где $b$ означает, что этот вектор представляет собой background (состояние системы). 

С другой стороны, у нас есть измерения температуры с метеостанций и метеодатчиков, сложим их в вектор размерности $p (p << k)$ и обозначим как $z$. И раз у векторов разная размерность, нам нужно уметь делать отображение вектора состояния в вектор измерений. То есть нам нужно понять, к какой ячейке сетки относится та или иная метеостанция. 

Обозначим такое отображение как $H$. Оно вычисляется с использованием метода интерполяции ближайшим соседом с учётом разницы высоты точки метеостанции и центра ячейки.

Усиление Калмана в данном многомерном случае — это матрица (так называемая Kalman gain matrix) размерности $k × p$ ($k$ — количество ячеек сетки, $p$ — количество измерений с метеостанций). При расчёте усиления Калмана учитывается не только сама разница между модельным и измеряемым значением, но и ошибки как модели, так и измерений. Причём вес источника измерений зависит от надёжности: профессиональной метеостанции мы доверяем больше, чем персональным метеодатчикам. Поправка из точки метеостанции распространяется по пространству по определённому закону.

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

Таким образом, наша задача сводится к следующему. Мы знаем состояние системы, хранящееся в векторе $x_b$ и нам нужно скорректировать это состояния с учётом измерений, хранящихся в векторе $z$. Формула для нахождения оптимального значения состояния системы для многомерного случая выглядит так: 

$x^{opt} = x_b + K(z - H[x_b])$, 

где $K$ — Kalman gain matrix, а $H$ — отображение вектора состояния в вектор измерений. 

Стоит упомянуть, что оригинальный алгоритм Калмана состоит из двух повторяющихся фаз:

  1. Прогноза, который делается динамической моделью системы.

  2. Корректировки прогноза за счёт измерений. 

Следующая итерация алгоритма учитывает те значения, что были рассчитаны на предыдущем шаге. В нашей технологии Omnicast используется только часть алгоритма Калмана. Мы делаем только корректировку состояния системы за счёт измерений, причём не итеративно. То есть каждый момент времени рассчитывается независимо от предыдущих. В таком виде алгоритм часто используется в ассимиляции данных и носит название оптимальная интерполяция.

Метод оптимальной интерполяции основывается на гипотезе, что данные со станций репрезентативны для некоторого ограниченного пространства вокруг (так называемая локализация). В нашем случае это означает, что для каждой ячейки сетки мы используем данные только с нескольких ближайших метеостанций и метеодатчиков в заданном радиусе. Такое допущение позволяет значительно сократить время расчётов, потому что при вычислении усиления Калмана нужно в том числе делать обращение матриц, на что требуются большие вычислительные мощности.

Карты температуры для Москвы и Екатеринбурга: слева — старая версия, справа — OmniCast
Карты температуры для Москвы и Екатеринбурга: слева — старая версия, справа — OmniCast

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

Чтобы обеспечить оптимальную скорость, мы используем распределенные вычисления. Регулярную сетку, покрывающую земной шар, мы делим на части. Каждая часть обрабатывается отдельно Map-операцией, где усваиваются отфильтрованные и обработанные данные с метеостанций и метеодатчиков, а также корректируется значение температуры в каждой ячейке сетки. Затем все части обратно склеиваются в большую сетку Reduce операцией. В среднем каждые 5 минут MapReduce-операция обрабатывает более 100 000 новых измерений с датчиков температуры.

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

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

Когда речь заходит об экстраполяции временного ряда, первыми на ум приходят методы семейства ARIMA (autoregressive integrated moving average). С неё мы и начали экспериментировать. В итоге удалось подобрать параметры модели, при которых ошибка экстраполированной температуры RMSE получалась в районе 1,5 градуса. 

Качество экстраполяции нас устраивало, но у такого подхода есть один большой недостаток. Параметры модели ARIMA стоит рассчитывать отдельно для каждой станции. Мы используем измерения примерно с 16 000 профессиональных метеостанций, а если сюда добавить ещё и остальные метеодатчики, получается очень много отдельных моделей. Таким образом решение с моделью ARIMA получается немасштабируемым.

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

Использование двунаправленной LSTM даёт преимущество за счёт того, что входная последовательность просматривается с начала до конца и с конца до начала. Тем самым нейронная сеть получает более репрезентативное представление входной последовательности. 

На данный момент наша модель экстраполирует температуры на 3 часа вперёд и выигрывает по качеству у модели ARIMA. Мы тем временем экспериментируем с другими подходами, чтобы расширить выходную последовательность на сутки вперёд.

Заключение

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

Тем не менее, прогнозировать погоду сложно, поэтому мы будем рады любой помощи. Если у вас есть любительская метеостанция, то подключить её к нашему сервису можно по API. Так вы сможете повысить качество прогноза Яндекс Погоды не только для себя, но и для тысяч ваших соседей по району. 

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