Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Узнайте, как прогнозировать спрос на аренду велосипедов с помощью единовременного анализа временных рядов данных, хранящихся в базе данных SQL Server с ML.NET.
В этом руководстве вы узнаете, как:
- Определение проблемы
- Загрузка данных из базы данных
- Создание модели прогнозирования
- Оценка модели прогнозирования
- Сохранение модели прогнозирования
- Использование модели прогнозирования
Предпосылки
- Visual Studio 2022 или более поздней версии с установленной нагрузкой разработки для настольных приложений .NET.
Обзор примера прогнозирования временных рядов
Этот пример является консольным приложением C# , которое прогнозирует спрос на прокат велосипедов с помощью единого алгоритма анализа временных рядов, известного как Анализ сингулярного спектра. Код для этого примера можно найти в репозитории dotnet/machinelearning-samples на сайте GitHub.
Определение проблемы
Для эффективного выполнения операции управление инвентаризацией играет ключевую роль. Наличие слишком большого количества продукта на складе означает нераспроданные продукты, сидящие на полках, не генерируя никакой выручки. Слишком мало продукта приводит к потере продаж и клиентов покупки от конкурентов. Таким образом, постоянный вопрос состоит в определении оптимального объема запасов, который следует иметь в наличии. Анализ временных рядов помогает ответить на эти вопросы, просматривая исторические данные, определяя шаблоны и используя эти сведения для прогнозирования значений в будущем.
Метод анализа данных, используемых в этом руководстве, является унивариативным анализом временных рядов. Одномерный анализ временных рядов смотрит на одно числовое наблюдение за периодом времени с определенными интервалами, такими как ежемесячные продажи.
Алгоритм, используемый в этом руководстве, — это анализ сингулярным спектром (SSA). SSA работает путем разложения временных рядов в набор основных компонентов. Эти компоненты можно интерпретировать как части сигнала, которые соответствуют тенденциям, шуму, сезонности и многим другим факторам. Затем эти компоненты восстанавливаются и используются для прогнозирования значений в будущем.
Создание консольного приложения
Создайте консольное приложение C# с именем BikeDemandForecasting. Нажмите кнопку Далее.
Выберите .NET 8 в качестве платформы для использования. Нажмите кнопку Создать.
Установка пакета NuGet версии Microsoft.ML
Замечание
В этом примере используется последняя стабильная версия упомянутых пакетов NuGet, если не указано иное.
- В обозревателе решений щелкните проект правой кнопкой мыши и выберите пункт "Управление пакетами NuGet".
- Выберите "nuget.org" в качестве источника пакета, перейдите на вкладку "Обзор ", найдите Microsoft.ML.
- Установите флажок "Включить предварительную версию ".
- Нажмите кнопку Установить.
- Нажмите кнопку "ОК " в диалоговом окне "Предварительные изменения" , а затем нажмите кнопку "Принять" в диалоговом окне принятия лицензий, если вы согласны с условиями лицензии для перечисленных пакетов.
- Повторите эти действия для System.Data.SqlClient и Microsoft.ML.TimeSeries.
Подготовка и понимание данных
- Создайте каталог с именем Data.
- Скачайте файл базы данных DailyDemand.mdf и сохраните его в каталоге данных.
Замечание
Данные, используемые в этом руководстве, поступают из набора данных Bike Sharing UCI. Hadi Fanaee-T и João Gama, "Обозначение событий, сочетание ансамблевых детекторов и фоновых знаний", Progress in Artificial Intelligence (2013): pp. 1-15, Springer Berlin Heidelberg, Web Link.
Исходный набор данных содержит несколько столбцов, соответствующих сезонности и погоде. Для краткости и из-за того, что алгоритм, используемый в этом руководстве, требует только значений из одного числового столбца, исходный набор данных был сокращен, чтобы включить только следующие столбцы:
- dteday: дата наблюдения.
- год: закодированный год наблюдения (0=2011, 1=2012).
- cnt: Общее количество прокатов велосипедов в течение этого дня.
Исходный набор данных сопоставляется с таблицей базы данных со следующей схемой в базе данных SQL Server.
CREATE TABLE [Rentals] (
[RentalDate] DATE NOT NULL,
[Year] INT NOT NULL,
[TotalRentals] INT NOT NULL
);
Ниже приведен пример данных:
| RentalDate | Год | TotalRentals |
|---|---|---|
| 1/1/2011 | 0 | 985 |
| 1/2/2011 | 0 | 801 |
| 1/3/2011 | 0 | 1349 |
Создание входных и выходных классов
Откройте файл Program.cs и замените существующие
usingдирективы следующими:using Microsoft.ML; using Microsoft.ML.Data; using Microsoft.ML.Transforms.TimeSeries; using System.Data.SqlClient;Создание
ModelInputкласса. Под классомProgramдобавьте следующий код.public class ModelInput { public DateTime RentalDate { get; set; } public float Year { get; set; } public float TotalRentals { get; set; } }Класс
ModelInputсодержит следующие столбцы:- RentalDate: Дата наблюдения.
- Год: закодированный год наблюдения (0=2011, 1=2012).
- TotalRentals: Общее количество прокатов велосипедов в течение этого дня.
Создайте
ModelOutputкласс под вновь созданнымModelInputклассом.public class ModelOutput { public float[] ForecastedRentals { get; set; } public float[] LowerBoundRentals { get; set; } public float[] UpperBoundRentals { get; set; } }Класс
ModelOutputсодержит следующие столбцы:- ForecastedRentals: прогнозируемые значения для прогнозируемого периода.
- LowerBoundRentals: прогнозируемые минимальные значения для прогнозируемого периода.
- UpperBoundRentals: прогнозируемые максимальные значения для прогнозируемого периода.
Определение путей и инициализация переменных
usingПод директивами определяются переменные для хранения расположения данных, строки подключения и места сохранения обученной модели.string rootDir = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../")); string dbFilePath = Path.Combine(rootDir, "Data", "DailyDemand.mdf"); string modelPath = Path.Combine(rootDir, "MLModel.zip"); var connectionString = $"Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename={dbFilePath};Integrated Security=True;Connect Timeout=30;";Инициализируйте переменную
mlContextновым экземпляромMLContext, добавив следующую строку после определения путей.MLContext mlContext = new MLContext();Класс
MLContextявляется отправной точкой для всех операций ML.NET, и инициализация mlContext создает новую среду ML.NET, которую можно совместно использовать для объектов рабочего процесса создания модели. Это концептуально похоже наDBContextв Entity Framework.
Загрузка данных
Создайте
DatabaseLoaderзаписи типаModelInput.DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();Определите запрос для загрузки данных из базы данных.
string query = "SELECT RentalDate, CAST(Year as REAL) as Year, CAST(TotalRentals as REAL) as TotalRentals FROM Rentals";ML.NET алгоритмы ожидают, что данные будут иметь тип
Single. Таким образом, числовые значения, поступающие из базы данных, не имеющие типаReal, значение с плавающей запятой с одной точностью, необходимо преобразовать вReal.Столбцы
YearиTotalRentalявляются целочисленными типами в базе данных. Используя встроенную функциюCAST, они оба преобразованы вReal.DatabaseSourceСоздайте объект для подключения к базе данных и выполните запрос.DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance, connectionString, query);Загрузка данных в объект
IDataView.IDataView dataView = loader.Load(dbSource);Набор данных содержит два года данных. Для обучения используются только данные первого года, второй год проводится для сравнения фактических значений с прогнозом, созданным моделью. Отфильтруйте данные с помощью
FilterRowsByColumnпреобразования.IDataView firstYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", upperBound: 1); IDataView secondYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", lowerBound: 1);В течение первого года только значения в
Yearстолбце меньше 1 выбираются, задавupperBoundпараметру значение 1. И наоборот, в течение второго года значения, превышающие или равные 1, выбираются путем заданияlowerBoundпараметра равным 1.
Определение конвейера анализа временных рядов
Определите конвейер, использующий SsaForecastingEstimator для прогнозирования значений в наборе данных временных рядов.
var forecastingPipeline = mlContext.Forecasting.ForecastBySsa( outputColumnName: "ForecastedRentals", inputColumnName: "TotalRentals", windowSize: 7, seriesLength: 30, trainSize: 365, horizon: 7, confidenceLevel: 0.95f, confidenceLowerBoundColumn: "LowerBoundRentals", confidenceUpperBoundColumn: "UpperBoundRentals");forecastingPipelineпринимает 365 точек данных за первый год и разбивает или выбирает временные интервалы набора данных временных рядов на 30-дневные (ежемесячные), как это указано параметромseriesLength. Каждый из этих примеров анализируется еженедельно или через 7-дневное окно. При определении прогнозируемого значения для следующих периодов значения, полученные за предыдущие семь дней, используются для прогнозирования. Модель устанавливается для прогнозирования семи периодов в будущем, как определено параметромhorizon. Так как прогноз является информированным предположением, это не всегда 100% точно. Поэтому хорошо знать диапазон значений в лучших и худших сценариях, как определено верхними и нижними границами. В этом случае уровень достоверности для нижних и верхних границ имеет значение 95%. Уровень достоверности может быть увеличен или уменьшен соответствующим образом. Чем выше значение, тем шире диапазон между верхними и нижними границами для достижения требуемого уровня достоверности.FitИспользуйте метод для обучения модели и соответствия данным ранее определеннымforecastingPipeline.SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
Оценка модели
Оцените, насколько хорошо модель выполняется путем прогнозирования данных следующего года и сравнения ее с фактическими значениями.
Создайте новый метод служебной программы, называемый
Evaluateв нижней части файла Program.cs .Evaluate(IDataView testData, ITransformer model, MLContext mlContext) { }В методе
Evaluateпрогнозируйте данные второго года с помощьюTransformметода с обученной моделью.IDataView predictions = model.Transform(testData);Получение фактических значений из данных с помощью
CreateEnumerableметода.IEnumerable<float> actual = mlContext.Data.CreateEnumerable<ModelInput>(testData, true) .Select(observed => observed.TotalRentals);Получение значений прогноза
CreateEnumerableс помощью метода.IEnumerable<float> forecast = mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true) .Select(prediction => prediction.ForecastedRentals[0]);Вычислите разницу между фактическими и прогнозными значениями, которые обычно называются ошибкой.
var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);Измеряйте производительность путем вычисления значений средней абсолютной ошибки и корневой среднеквадратической ошибки.
var MAE = metrics.Average(error => Math.Abs(error)); // Mean Absolute Error var RMSE = Math.Sqrt(metrics.Average(error => Math.Pow(error, 2))); // Root Mean Squared ErrorДля оценки производительности используются следующие метрики:
- Средняя абсолютная ошибка: измеряет, как близкие прогнозы относятся к фактическому значению. Это значение диапазонов от 0 до бесконечности. Чем ближе к 0, тем лучше качество модели.
- Среднеквадратическая ошибка: суммирует ошибку в модели. Это значение диапазонов от 0 до бесконечности. Чем ближе к 0, тем лучше качество модели.
Выводит метрики в консоль.
Console.WriteLine("Evaluation Metrics"); Console.WriteLine("---------------------"); Console.WriteLine($"Mean Absolute Error: {MAE:F3}"); Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");Вызовите приведенный ниже метод, вызывающий
EvaluateFit()метод.Evaluate(secondYearData, forecaster, mlContext);
Сохранение модели
Если вы удовлетворены моделью, сохраните ее для дальнейшего использования в других приложениях.
Под методом
Evaluate()TimeSeriesPredictionEngineсоздается .TimeSeriesPredictionEngine— это удобный метод для создания отдельных прогнозов.var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);Сохраните модель в файл, который называется
MLModel.zipуказанной ранееmodelPathпеременной.CheckpointИспользуйте метод для сохранения модели.forecastEngine.CheckPoint(mlContext, modelPath);
Использование модели для прогнозирования спроса
Под методом
Evaluateсоздайте новый методForecastслужебной программы.void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext) { }В методе
ForecastиспользуйтеPredictметод для прогнозирования аренды в течение следующих семи дней.ModelOutput forecast = forecaster.Predict();Выровняйте фактические и прогнозные значения за семь периодов.
IEnumerable<string> forecastOutput = mlContext.Data.CreateEnumerable<ModelInput>(testData, reuseRowObject: false) .Take(horizon) .Select((ModelInput rental, int index) => { string rentalDate = rental.RentalDate.ToShortDateString(); float actualRentals = rental.TotalRentals; float lowerEstimate = Math.Max(0, forecast.LowerBoundRentals[index]); float estimate = forecast.ForecastedRentals[index]; float upperEstimate = forecast.UpperBoundRentals[index]; return $"Date: {rentalDate}\n" + $"Actual Rentals: {actualRentals}\n" + $"Lower Estimate: {lowerEstimate}\n" + $"Forecast: {estimate}\n" + $"Upper Estimate: {upperEstimate}\n"; });Выполните итерацию по выходным данным прогноза и отобразите его на консоли.
Console.WriteLine("Rental Forecast"); Console.WriteLine("---------------------"); foreach (var prediction in forecastOutput) { Console.WriteLine(prediction); }
Запуск приложения
Под вызовом
Checkpoint()Forecastметода вызывается метод.Forecast(secondYearData, 7, forecastEngine, mlContext);Запустите приложение. Выходные данные, аналогичные приведенному ниже, должны отображаться в консоли. Для краткости выходные данные были сокращены.
Evaluation Metrics --------------------- Mean Absolute Error: 726.416 Root Mean Squared Error: 987.658 Rental Forecast --------------------- Date: 1/1/2012 Actual Rentals: 2294 Lower Estimate: 1197.842 Forecast: 2334.443 Upper Estimate: 3471.044 Date: 1/2/2012 Actual Rentals: 1951 Lower Estimate: 1148.412 Forecast: 2360.861 Upper Estimate: 3573.309
Проверка фактических и прогнозируемых значений показывает следующие связи:
Хотя прогнозируемые значения не прогнозируют точное количество аренды, они предоставляют более узкий диапазон значений, что позволяет операции оптимизировать их использование ресурсов.
Поздравляю! Теперь вы успешно создали модель машинного обучения временных рядов для прогнозирования спроса на прокат велосипедов.
Исходный код этого руководства можно найти в репозитории dotnet/machinelearning-samples .