使用KMeans聚类算法查找部分成员身份

9

我可以通过KMeans轻松计算聚类成员:

open System
open System.IO
open Utils
open Accord
open Accord.Math 
open Accord.MachineLearning

let vals = [|
    [|1.0; 2.0; 3.0; 2.0|]
    [|1.1; 1.9; 3.1; 4.0|]
    [|2.0; 3.0; 4.0; 4.0|]    
    [|3.0; 3.1; 2.0; 3.0|]
    [|2.0; 4.0; 3.0; 6.0|]
    [|1.0; 5.0; 5.0; 7.0|]
    [|4.0; 3.0; 6.0; 8.0|]
    [|5.0; 4.0; 3.0; 6.0|]
    [|6.0; 4.0; 8.0; 7.0|]
    [|5.0; 6.0; 5.0; 9.0|]
    [|4.0; 2.0; 7.0; 8.0|]
    [|8.0; 9.0; 3.1; 2.2|]
    [|8.0; 9.0; 2.0; 2.0|]
    [|10.0; 2.0; 3.0; 2.0|]
    [|10.1; 1.9; 3.1; 4.0|]
    [|20.0; 3.0; 4.0; 4.0|]
    [|22.0; 7.0; 2.0; 3.0|]
    [|21.0; 4.0; 3.0; 6.0|]
|]

let kmeans = new KMeans 5
let clusterModel = kmeans.Learn vals
let clusters = clusterModel.Decide vals

我能用标准的KMeans算法计算部分成员吗?一位同事建议使用聚类成员的平均值和方差来确定比例成员,并且今天我一直在研究模糊集及其在F#中的实现。例如,这里是Accord.net实现模糊集的文档。我可以翻译/运行F#的示例,但乍一看,我没有看到一种简单的方法来将Kmeans运行的数据适配到分配部分成员的格式中。
问题:
  1. 我如何使用聚类成员的平均值/方差计算部分成员?
  2. 是否有一种简单的方法使用Accord.net库中的KMeans聚类计算部分成员?
  3. Accord.net中的KMeans算法易于实现;我应该花时间尝试学习这种聚类/成员的方法以适应我的问题,而不是尝试迫使Kmeans聚类适应我的需求吗?
2个回答

3
你应该能够使用Accord.NET获取K-means算法找到的聚类的“质心”。这些本质上是各个聚类的中心。然后,你应该能够计算你的新数据点与每个质心之间的距离,以查看哪些质心接近你的点。(“Decide”方法仅返回第一个。)
我没有尝试过这个,但似乎“KMeans”公开了“Clusters”,这是一个“KMeansClusterCollection”,具有“Centroids”属性(参见文档)。它还公开了“Distance”属性,该属性返回用于计算数据点之间距离的函数。
使用这些,你应该能够比较你的数据点与所有聚类的质心之间的距离,并决定该点与各个聚类之间的接近程度。

从零开始实现k-means并不难(Mathias Brandewinder的这篇好文章介绍了如何实现),但似乎Accord.NET在这种情况下提供了所有需要的信息 - 因此,也许这就是你所需要的(在自定义实现中获得所有细节总是最困难的部分...)。


3
正如Tomas所提到的,Accord.NET已经为您提供了许多构建模块。特别地,调用clusterModel.Scores会给您提供到聚类中心的(负)距离,请参阅源代码
从这些负距离中,您可以通过取指数来计算近似的类成员分数,类似于计算高斯概率密度函数。在F#中,它看起来像这样:
// Scores returns the negative distances between each point
// and the cluster centroid
let negDistances = clusterModel.Scores vals
// Compute an estimated cluster assigment score
let clusterMembership =
    negDistances
    |> Array.map (fun distances ->
        // Take the Exponential of the (negative) distances,
        // as in computing a Gaussian pdf
        let expDist = distances |> Array.map Math.Exp
        let total = Array.sum expDist
        expDist
        |> Array.map (fun d -> d/total)
    )

这里有一些需要注意的地方:
  • Accord中的标准KMeans使用欧氏距离,这意味着每个方向都具有相同的权重。根据您的数据性质不同,可能会导致不合理的结果(例如2个集群,每个集群形状像长雪茄)。
  • 上述类成员计算也没有考虑聚类协方差。为了更接近真实情况,您需要计算Bhattacharyya距离,指数化,然后按协方差矩阵的逆比例缩放。这对于孤立的集群将无法实现。
关于您的第三个问题:我不建议重新实现。尽管最初看起来很容易,但通常会遇到许多特殊情况和稳定性问题,只有在一段时间后才能发现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接