AgroNDVI – отчёт для работодателя
Автор: Валентюк Евгений Григорьевич (ВЕГ). Системный/бизнес-аналитик, переходящий в ML/DS. Контекст: второй пет-проект для портфолио. Первый – MiniProctor, CV-прокторинг на MediaPipe + YOLOv8. Срок: 7-10 дней плотной работы. Стек: Python 3.13, rasterio, geopandas, lightgbm, scikit-learn, streamlit, folium. Стоимость инфраструктуры: ноль рублей. Все данные открытые, обработка локальная.
Главный методологический сигнал
На датасете 20 точек простая LinearRegression на одной фиче
ndvi_peakпобеждает LightGBM на 18 фичах.Метрики Leave-One-Out CV: MAPE 2.95% vs 4.39%, R² 0.70 vs 0.32. Train MAPE LightGBM = 0.03% при LOO MAPE 4.39% – классический симптом переобучения.
Что это показывает. Зрелое понимание bias-variance trade-off, а не подход «лишь бы LightGBM запустить». Я начал с baseline, сравнил пять моделей на одних данных, и публично включил в отчёт результат, который против моей более сложной модели. Это и есть рабочая дисциплина ML/DS: сначала простая модель, потом обоснование сложности.
Подробный разбор – в docs/experiments/2026-05-26-lgb-baseline.md.
Что в портфолио
- Полный pipeline «спутник -> прогноз». От поиска снимков Sentinel-2 через STAC API до Streamlit UI с интерактивной картой полей.
- Реальные данные из РФ. Granular spatial: 20 рисовых чеков Темрюкского района (700-1500 га каждый), полученных из OpenStreetMap. Temporal: 45 безоблачных снимков за полный сезон октябрь 2023 - сентябрь 2024.
- Time-series NDVI. 900 точек данных (20 полей × 45 дат), 98.9% валидных пикселей после SCL-маскирования. Видна классическая рисовая кривая: затопление чеков -> вода -> всходы -> пик -> жатва.
- Feature engineering. Из time-series извлечены 10 признаков NDVI + 8 признаков погоды + площадь поля. Каждый признак физически интерпретируем.
- ML pipeline с честной оценкой. 5 моделей (mean, 2× LinearRegression, 2× LightGBM), Leave-One-Out CV, 3 типа feature importance, открытое обсуждение, почему простой baseline победил сложный бустинг.
- Anomaly detection (день 7).
- Streamlit UI (день 8).
- Документация: brief, эксперимент-отчёт, архитектура, метрики (день 9).
Технологический стек и почему так
| Слой | Что используется | Почему этот выбор |
|---|---|---|
| Спутниковые снимки | Sentinel-2 L2A через AWS Element 84 STAC | Бесплатно, без регистрации, доступен из РФ (Copernicus заблокирован санкциями). COG-формат позволяет читать удалённо через HTTP-range, без скачивания всего tile. |
| Геоданные | rasterio + geopandas + shapely + pyproj | Индустриальный стандарт. GDAL 3.12 встроен в rasterio. Без зависимости от QGIS/ArcGIS. |
| Границы полей | OpenStreetMap через Overpass API | Реальные данные, не выдуманные. landuse=farmland в OSM покрывает большинство российских пашен. |
| Погода | Open Meteo Historical + NASA POWER | Оба бесплатно, без ключа, доступны из РФ. Open Meteo даёт температуру/осадки/ET0, NASA POWER – солнечную радиацию. |
| ML | LightGBM + scikit-learn | LightGBM как промышленный gradient boosting. sklearn для baselines и LOO-CV. На текущем датасете baseline побеждает – честно отражено в отчёте. |
| UI | Streamlit + folium | Быстро поднять интерактив. folium даёт интерактивную карту со спутниковой подложкой Esri прямо в браузере. |
Ключевые количественные результаты
| Артефакт | Метрика | Значение |
|---|---|---|
| Серия Sentinel-2 | Снимков за год после фильтра облачности <20% | 45 |
| NDVI time-series | Размер CSV (поле × дата) | 900 строк |
| Чистота данных | Доля валидных NDVI после SCL-маски | 98.9% |
| Сезонная амплитуда NDVI | Январь min vs август max | -0.03 -> 0.56 |
| GDD рисового сезона | Сумма градусо-дней (база 10°C) | 2296 |
| Модель победитель | LinearRegression(ndvi_peak), MAPE LOO-CV | 2.95% |
| Модель победитель | LinearRegression(ndvi_peak), R² LOO-CV | 0.70 |
| LightGBM trade-off | train MAPE / LOO MAPE | 0.03% / 4.39% |
| Время прогона серии | 45 снимков, 6 параллельных потоков | 7:37 минут |
Главные методологические решения
- Сменил Copernicus на AWS Element 84 STAC после того как Copernicus оказался заблокирован для РФ. Решение лучше изначального плана: не нужно качать .SAFE-архивы по 1 ГБ, COG читается удалённо по нужному окну.
- Перешёл с pystac-client на прямой
requests+ retry послеIncompleteReadошибок на нестабильном канале РФ -> us-west-2. Разбил запрос на месячные чанки, добавил экспоненциальный backoff. - Принял рис вместо пшеницы когда OSM показал, что в выбранном Темрюкском районе доминирует именно рис. Адаптировался к данным, вместо того чтобы перебрасывать bbox под исходный план. Для портфолио рис как ниша даже редкая.
- Сделал таргет урожайности синтетическим и честно зафиксировал это. Реальной пол-уровневой урожайности в открытом доступе нет. Альтернатива «промолчать про синтетику» отброшена.
- Использовал Leave-One-Out CV вместо обычного train/test split. На N=20 train/test даст случайные числа, LOO – единственный честный способ оценить out-of-sample.
- Включил в отчёт baseline, который побил LightGBM. Это и есть тот самый методологический сигнал из hero-блока выше.
Что осознанно НЕ сделано (и почему)
- Не использовал нейросети. На 20 точках Conv-LSTM или U-Net будут переобучаться ещё хуже LightGBM. NN – следующий этап при расширении датасета.
- Не делал tuning гиперпараметров. Любой grid-search/optuna на 20 точках переобучится на CV. Использованы консервативные настройки LightGBM.
- Не подключил Google Earth Engine. GEE заблокирован для РФ. AWS STAC выбран как замена.
- Не использовал платные сервисы (Sentinel Hub, Planet, Climate FieldView). Всё бесплатно и воспроизводимо.
- Не масштабировал на всю Россию. Pet-проект – демонстрация подхода, не продакшн-сервис.
Привязка к навыкам системного анализа
Проект – это в первую очередь ML/DS, но в каждом блоке проявляются навыки СА. Кратко:
| Навык СА | Где в проекте |
|---|---|
| Постановка задачи и scope | docs/brief.md: чёткая постановка, целевые работодатели, риски, открытые вопросы. |
| Анализ источников данных | Таблица «Откуда что берётся» в brief: 9 источников с пометкой доступности и стоимости. |
| Выявление и обработка ограничений | Honest list «что НЕ сделано». Документирование санкционных блоков (Copernicus, GEE) и решений в обход. |
| Документирование решений | 7 артефактов в docs/: brief, sentinel-download, experiments, portfolio-report. Каждая развилка зафиксирована с reasoning. |
| Декомпозиция и итеративный план | План 10 дней по дням, контроль через TodoWrite и два параллельных лога (results.md технический + journal.md простыми словами). |
| Качество данных и валидация | SCL-маска убрала 21% мусорных пикселей, valid_share отслеживается по датам, 98.9% после маски. |
| Метрики и доказательная отчётность | 5 моделей × 4 метрики, LOO-CV, 3 типа feature importance, открытое обсуждение результатов в эксперимент-отчёте. |
Что дальше – planned extensions
- Multi-year датасет: 2020-2024 = 5 лет × 20 полей = 100 строк. Появляется реальная дисперсия по погоде между годами – LightGBM получит шанс показать преимущество над линейной моделью.
- Multi-region: добавить Калининский / Славянский районы (пшеница). Микс культур даст gradient boosting нелинейности для разделения.
- Реальный таргет: запросить пол-уровневые урожайности у местных хозяйств или подобрать через open data partnership.
- CNN/Conv-LSTM на сырой NDVI-кривой: вместо плоских фичей – обработка time-series длиной 45 точек напрямую.
- Бэктест на отложенном годе: train на 2020-2023, test на 2024. Это и есть индустриальная оценка прогностической модели.
Связь с MiniProctor
MiniProctor – первый пет-проект (CV-прокторинг). Что переиспользовано:
- Структура документации (brief + experiment reports + portfolio report);
- Streamlit + folium как UI-комбо;
- Логика честного отчёта: «вот что получилось, вот ограничения, вот что бы я доделал»;
- Шаблон C4-диаграмм для архитектуры (через Mermaid).
Чем AgroNDVI расширяет MiniProctor:
- Новый домен: агро/спутниковый мониторинг вместо CV-прокторинга;
- Новый стек: rasterio + geopandas + LightGBM (геоданные + табличный ML);
- Time-series: работа с серией снимков за сезон, а не покадровая обработка;
- Внешние API: STAC, Overpass, Open Meteo, NASA POWER (4 различных протокола: STAC, Overpass QL, REST, JSON-API);
- Bias-variance trade-off: урок, которого в MiniProctor не было.
Контакты
- GitHub: https://github.com/EValentyuk
- Email: e.valentyuk@yandex.ru