Dotnet core基于ML.net的销售数据预测实践

ML.net已经进到了1.5版本。作为Microsoft官方的机器学习模型,你不打算用用?

一、前言

ML.net可以让我们很容易地在各种应用场景中将机器学习加入到应用程序中。这是这个框架很重要的一点。

通过ML.net,我们可以使用手中的可用数据,进行预测、分析、检测,而不需要进行过于复杂的编程。

ML.net的核心,同样是机器学习模型。它采用同样的步骤,通过指定算法来训练模型,将输入数据转换为所需的预测数据。

更重要的是,ML.net基于.NET Core,这让它可以非常简单地跨平台,在Windows、Linux、MacOS上运行,并成为我们服务端的一部分内容。

回到今天的主题。

我们用实际的例子,完成一个通过历史销售数据进行单变量时序分析(单谱分析),以预测未来销量的需求。

二、开发环境&基础工程

这个Demo的开发环境是:Mac + VS Code + Dotnet Core 3.1.2。

$ dotnet --info
.NET Core SDK (reflecting any global.json):Version:   3.1.201Commit:    b1768b4ae7Runtime Environment:OS Name:     Mac OS XOS Version:  10.15OS Platform: DarwinRID:         osx.10.15-x64Base Path:   /usr/local/share/dotnet/sdk/3.1.201/Host (useful for support):Version: 3.1.3Commit:  4a9f85e9f8.NET Core SDKs installed:3.1.201 [/usr/local/share/dotnet/sdk].NET Core runtimes installed:Microsoft.AspNetCore.App 3.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]Microsoft.NETCore.App 3.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

首先,在这个环境下建立工程:

  1. 创建Solution

% dotnet new sln -o demo
The template "Solution File" was created successfully.
  1. 这次,我们用Console创建工程

% cd demo
% dotnet new console -o demo
The template "Console Application" was created successfully.Processing post-creation actions...
Running 'dotnet restore' on demo/demo.csproj...Determining projects to restore...Restored demo/demo.csproj (in 143 ms).Restore succeeded.
  1. 把工程加到Solution中

% dotnet sln add demo/demo.csproj

基础工程搭建完成。

三、引入ML.net库

为了使用ML.net,我们需要引入Microsoft.ML库:

% cd demo
% dotnet add package Microsoft.ML

除此之外,本文是基于时序的预测,还需要引入时序库Microsoft.ML.TimeSeries

% dotnet add package Microsoft.ML.TimeSeries

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

四、准备数据

为了这个DEMO,我准备了一个包含全年365天实际销售金额的数据。

其中这个数据又分为了两部分,第一部分是前11个月的数据,用来做训练,第二部分是12月一个月的数据,用来评估模型。

两部分数据的链接如下:训练数据,评估数据

两个数据文件均为CSV文件,数据结构完全相同,下面是一段内容范例:

2018-12-21,17959.0
2018-12-22,19537.03
2018-12-23,20068.0
2018-12-24,20013.0
2018-12-25,21005.0
2018-12-26,16876.0
2018-12-27,15150.0
2018-12-28,15669.0
2018-12-29,25048.0
2018-12-30,25236.0

五、代码开发

  1. 准备一个输入模型ModelInput

public class ModelInput
{[LoadColumn(0)]public DateTime action_time { get; set; }[LoadColumn(1)]public float count { get; set; }
}

这个模型对应数据文件的结构,分两个字段,第一个是日期,第二个是对应的销售金额。

  1. 准备另一个输出模型ModelOutput

public class ModelOutput
{public float[] forecasted_count { get; set; }public float[] lower_count { get; set; }public float[] upper_count { get; set; }
}

这个模型跟随预测结果的输出,其中:

  • forecasted_count - 预测时间段内的预测值

  • lower_count - 预测时间段内预测值的下限

  • upper_count - 预测时间段内预测值的上限

  1. 初始化机器学习的实例

MLContext mlContext = new MLContext();

执行所有 ML.NET 操作都是从MLContext类开始,初始化 MLContext将创建一个新的 ML.net 环境,并在模型创建工作流对象之间共享该环境。 

  1. 加载数据

ML.net有多种数据的加载方式,可以通过文件、数据库、JSON/XML、内存中加载数据,甚至可以用自定义的数据库连接加载数据。

本文的DEMO中,数据在CSV文件中,所以,我们采用下面的方式加载:

static readonly string _data1Path = Path.Combine(Environment.CurrentDirectory, "data1.csv");
static readonly string _data2Path = Path.Combine(Environment.CurrentDirectory, "data2.csv");static void Main(string[] args)
{MLContext mlContext = new MLContext();IDataView data1View = mlContext.Data.LoadFromTextFile<ModelInput>(_data1Path, separatorChar: ',', hasHeader: false);IDataView data2View = mlContext.Data.LoadFromTextFile<ModelInput>(_data2Path, separatorChar: ',', hasHeader: false);
}

IDataView是数据的承载空间。

  1. 定义时序分析管道

var forecastingPipeline = mlContext.Forecasting.ForecastBySsa(outputColumnName: "forecasted_count",inputColumnName: "count",windowSize: 7,seriesLength: 30,trainSize: 334,horizon: 7,confidenceLevel: 0.95f,confidenceLowerBoundColumn: "lower_count",confidenceUpperBoundColumn: "upper_count");

前面有说过,我们采用单谱分析,所以代码中我们选择了mlContext.Forecasting.ForecastBySsa

解释一下这里面的几个参数:

  • trainSize - 数据样本的数量,也就是训练数据的行数(在这个文件中,一行是一个数据样本,共334行)

  • seriesLength - 从数据样本按时序采样时的间隔,这里是30天

  • windowSize - 样本周期的天数,这里是7天

  • horizon - 预测结果的天数

  • confidenceLevel - 上下限的可信度。预测属于合理猜测,不总是完全准确。

  • 其它几个参数,对应输入输出模型的字段名

  1. 训练模型

管道定义完成,数据加载完成,下面要进行数据训练。

SsaForecastingTransformer forecaster = forecastingPipeline.Fit(data1View);

跟随上一节,管道是单谱管道,所以训练也是单谱训练SsaForecastingTransformer

程序执行到这里,数据训练完成。

  1. 模型评估

模型评估不是必须环节。

模型评估的意义在于:通过评估模型的性能,来调整管道的参数,以达到最佳的预测效果。

模型评估也有多种方式。在这里,我们采用平均绝对误差均方根误差来做评估依据。

static void Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
{IDataView predictions = model.Transform(testData);IEnumerable<float> actual =mlContext.Data.CreateEnumerable<ModelInput>(testData, true).Select(p => p.count);IEnumerable<float> forecast =mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true).Select(p => p.forecasted_count[0]);var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);var MAE = metrics.Average(error => Math.Abs(error));var RMSE = Math.Sqrt(metrics.Average(error => Math.Pow(error, 2)));Console.WriteLine("评估结果");Console.WriteLine("---------------------");Console.WriteLine($"平均绝对误差: {MAE:F3}");Console.WriteLine($"均方根误差: {RMSE:F3}\n");
}

在这个方法中,我们取评估数据的实际值actual和通过训练数据生成的预测值forecast,计算两个误差并输出。

Main中调用此方法:

static void Main(string[] args)
{/* 这儿是前边训练的代码,略过 */Evaluate(data2View, forecaster, mlContext);
}
static void Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
{/* 这儿是评估模型的方法,上面有,略过 */
}

输出结果类似于以下内容:

评估结果
---------------------
平均绝对误差: 23.442
均方根误差: 174.236

两个指标:

  • 平均绝对误差 - 度量预测与实际值之间的接近程度。此值介于 0 到无限大之间。越接近 0,模型的质量越好。

  • 均方根误差 - 汇总模型中的错误。此值介于 0 到无限大之间。越接近 0,模型的质量越好。

  1. 预测

训练模型调整到满意后,即可开始预测的工作:

var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);
ModelOutput forecast = forecastEngine.Predict();

这两行代码,在内存中加载前边训练好的模型,并进行预测操作。预测数据的结果放在forecast中。

对应于分析管道定义中的horizon,预测数据包含7天的预测结果。

  1. 预测结果输出

放在forecast中的数据,对应模型ModelOutput,可以用在任何地方。

在本文中,我们直接显示到Console

IEnumerable<string> forecastOutput =mlContext.Data.CreateEnumerable<ModelInput>(data2View, reuseRowObject: false).Take(7).Select((ModelInput data, int index) =>{string action_date = data.action_time.ToString("yyyy-MM-dd");float actual_count = data.count;float lowerEstimate = Math.Max(0, forecast.lower_count[index]);float estimate = forecast.forecasted_count[index];float upperEstimate = forecast.upper_count[index];return $"日期: {action_date}\n" +$"实际值: {actual_count}\n" +$"预测下限估值: {lowerEstimate}\n" +$"预测估值: {estimate}\n" +$"预测上限估值: {upperEstimate}\n";});Console.WriteLine("预测结果");
Console.WriteLine("---------------------");
foreach (var prediction in forecastOutput)
{Console.WriteLine(prediction);
}

运行结果类似于以下内容:

预测结果
---------------------
日期: 2018-12-01
实际值: 24566.08
预测下限估值: 16791.379
预测估值: 20394.115
预测上限估值: 23996.852

完成!

六、延伸内容

ML.net包含了很多机器学习的内容。其中,我自己认为时序预测是用途很广的一个部分,可以用在

  • 销售预测

  • 库存预警

  • 活动策划辅助

以及其它诸如天气、股票、人口等诸多内容上,依靠过去和现在的数据,分析两者之间的关系,然后利用得到的这个关系去预测未来的数据。

因此,在这个分类中,我的第一篇文章就写了时序预测。

机器学习,核心是各种算法,而算法的基础是一类数学。这是一个很高的坎。刷算法,线性的部分还好,一旦到了幂次或矩阵,没有正统的学习,是很难有突破的。而即便刷通了,也只是皮毛性的理解,距离创造算法的大神,还有很长的距离。

所以,退而求其次,对很多人而言,与其花大功夫去研究算法,不如多研究下如何能把现有的算法或工具用好。

还有,在应用中,你能用机器学习来预测销量、预测库存,有没有很自豪?是不是很高大上?

(全文完)

本文的对应代码,在https://github.com/humornif/Demo-Code/tree/master/0013/demo

点「在看」,让更多人因你而受益

↘  ↘  ↘

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309236.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java中关于省略作用域报错问题分析

这个是很典型的作用域问题&#xff0c;if后如果省略那么if只作用于其后面的第一行代码 这时候如果这行代码只是个变量声明语句的话&#xff0c;这个变量是没有其他任何逻辑可以访问到的&#xff0c;因为作用域问题(如果有/&#xff0c;那么声明语句中声明的变量只在这个个内可用…

java进阶之注解篇

文章目录注解基本语法定义注解元注解编写注解处理器注解元素默认值限制生成外部文件替代方案注解不支持继承实现处理器注解 注解&#xff08;也被称为元数据&#xff09;为我们在代码中添加信息提供了一种形式化的方式&#xff0c;使我们可以在稍后的某个时刻更容易的使用这些…

C#9就这么来了,.NET开发者该做点什么?

就在上周三10号&#xff0c;.NET5.0发布了第5个预览版&#xff0c;同时支持了C#9-preview&#xff01;是的&#xff0c;你没看错&#xff0c;虽然C# 8.0还未正式发布&#xff0c;但是通往C&#xff03;9的漫长道路却已经开始&#xff0c;这发展速度简直了&#xff01;C#语言的快…

C++,Java编程空指针的一个小细节

//判断是否击中了敌人坦克if (hero.shot!null && hero.shot.isLive ){for (int i 0;i<enemyTanks.size();i){EnemyTank enemyTank enemyTanks.get(i);hitTank(hero.shot,enemyTank);}}上面代码的if条件不能写成这样&#xff1a; if ( hero.shot.isLive &&am…

Magicodes.IE在.NET Core中通过请求头导出多种格式文件

原文作者&#xff1a;HueiFeng前言在2.2里程碑中我们增加了一些新的功能,正如标题所写通过请求头进行导出我们不同格式的文件.下面我们来看一下如何使用.通过这种方式无论是对我们的数据多用途&#xff0c;还是说对我们的数据校验都做到了轻松易配。同时我们也将在本周发布2.3版…

使用DQL查询数据

文章目录DQL语言SELECT语法制定查询字段AS 子句作为别名DISTINCT关键字的使用使用表达式的列where条件语句逻辑操作符模糊查询 &#xff1a; 比较操作符连接查询JION自连接排序和分页子查询DQL语言 DQL( Data Query Language 数据查询语言 ) 查询数据库数据 , 如SELECT语句简…

基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(九)

系列文章使用 abp cli 搭建项目给项目瘦身&#xff0c;让它跑起来完善与美化&#xff0c;Swagger登场数据访问和代码优先自定义仓储之增删改查统一规范API&#xff0c;包装返回模型再说Swagger&#xff0c;分组、描述、小绿锁接入GitHub&#xff0c;用JWT保护你的API异常处理和…

关于-32768补码的问题

首先要知道的是计算机中补码的表示是唯一且连续的&#xff01;我想这是计算机为什么不用原码来表示的一个原因&#xff01;另外&#xff0c;以补码形式来运算的话&#xff0c;设计的逻辑电路会简单很多&#xff0c;会少很多逻辑运算器件&#xff0c;所以计算机采用补码的形式来…

TCP(发消息:简易代码实现)

文章目录客户端服务器review&#xff1a;查询IP和端口发送文件客户端 链接服务器Socket发送消息 package com.ayv.try02;import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket;//客户端 public class TcoClientDe…

记实现TDengine时序数据库支持 .Net Windows 32位系统踩坑

TDengine是一个高效的存储、查询、分析时序大数据的平台&#xff0c;专为物联网、车联网、工业互联网、运维监测等优化而设计的数据库&#xff0c; 官方目前没有提供完整的.Net Core 解决方案&#xff0c; 因此闲来无事&#xff0c; 从基于restful api 到现在使用官方编译的动态…

SPDY, WebSocket, WebDAV概念

SPDY&#xff08;读作“SPeeDY”&#xff09;是Google开发的基于TCP的应用层协议&#xff0c;用以最小化网络延迟&#xff0c;提升网络速度&#xff0c;优化用户的网络使用体验。SPDY并不是一种用于替代HTTP的协议&#xff0c;而是对HTTP协议的增强。新协议的功能包括数据流的多…

UDP(发短信:简单模拟)

发短信&#xff1a;不用连接&#xff0c;需要知道对方地址 文章目录UDP发送消息实现互相聊天UDP多线程实现聊天UDP发送消息 UDP传输 我们要用UDP传输数据时&#xff0c;怎么用Socket建立连接呢&#xff1f; DatagramSocket与DatagramPacket 建立发送端&#xff0c;接收端。 建…

SilkierQuartz 1.0.21 发布, 是一个 Quartz.NET 的强大且简单的Web管理工具和承载组件...

SilkierQuartz 是一个新的合并了 Quartzmin 和 QuartzHostedService的组件!Quartz.NET 是一个完整的开源的任务规划系统&#xff0c;从小应用至大型企业级应用都可以适用.Quartzmin Quartzmin 是一个 Quartz.NET 的强大且简单的Web管理工具QuartzHostedService QuartzHostedSer…

超文本运输协议HTTP概念

超文本传输协议&#xff08;HTTP&#xff0c;HyperTextTransfer Protocol)是互联网上应用最为广泛的一种网络传输协议&#xff0c;所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。 1960年美国人Ted Nelson构思了一种通过计算机处…

多线程(简单实现)

继承Thread类 两条线程交替进行创建线程方式一&#xff1a;继承Theard类&#xff0c;重写run方法&#xff0c;调用start开启线程总结:注意&#xff0c;线程开启不一定立即执行&#xff0c;由CPU调度执行 //两条线程交替进行//创建线程方式一&#xff1a;继承Theard类&#xf…

用C#在STM32上写第一个Hello world

随着微软放弃.Net MF ,通过C#编写STM32 平台上的程序变得渺茫&#xff0c; 但是&#xff0c; 别着急&#xff0c; 目前至少有两个社区在做这件事情&#xff0c; 传承了微软的.Net MF , 一家是 nanoframework,另外一家比较封闭的是 GHI Electronics 地址是: https://github.com/…

如何找到Eclipse左侧项目栏

如何找到Eclipse左侧项目栏 window --> Show View --> other --> Java–> package Explorer

静态代理模式(多线程底部原理)

静态代理模式总结(线程底部原理) 真实对象和代理对象都要实现同一个接口代理对象要代理真实角色好处&#xff1a; - 代理对象可以做很多真实对象做不了的事情 - 真实对象专注做自己的事情创建静态代理模式&#xff1a;一个接口&#xff08;当前创建为函数式接口&#xff08;只…

深入async/await知多少

.net的async/await功能相信对很多人来说并不陌生了&#xff0c;有人感觉这功能很好&#xff0c;但也有人说这功能不好容易产生一些莫名其妙的死锁&#xff1b;有人说这些异步功能也有人说这是同步功能。其实在使用async/await的有多少人真的了解它们呢&#xff1f;接下来详细地…

Java中各种整形类型可以表示的范围

对于整型类型&#xff0c;Java只定义了带符号的整型&#xff0c;因此&#xff0c;最高位的bit表示符号位&#xff08;0表示正数&#xff0c;1表示负数&#xff09;。各种整型能表示的最大范围如下&#xff1a; byte&#xff1a;-128 ~ 127 short: -32768 ~ 32767 int: -214748…