我在一个无监督聚类场景中试验ML.NET。我的起始数据少于30条记录,每条记录有5个特征,数据存储在一个TSV文件中,例如(当然标签将被忽略):
Label S1 S2 S3 S4 S5alpha 0.274167987321712 0.483359746434231 0.0855784469096672 0.297939778129952 0.0332805071315372beta 0.378208470054279 0.405409549510871 0.162317151706584 0.292342604802355 0.0551994848048085...
我的起点是iris教程,这是一个K-means聚类的示例。在我的案例中,我想要3个聚类。由于我只是在学习,一旦创建了模型,我想用它在原始文件的一个副本中为每条记录添加聚类数据,以便我可以检查它们并绘制散点图。
我从以下训练代码开始(假设MyModel
是表示其模型的POCO类,具有S1
–S5
的属性):
// 加载数据MLContext mlContext = new MLContext(seed: 0);IDataView dataView = mlContext.Data.LoadFromTextFile<MyModel> (dataPath, hasHeader: true, separatorChar: '\t');// 训练模型const string featuresColumnName = "Features";EstimatorChain<ClusteringPredictionTransformer<KMeansModelParameters>> pipeline = mlContext.Transforms .Concatenate(featuresColumnName, "S1", "S2", "S3", "S4", "S5") .Append(mlContext.Clustering.Trainers.KMeans(featuresColumnName, numberOfClusters: 3));TransformerChain<ClusteringPredictionTransformer<KMeansModelParameters>> model = pipeline.Fit(dataView);// 保存模型using (FileStream fileStream = new FileStream(modelPath, FileMode.Create, FileAccess.Write, FileShare.Write)){ mlContext.Model.Save(model, dataView.Schema, fileStream);}
然后,我加载保存的模型,从原始数据中读取每条记录,并获取其聚类ID。这听起来有点复杂,但我的学习意图在这里是检查结果,在玩弄它们之前。结果应该保存在一个新文件中,包含质心坐标和点坐标。
然而,似乎这个API不够透明,无法轻松访问质心;我只找到一个帖子,这篇帖子相当旧,其代码不再编译。我将其用作通过反射恢复数据的提示,但这是一个权宜之计。
此外,我不确定框架提供的数据的细节。我可以看到每个质心有3个向量(在示例代码中命名为cx
cy
cz
),每个向量有5个元素(我认为是5个特征,按其连接的输入顺序,即从S1到S5);此外,每个预测提供一个三倍距离(dx
dy
dz
)。如果这些假设是正确的,我可以像这样为每条记录分配一个聚类ID:
// 对于原始数据中的每条记录foreach (MyModel record in csvReader.GetRecords<MyModel>()){ // 获取其聚类ID MyPrediction prediction = predictor.Predict(record); // 只获取一次质心,因为当然它们对于所有记录来说都是相同的 // 这些记录参考它们的距离 if (cx == null) { // 获取质心(通过反射...): // https://github.com/dotnet/machinelearning/blob/master/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/Clustering/KMeansWithOptions.cs#L49 // https://social.msdn.microsoft.com/Forums/azure/en-US/c09171c0-d9c8-4426-83a9-36ed72a32fe7/kmeans-output-centroids-and-cluster-size?forum=MachineLearning VBuffer<float>[] centroids = default; var last = ((TransformerChain<ITransformer>)model) .LastTransformer; KMeansModelParameters kparams = (KMeansModelParameters) last.GetType().GetProperty("Model").GetValue(last); kparams.GetClusterCentroids(ref centroids, out int k); cx = centroids[0].GetValues().ToArray(); cy = centroids[1].GetValues().ToArray(); cz = centroids[2].GetValues().ToArray(); } float dx = prediction.Distances[0]; float dy = prediction.Distances[1]; float dz = prediction.Distances[2]; // ... 计算并保存记录的完整细节 ...}
鉴于这种情况,我假设我可以以下列方式获取预训练模型中每条记录位置的所有细节:
dx
,dy
,dz
是距离。cx[0]
cy[0]
cz[0]
加上距离(分别是dx
,dy
, 和dz
)应该是S1点的位置;cx[1]
cy[1]
cz[1]
加上距离是S2的位置;依此类推直到S5(cx[4]
等)。
在这种情况下,我可以将这些数据绘制在3D散点图中。然而,我对ML.NET完全是新手,因此我对这些假设并不确定,很可能我走错了路。能有人指导我正确的方向吗?
回答: