上一篇博文我们介绍了 ML.NET 的入门:
ML.NET 技术研究系列 1 - 入门篇
本文我们继续, 研究分享一下聚类算法 k-means.
一, k-means 算法简介
k-means 算法是一种聚类算法, 所谓聚类, 即根据相似性原则, 将具有较高相似度的数据对象划分至同一类簇, 将具有较高相异度的数据对象划分至不同类簇.
1. k-means 算法的原理是什么样的? 参考:
k-means 算法中的 k 代表类簇个数, means 代表类簇内数据对象的均值 (这种均值是一种对类簇中心的描述), 因此, k-means 算法又称为 k - 均值算法.
k-means 算法是一种基于划分的聚类算法, 以距离作为数据对象间相似性度量的标准, 即数据对象间的距离越小, 则它们的相似性越高, 则它们越有可能在同一个类簇.
数据对象间距离的计算有很多种, k-means 算法通常采用欧氏距离来计算数据对象间的距离. 算法详细的流程描述如下:
2. k-means 算法的优缺点:
优点: 算法简单易实现;
缺点: 需要用户事先指定类簇个数; 聚类结果对初始类簇中心的选取较为敏感; 容易陷入局部最优; 只能发现球形类簇;
接下来我们说一下 k-means 算法的经典应用场景: 鸢尾花
二, 鸢尾花
首先, 鸢尾花是一种植物, 有四个典型的属性:
花瓣长度
花瓣宽度
花萼长度
花萼宽度
鸢尾花有三大品种 setosa,versicolor 或 virginica , 每个品种对应的以上四个属性各不相同.
鸢尾花数据集中一共包含了 150 条记录, 每个样本的包含它的萼片长度和宽度, 花瓣的长度和宽度以及这个样本所属的具体品种. 每个品种的样本量为 50 条.
鸢尾花样本数据格式:
- 5.2,3.4,1.4,0.2,Iris-setosa
- 4.7,3.2,1.6,0.2,Iris-setosa
- 4.8,3.1,1.6,0.2,Iris-setosa
- 6.0,2.2,4.0,1.0,Iris-versicolor
- 6.1,2.9,4.7,1.4,Iris-versicolor
- 5.6,2.9,3.6,1.3,Iris-versicolor
- 5.7,2.5,5.0,2.0,Iris-virginica
- 5.8,2.8,5.1,2.4,Iris-virginica
- 6.4,3.2,5.3,2.3,Iris-virginica
上述数据中, 第一列是鸢尾花花萼长度, 第二列是鸢尾花花萼宽度, 第三列是鸢尾花花瓣长度, 第四列是鸢尾花花瓣宽度.
基于上述数据做机器学习, 训练, 形成一个模型.
三, ML.NET k-means
基于上述的场景, 我们先准备样本数据,
另存为 iris.data 文件, 每个属性逗号间隔.
然后, 大致梳理了一下实现步骤:
新建一个. Net Core Console Project
添加 Microsoft.ML nuget 1.2.0 版本
添加鸢尾花数据, 预测类实体类 IrisData,ClusterPrediction
构造 MLContext, 从 iris.data 构造 IDataView, 采用 Trainers.KMeans 进行模型训练, 形成模型文件: IrisClusteringModel.zip
输入一个测试数据, 进行预测.
好, 让我们开始搞吧:
1. 新建一个. Net Core Console Project
先看下用的 VS 的版本:
新建一个. Net Core Console 的 Project KMeansDemo
2. 添加 Microsoft.ML nuget 1.2.0 版本
将 iris.data 文件放到 Project 下的 Data 目录中, 同时右键 iris.data, 设置为: 始终复制
3. 添加鸢尾花数据, 预测类实体类 IrisData,ClusterPrediction
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace KMeansDemo
- {
- using Microsoft.ML.Data;
- /// <summary>
- /// 鸢尾花数据
- /// </summary>
- class IrisData
- {
- /// <summary>
- /// 鸢尾花花萼长度
- /// </summary>
- [LoadColumn(0)]
- public float SepalLength;
- /// <summary>
- /// 鸢尾花花萼宽度
- /// </summary>
- [LoadColumn(1)]
- public float SepalWidth;
- /// <summary>
- /// 鸢尾花花瓣长度
- /// </summary>
- [LoadColumn(2)]
- public float PetalLength;
- /// <summary>
- /// 鸢尾花花瓣宽度
- /// </summary>
- [LoadColumn(3)]
- public float PetalWidth;
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace KMeansDemo
- {
- using Microsoft.ML.Data;
- public class ClusterPrediction
- {
- /// <summary>
- /// 预测的族群
- /// </summary>
- [ColumnName("PredictedLabel")]
- public uint PredictedClusterId;
- [ColumnName("Score")]
- public float[] Distances;
- }
- }
4. 构造 MLContext, 从 iris.data 构造 IDataView, 采用 Trainers.KMeans 进行模型训练, 形成模型文件: IrisClusteringModel.zip
在 Main 函数中, 开始编码 , 首先添加引用
using Microsoft.ML;
声明样本数据文件和模型文件的文件路径
- static readonly string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "iris.data");
- static readonly string _modelPath = Path.Combine(Environment.CurrentDirectory, "Data", "IrisClusteringModel.zip");
构造 MLContext,IDataView, 采用 Trainer.KMeans 进行模型训练, 形成模型文件: IrisClusteringModel.zip
- var mlContext = new MLContext(seed: 0);
- IDataView dataView = mlContext.Data.LoadFromTextFile<IrisData>(_dataPath, hasHeader: false, separatorChar: ',');
- string featuresColumnName = "Features";
- var pipeline = mlContext.Transforms
- .Concatenate(featuresColumnName, "SepalLength", "SepalWidth", "PetalLength", "PetalWidth")
- .Append(mlContext.Clustering.Trainers.KMeans(featuresColumnName, numberOfClusters: 3));
- var model = pipeline.Fit(dataView);
- using (var fileStream = new FileStream(_modelPath, FileMode.Create, FileAccess.Write, FileShare.Write))
- {
- mlContext.Model.Save(model, dataView.Schema, fileStream);
- }
- Console.WriteLine("完成模型训练!");
- Console.WriteLine("模型文件:"+ _modelPath);
5. 输入一个测试数据, 进行预测.
输入一个测试数据, 使用生成的模型, 进行预测:
- var predictor = mlContext.Model.CreatePredictionEngine<IrisData, ClusterPrediction>(model);
- var Setosa = new IrisData
- {
- SepalLength = 5.1f,
- SepalWidth = 3.5f,
- PetalLength = 1.4f,
- PetalWidth = 0.2f
- };
- var prediction = predictor.Predict(Setosa);
- Console.WriteLine($"Cluster: {prediction.PredictedClusterId}");
- Console.WriteLine($"Distances: {string.Join(" ", prediction.Distances)}");
- Console.WriteLine("Press any key!");
全部的代码:
- using Microsoft.ML;
- using System;
- using System.IO;
- namespace KMeansDemo
- {
- class Program
- {
- static readonly string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "iris.data");
- static readonly string _modelPath = Path.Combine(Environment.CurrentDirectory, "Data", "IrisClusteringModel.zip");
- static void Main(string[] args)
- {
- var mlContext = new MLContext(seed: 0);
- IDataView dataView = mlContext.Data.LoadFromTextFile<IrisData>(_dataPath, hasHeader: false, separatorChar: ',');
- string featuresColumnName = "Features";
- var pipeline = mlContext.Transforms
- .Concatenate(featuresColumnName, "SepalLength", "SepalWidth", "PetalLength", "PetalWidth")
- .Append(mlContext.Clustering.Trainers.KMeans(featuresColumnName, numberOfClusters: 3));
- var model = pipeline.Fit(dataView);
- using (var fileStream = new FileStream(_modelPath, FileMode.Create, FileAccess.Write, FileShare.Write))
- {
- mlContext.Model.Save(model, dataView.Schema, fileStream);
- }
- Console.WriteLine("完成模型训练!");
- Console.WriteLine("模型文件:"+ _modelPath);
- // 预测
- var predictor = mlContext.Model.CreatePredictionEngine<IrisData, ClusterPrediction>(model);
- var Setosa = new IrisData
- {
- SepalLength = 5.1f,
- SepalWidth = 3.5f,
- PetalLength = 1.4f,
- PetalWidth = 0.2f
- };
- var prediction = predictor.Predict(Setosa);
- Console.WriteLine($"Cluster: {prediction.PredictedClusterId}");
- Console.WriteLine($"Distances: {string.Join(" ", prediction.Distances)}");
- Console.WriteLine("Press any key!");
- }
- }
- }
Run, 看一下输出:
以上就是通过 ML.NET 的 KMeans 算法, 实现聚类.
上面的数据是一个监督学习的样本, 同时是一个数值类型的数据, 比较好奇的是, 能不能对文本数据 + 值数据进行聚类, 下一篇, 我们将继续完成文本数据 + 值数据的聚类分析.
以上, 分享给大家.
周国庆
2019/7/14
来源: https://www.cnblogs.com/tianqing/p/11183035.html