三、ML.NET示例:使用时序分析和 ML.NET 预测自行车租赁服务需求

- 36氪

教程:使用时序分析和 ML.NET 预测自行车租赁服务需求

了解如何通过 ML.NET 对 SQL Server 数据库中存储的数据进行单变量时序分析,以预测自行车租赁服务需求。

在本教程中,你将了解:

了解问题

从数据库加载数据

创建预测模型

评估预测模型

保存预测模型

使用预测模型

先决条件

已安装“.NET 桌面开发”工作负载的 Visual Studio 2022

时序预测示例概述

此示例为 C# .NET Core 控制台应用程序,它使用单变量时序分析算法(称为单谱分析)来预测自行车租赁需求。 此示例的代码可以在 GitHub 上的 dotnet/machinelearning-samples 存储库找到。

了解问题

为了实现高效运营,其中库存管理的作用不可或缺。 产品库存过多意味着产品积压,无法产生收入。 产品库存过少会损失销售额,导致客户转而购买竞争对手的产品。 因此,一个永恒的问题就是:保有多少库存才最合适呢? 借助时序分析,可通过查看历史数据、识别模式并使用此信息来预测未来某个时间的值,从而帮助找到这些问题的答案。

此教程使用的数据分析技术为单变量时序分析。 单变量时序分析可按照特定间隔(如月销售额)查看一个时段内的单个数值观测。

本教程中使用的算法是单谱分析 (SSA)。 SSA 会将时序分解为一组主要成分, 可以将这些成分解释为信号的组成部分,对应于趋势、噪音、季节性及许多其他的因素。 然后重新构建这些成分,并用来预测未来某个时间的值。

创建控制台应用程序

1.创建一个名为“BikeDemandForecasting”的 C# 控制台应用程序。 单击“下一步”按钮。

2.选择 .NET 6 作为要使用的框架。 单击“创建” 按钮。

3.安装 Microsoft.ML 版本 NuGet 包

 备注

除非另有说明,否则本示例使用前面提到的 NuGet 包的最新稳定版本。

zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.在“解决方案资源管理器”中,右键单击项目,然后选择“管理 NuGet 包” 。

a.选择“nuget.org”作为“包源”,选择“浏览”选项卡,再搜索“Microsoft.ML”。

b.选中“包括预发行版”复选框。

c.选择“安装”按钮。

d.选择“预览更改”对话框中的“确定”按钮;如果同意所列包的许可条款,请选择“接受许可”对话框中的“我接受”按钮。

e.针对 System.Data.SqlClient 和 Microsoft.ML.TimeSeries 重复上述步骤 。

准备和了解数据

1.创建一个名为“Data”的目录。

2.下载 DailyDemand.mdf 数据库文件并将其保存到“Data”目录中。

 备注

此教程使用的数据来自 UCI 自行车共享数据集。 作者 Fanaee-T,Hadi 和 Gama, Joao,“事件标签结合集合探测器和背景知识”,人工智能进展 (2013):1-15 页,Springer Berlin Heidelberg,网页链接

原始数据集包含与季节和天气相对应的若干列。 为了简洁起见,并且由于本教程使用的算法仅需要单个数值列中的值,因此,已将原始数据集精简为仅包括以下列:

dteday:观测日期。

year:观测年份编码(0=2011,1=2012)。

cnt:观测日当天自行车租赁总数。

原始数据集映射到 SQL Server 数据库中具有以下架构的数据库表。

SQL复制

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

创建输入和输出类

1.打开 Program.cs 文件,将现有 using 语句替换为以下内容:

C#复制

using Microsoft.ML;

using Microsoft.ML.Data;

using Microsoft.ML.Transforms.TimeSeries;

using System.Data.SqlClient;

2.创建 ModelInput 类。 在 Program 类下面,添加以下代码。

C#复制

public class ModelInput

{

public DateTime RentalDate { get; set; }


public float Year { get; set; }


public float TotalRentals { get; set; }

}

ModelInput 类包含以下列:

RentalDate:观测日期。

Year:观测年份编码(0=2011,1=2012)。

TotalRentals:观测日当天自行车租赁总数。

3.在新建的 ModelOutput 类的下面,创建 ModelInput 类。

C#复制

public class ModelOutput

{

public float[] ForecastedRentals { get; set; }


public float[] LowerBoundRentals { get; set; }


public float[] UpperBoundRentals { get; set; }

}

ModelOutput 类包含以下列:

ForecastedRentals:预测时段内的预测值。

LowerBoundRentals:预测时段内的最低预测值。

UpperBoundRentals:预测时段内的最高预测值。

定义路径并初始化变量

1.在 using 语句下,定义变量,用于存储数据位置、连接字符串,以及保存已训练模型的位置。

C#复制

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;";

2.通过在定义路径后添加以下行,使用新的 MLContext 实例初始化 mlContext 变量。

C#复制

MLContext mlContext = new MLContext();

执行所有 ML.NET 操作都是从 MLContext 类开始,初始化 mlContext 将创建一个新的 ML.NET 环境,可在模型创建工作流对象之间共享该环境。 从概念上讲,它与实体框架中的 DBContext 类似。

加载数据

1.创建 DatabaseLoader,用于加载 ModelInput 类型的记录。

C#复制

DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader();

2.定义查询,以从数据库加载数据。

C#复制

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。

3.创建 DatabaseSource 以连接到数据库,并执行查询。

C#复制

DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance,

connectionString,

query);

4.将数据加载到 IDataView 中。

C#复制

IDataView dataView = loader.Load(dbSource);

5.此数据集包含两年的重要数据。 第一年的数据仅用于培训,第二年的数据用于将实际值与模型生成的预测进行比较。 使用 FilterRowsByColumn 转换筛选数据。

C#复制

IDataView firstYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", upperBound: 1);

IDataView secondYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", lowerBound: 1);

对于第一年,通过将 upperBound 参数设置为 1 来仅选择 Year 列中小于 1 的值。 相反,对于第二年,通过将 lowerBound 参数设置为 1 来仅选择大于或等于 1 的值。

定义时序分析管道

1.定义使用 SsaForecastingEstimator 预测时序数据集中的值的管道。

C#复制

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 个数据点,并按 seriesLength 参数指定的间隔从时序数据集采样或将其分为 30 天(每月)的间隔。 以一周或 7 天为一个时段分析各个样本。 确定下一个时段的预测值时,使用前面 7 天的值进行预测。 根据 horizon 参数的定义,该模型设置为预测将来的 7 个时段。 由于预测属于合理猜测,它不总是完全准确。 因此,最好了解上限和下限定义的最佳和最坏情况下的范围值。 在本案例中,设置的上下限可信度为 95%。 可信度可以相应地提高或降低。 值越高,上限和下限之间的范围越大,以便达到所需的可信度。

2.使用 Fit 方法培训模型,使数据适用于前面定义的 forecastingPipeline。

C#复制

SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);

评估模型

通过预测下一年的数据并将其与实际值进行比较,评估模型的执行情况。

1.在 Program.cs 文件底部创建名为 Evaluate 的新实用工具方法。

C#复制

Evaluate(IDataView testData, ITransformer model, MLContext mlContext)

{


}

2.在 Evaluate 方法中,通过结合使用 Transform 方法和培训模型,预测第二年的数据。

C#复制

IDataView predictions = model.Transform(testData);

3.使用 CreateEnumerable 方法,从数据中获取实际值。

C#复制

IEnumerableactual =

mlContext.Data.CreateEnumerable(testData, true)

.Select(observed => observed.TotalRentals);

4.使用 CreateEnumerable 方法获取预测值。

C#复制

IEnumerableforecast =

mlContext.Data.CreateEnumerable(predictions, true)

.Select(prediction => prediction.ForecastedRentals[0]);

5.计算实际值和预测值之间的差值(通常称为“误差”)。

C#复制

var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);

6.通过计算平均绝对误差和均方根误差值测量性能。

C#复制

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,模型的质量越好。

7.将指标输出到控制台。

C#复制

Console.WriteLine("Evaluation Metrics");

Console.WriteLine("---------------------");

Console.WriteLine($"Mean Absolute Error: {MAE:F3}");

Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");

8.在调用 Fit() 方法下方调用 Evaluate 方法。

C#复制

Evaluate(secondYearData, forecaster, mlContext);

保存模型

如果对模型满意,则保存它,以便以后用于其他应用程序。

1.在 Evaluate() 方法下面,创建 TimeSeriesPredictionEngine。 TimeSeriesPredictionEngine 是进行单个预测的一个便捷方法。

C#复制

var forecastEngine = forecaster.CreateTimeSeriesEngine(mlContext);

2.将此模型保存到由先前定义的 modelPath 变量指定的名为 MLModel.zip 的文件。 使用 Checkpoint 方法保存模型。

C#复制

forecastEngine.CheckPoint(mlContext, modelPath);

使用模型预测需求

1.在 Evaluate 方法下面,创建一个名为 Forecast 的新实用方法。

C#复制

void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngineforecaster, MLContext mlContext)

{


}

2.在 Forecast 方法中,使用 Predict 方法预测接下来的 7 天的租赁数量。

C#复制

ModelOutput forecast = forecaster.Predict();

3.排列 7 个时段的实际值和预测值。

C#复制

IEnumerableforecastOutput =

mlContext.Data.CreateEnumerable(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";

});

4.循环访问预测输出,并在控制台上显示它。

C#复制

Console.WriteLine("Rental Forecast");

Console.WriteLine("---------------------");

foreach (var prediction in forecastOutput)

{

Console.WriteLine(prediction);

}

运行此应用程序

1.在调用 Checkpoint() 方法下方调用 Forecast 方法。

C#复制

Forecast(secondYearData, 7, forecastEngine, mlContext);

2.运行该应用程序。 控制台应显示类似以下内容的输出。 为简洁起见,输出已进行压缩。

text复制

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 存储库中找到本教程的源代码。


相关文章!
  • 一、ML.NET 介绍

    ML.NET 使你能够在联机或脱机场景中将机器学习添加到 .NET 应用程序中

  • 二、ML.NET 开发环境

    目前机器学习训练的样本数据都是结构化的数据,确定的维度、值。同时,需要对要预测的维度数据进行Label标识和标注。