![](https://habrastorage.org/getpro/habr/upload_files/bae/dd2/375/baedd23754ebe57bff92a64bbbe178b7.png)
Точность прогноза погоды зависит от многих факторов — в том числе от данных, на основе которых и проводятся вычисления. Поэтому мы постоянно добавляем новые источники информации, которые используем в Яндекс Погоде. Три года назад мы представили технологию Метеум 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$. И раз у векторов разная размерность, нам нужно уметь делать отображение вектора состояния в вектор измерений. То есть нам нужно понять, к какой ячейке сетки относится та или иная метеостанция.
![](https://habrastorage.org/getpro/habr/upload_files/446/1df/c5d/4461dfc5dc006432ae194650d84d3c51.png)
Обозначим такое отображение как $H$. Оно вычисляется с использованием метода интерполяции ближайшим соседом с учётом разницы высоты точки метеостанции и центра ячейки.
Усиление Калмана в данном многомерном случае — это матрица (так называемая Kalman gain matrix) размерности $k × p$ ($k$ — количество ячеек сетки, $p$ — количество измерений с метеостанций). При расчёте усиления Калмана учитывается не только сама разница между модельным и измеряемым значением, но и ошибки как модели, так и измерений. Причём вес источника измерений зависит от надёжности: профессиональной метеостанции мы доверяем больше, чем персональным метеодатчикам. Поправка из точки метеостанции распространяется по пространству по определённому закону.
![](https://habrastorage.org/getpro/habr/upload_files/a45/e22/b53/a45e22b536daf1b24d7386a26824b396.png)
В нашем случае это функция Гаусса, которая задаёт степень корреляции между ячейками сетки. Параметрами функции мы можем регулировать скорость убывания в зависимости от расстояний по горизонтали и вертикали.
Таким образом, наша задача сводится к следующему. Мы знаем состояние системы, хранящееся в векторе $x_b$ и нам нужно скорректировать это состояния с учётом измерений, хранящихся в векторе $z$. Формула для нахождения оптимального значения состояния системы для многомерного случая выглядит так:
$x^{opt} = x_b + K(z - H[x_b])$,
где $K$ — Kalman gain matrix, а $H$ — отображение вектора состояния в вектор измерений.
Стоит упомянуть, что оригинальный алгоритм Калмана состоит из двух повторяющихся фаз:
Прогноза, который делается динамической моделью системы.
Корректировки прогноза за счёт измерений.
Следующая итерация алгоритма учитывает те значения, что были рассчитаны на предыдущем шаге. В нашей технологии Omnicast используется только часть алгоритма Калмана. Мы делаем только корректировку состояния системы за счёт измерений, причём не итеративно. То есть каждый момент времени рассчитывается независимо от предыдущих. В таком виде алгоритм часто используется в ассимиляции данных и носит название оптимальная интерполяция.
Метод оптимальной интерполяции основывается на гипотезе, что данные со станций репрезентативны для некоторого ограниченного пространства вокруг (так называемая локализация). В нашем случае это означает, что для каждой ячейки сетки мы используем данные только с нескольких ближайших метеостанций и метеодатчиков в заданном радиусе. Такое допущение позволяет значительно сократить время расчётов, потому что при вычислении усиления Калмана нужно в том числе делать обращение матриц, на что требуются большие вычислительные мощности.
![Карты температуры для Москвы и Екатеринбурга: слева — старая версия, справа — OmniCast Карты температуры для Москвы и Екатеринбурга: слева — старая версия, справа — OmniCast](https://habrastorage.org/getpro/habr/upload_files/45d/a29/221/45da29221be5393926fb1d86b98fe690.jpeg)
Нам нужно, чтобы измерения с метеостанций и метеодатчиков как можно скорее вносили корректировку в значения температуры, которую мы показываем пользователям. При резком изменении температуры измерения со станции быстро теряют актуальность.
![](https://habrastorage.org/getpro/habr/upload_files/ab4/85a/c4d/ab485ac4d4c19f16bb2e6a70752b2a0a.png)
Чтобы обеспечить оптимальную скорость, мы используем распределенные вычисления. Регулярную сетку, покрывающую земной шар, мы делим на части. Каждая часть обрабатывается отдельно Map-операцией, где усваиваются отфильтрованные и обработанные данные с метеостанций и метеодатчиков, а также корректируется значение температуры в каждой ячейке сетки. Затем все части обратно склеиваются в большую сетку Reduce операцией. В среднем каждые 5 минут MapReduce-операция обрабатывает более 100 000 новых измерений с датчиков температуры.
Если мы возьмём данные с метеостанций и метеодатчиков и скорректируем температуру, мы поправим только текущее состояние. В случаях, когда прогноз температуры, рассчитанный нашей ML-моделью на ближайшие несколько часов, заметно отличается от измерения на станции, в таймлайне прогноза появится резкий скачок.
![](https://habrastorage.org/getpro/habr/upload_files/f77/5cf/864/f775cf8641e710b69506e7c8801c2142.jpeg)
Чтобы избежать таких проблем, нужно продлить влияние измерения со станции в будущее. Для этого мы разработали модель, которая принимает на вход историю измерений температуры с метеостанции и экстраполирует на ближайшие 3 часа.
Когда речь заходит об экстраполяции временного ряда, первыми на ум приходят методы семейства ARIMA (autoregressive integrated moving average). С неё мы и начали экспериментировать. В итоге удалось подобрать параметры модели, при которых ошибка экстраполированной температуры RMSE получалась в районе 1,5 градуса.
Качество экстраполяции нас устраивало, но у такого подхода есть один большой недостаток. Параметры модели ARIMA стоит рассчитывать отдельно для каждой станции. Мы используем измерения примерно с 16 000 профессиональных метеостанций, а если сюда добавить ещё и остальные метеодатчики, получается очень много отдельных моделей. Таким образом решение с моделью ARIMA получается немасштабируемым.
Чтобы сделать одну модель под все станции, мы перешли от классических методов к нейронным сетям. В качестве бейзлайна мы взяли LSTM, как популярный вариант обработки временных рядов. В процессе экспериментов усложняли архитектуру и в итоге пока остановились на комбинации biLSTM и однонаправленной LSTM.
Использование двунаправленной LSTM даёт преимущество за счёт того, что входная последовательность просматривается с начала до конца и с конца до начала. Тем самым нейронная сеть получает более репрезентативное представление входной последовательности.
На данный момент наша модель экстраполирует температуры на 3 часа вперёд и выигрывает по качеству у модели ARIMA. Мы тем временем экспериментируем с другими подходами, чтобы расширить выходную последовательность на сутки вперёд.
![](https://habrastorage.org/getpro/habr/upload_files/626/511/234/62651123495a0ecc36026250b0387dde.gif)
Заключение
В этой статье мы рассказали о проблеме перепада температур между разными районами города, из-за чего любой сервис метеопрогнозирования может существенно ошибаться в своих прогнозах. Мы показали, как учимся преодолевать эту проблему с помощью новой технологии OmniCast и расширенного числа источников метеоданных, и планируем использовать такой подход для других погодных параметров.
Тем не менее, прогнозировать погоду сложно, поэтому мы будем рады любой помощи. Если у вас есть любительская метеостанция, то подключить её к нашему сервису можно по API. Так вы сможете повысить качество прогноза Яндекс Погоды не только для себя, но и для тысяч ваших соседей по району.