📜  K表示聚类–简介

📅  最后修改于: 2021-04-17 04:02:36             🧑  作者: Mango

我们获得了具有某些特征的项目数据集,以及这些特征的值(如矢量)。任务是将这些项目归类。为了达到这个目的,我们将使用kMeans算法。一种无监督的学习算法。

概述

(如果您将项目视为n维空间中的点,它将很有帮助)。该算法会将项目分类为k个相似度组。为了计算相似度,我们将使用欧式距离作为度量。

该算法的工作原理如下:

  1. 首先,我们随机初始化k个点,称为均值。
  2. 我们将每个项目分类为最接近的均值,并更新均值的坐标,这是到目前为止按该均值分类的项目的平均值。
  3. 我们对给定的迭代次数重复该过程,最后,有了我们的集群。

上面提到的“点”称为“均值”,因为它们保存了其中归类的项目的均值。要初始化这些方法,我们有很多选择。一种直观的方法是在数据集中的随机项目处初始化均值。另一种方法是在数据集边界之间的随机值处初始化均值(如果对于某个要素x,这些项的值在[0,3]中,我们将在x的值处初始化均值[[0,3]) 。

上面的算法采用伪代码:

Initialize k means with random values

For a given number of iterations:
    Iterate through items:
        Find the mean closest to the item
        Assign item to mean
        Update mean

读取资料

我们接收输入为文本文件(’data.txt’)。每行代表一个项目,并且包含数值(每个要素一个),并用逗号分隔。您可以在此处找到样本数据集。

我们将从文件中读取数据,并将其保存到列表中。列表的每个元素都是另一个列表,其中包含要素的项目值。我们使用以下函数做到这一点:

def ReadData(fileName): 
  
    # Read the file, splitting by lines 
    f = open(fileName, 'r'); 
    lines = f.read().splitlines(); 
    f.close(); 
  
    items = []; 
  
    for i in range(1, len(lines)): 
        line = lines[i].split(','); 
        itemFeatures = []; 
  
        for j in range(len(line)-1): 
              
            # Convert feature value to float
            v = float(line[j]); 
              
            # Add feature value to dict 
            itemFeatures.append(v); 
  
        items.append(itemFeatures); 
  
    shuffle(items); 
  
    return items; 

初始化手段

我们要在各项特征值的范围内初始化每个均值。为此,我们需要找到每个功能的最小值和最大值。我们通过以下函数来实现:

def FindColMinMax(items):
    n = len(items[0]);
    minima = [sys.maxint for i in range(n)];
    maxima = [-sys.maxint -1 for i in range(n)];
      
    for item in items:
        for f in range(len(item)):
            if (item[f] < minima[f]):
                minima[f] = item[f];
              
            if (item[f] > maxima[f]):
                maxima[f] = item[f];
  
return minima,maxima;

最小值,最大值是分别包含项的最小值和最大值的列表。我们在以上两个列表的相应最小值和最大值之间随机初始化每个均值的特征值:

def InitializeMeans(items, k, cMin, cMax):
  
    # Initialize means to random numbers between
    # the min and max of each column/feature    
    f = len(items[0]); # number of features
    means = [[0 for i in range(f)] for j in range(k)];
      
    for mean in means:
        for i in range(len(mean)):
  
            # Set value to a random float
            # (adding +-1 to avoid a wide placement of a mean)
            mean[i] = uniform(cMin[i]+1, cMax[i]-1);
  
    return means;

欧氏距离

我们将使用欧氏距离作为数据集的相似性度量(注意:根据您的项目,您可以使用其他相似性度量)。

def EuclideanDistance(x, y): 
    S = 0; # The sum of the squared differences of the elements 
    for i in range(len(x)): 
        S += math.pow(x[i]-y[i], 2)
  
    #The square root of the sum
    return math.sqrt(S)

更新方式

要更新均值,我们需要为均值/集群中的所有项目找到其特征的平均值。我们可以通过将所有值相加然后除以项目数来做到这一点,或者可以使用更优雅的解决方案。通过执行以下操作,我们将无需重新添加所有值即可计算新的平均值:

m = (m*(n-1)+x)/n

其中, m是特征的平均值, n是群集中的项数, x是添加项的特征值。我们对每个功能都执行上述操作以获取新的均值。

def UpdateMean(n,mean,item):
    for i in range(len(mean)):
        m = mean[i];
        m = (m*(n-1)+item[i])/float(n);
        mean[i] = round(m, 3);
      
    return mean;

分类项目

现在,我们需要编写一个函数来将项目分类为组/集群。对于给定的项目,我们将发现它与每个均值的相似性,然后将项目分类为最接近的项目。

def Classify(means,item):
  
    # Classify item to the mean with minimum distance    
    minimum = sys.maxint;
    index = -1;
  
    for i in range(len(means)):
  
        # Find distance from item to mean
        dis = EuclideanDistance(item, means[i]);
  
        if (dis < minimum):
            minimum = dis;
            index = i;
      
    return index;

寻找手段

为了真正找到均值,我们将遍历所有项目,将它们分类到最近的聚类,并更新聚类的均值。我们将以固定的迭代次数重复该过程。如果两次迭代之间没有项目更改分类,我们将停止该过程,因为该算法已找到最佳解决方案。

下面的函数将项目和最大迭代次数作为输入k (所需聚类的数量),并返回均值和聚类。的项的分类存储在数组属于关联和项目的群集中的号被存储在clusterSizes。

def CalculateMeans(k,items,maxIterations=100000):
  
    # Find the minima and maxima for columns
    cMin, cMax = FindColMinMax(items);
      
    # Initialize means at random points
    means = InitializeMeans(items,k,cMin,cMax);
      
    # Initialize clusters, the array to hold
    # the number of items in a class
    clusterSizes= [0 for i in range(len(means))];
  
    # An array to hold the cluster an item is in
    belongsTo = [0 for i in range(len(items))];
  
    # Calculate means
    for e in range(maxIterations):
  
        # If no change of cluster occurs, halt
        noChange = True;
        for i in range(len(items)):
  
            item = items[i];
  
            # Classify item into a cluster and update the
            # corresponding means.        
            index = Classify(means,item);
  
            clusterSizes[index] += 1;
            cSize = clusterSizes[index];
            means[index] = UpdateMean(cSize,means[index],item);
  
            # Item changed cluster
            if(index != belongsTo[i]):
                noChange = False;
  
            belongsTo[i] = index;
  
        # Nothing changed, return
        if (noChange):
            break;
  
    return means;

查找集群

最后,我们要找到聚类,并给出相应的方法。我们将遍历所有项目,并将每个项目分类为最接近的类。

def FindClusters(means,items):
    clusters = [[] for i in range(len(means))]; # Init clusters
      
    for item in items:
  
        # Classify item into a cluster
        index = Classify(means,item);
  
        # Add item to cluster
        clusters[index].append(item);
  
    return clusters;

其他常用的相似性度量是:

1.余弦距离:它确定n维空间中两个点的点向量之间的夹角的余弦值

d = \frac{X.Y}{||X||*||Y||}\

2.曼哈顿距离:它计算两个数据点的坐标之间的绝对差之和。

d = \sum_{n} X{_{i}}-Y{_{i}}

3. Minkowski距离:也称为广义距离度量。它可以用于序数和定量变量

d = (\sum _{n}|X_{i}-Y_{i}|^{\frac{1}{p}})^{p}

您可以在我的GitHub上找到完整的代码,以及示例数据集和绘图函数。谢谢阅读。