【问题标题】:Calculating medoid of a cluster (Python)计算集群的中心点(Python)
【发布时间】:2016-10-27 07:08:17
【问题描述】:

所以我正在运行 KNN 来创建集群。从每个集群中,我想获得集群的中心点。

我使用分数距离度量来计算距离:

其中d是维数,第一个数据点的坐标是x^i,第二个数据点的坐标是y^i,f是0到1之间的任意数

然后我会将中心点计算为:

其中 S 是数据点的集合,δ 是上面使用的距离度量的绝对值。

我在网上寻找 medoid 的实现无济于事(即使有其他距离指标,但大多数东西都是专门的 k-means 或 k-medoid [我认为]与我想要的相对不同。

基本上这归结为我无法将数学转化为有效的编程。任何帮助或正确方向的指示将不胜感激!以下是我目前所拥有的简短列表:

  • 我已经弄清楚了如何计算分数距离度量(第一个方程),所以我认为我很好。
  • 我知道 numpy 有一个 argmin() 函数(记录在 here)。
  • 在不缺乏准确性的情况下提高效率的额外分数(我试图通过计算每个分数距离度量来避免蛮力(因为点对的数量可能会导致阶乘复杂性...)。

【问题讨论】:

    标签: python numpy cluster-analysis distance


    【解决方案1】:
    1. 计算成对距离矩阵
    2. 计算列或行总和
    3. argmin 查找中心点索引

    numpy.argmin(distMatrix.sum(axis=0)) 或类似的。

    【讨论】:

    • 如此明显,但我没想到!
    【解决方案2】:

    所以我在这里接受了答案,但我想如果其他人试图做类似的事情,我会提供我的实现:

    (1)这是距离函数:

    def fractional(p_coord_array, q_coord_array):
      # f is an arbitrary value, but must be greater than zero and 
      # less than one. In this case, I used 3/10. I took advantage
      # of the difference of cubes in this case, so that I wouldn't
      # encounter an overflow error.
    
      a = np.sum(np.array(p_coord_array, dtype=np.float64))
      b = np.sum(np.array(q_coord_array, dtype=np.float64))
      a2 = np.sum(np.power(p_coord_array, 2))
      ab = np.sum(p_coord_array) * np.sum(q_coord_array)
      b2 = np.sum(np.power(p_coord_array, 2))
      diffab = a - b
      suma2abb2 = a2 + ab + b2
    
      temp_dist = abs(diffab * suma2abb2)
      temp_dist = np.power(temp_dist, 1./10)
    
      dist = np.power(temp_dist, 10./3)
      return dist
    

    (2) medoid 函数(如果数据集的长度小于 6000 [如果大于该长度,我会遇到溢出错误......老实说,我仍在努力解决这个问题......] ):

    def medoid(dataset):
    
      point = []
      w = len(dataset)
    
      if(len(dataset) < 6000):
        h = len(dataset)
        dist_matrix = [[0 for x in range(w)] for y in range(h)]
    
        list_combinations = [(counter_1, counter_2, data_1, data_2) for counter_1, data_1 in enumerate(dataset) for counter_2, data_2 in enumerate(dataset) if counter_1 < counter_2]
    
        for counter_3, tuple in enumerate(list_combinations):
          temp_dist = fractional(tuple[2], tuple[3])
          dist_matrix[tuple[0]][tuple[1]] = abs(temp_dist)
          dist_matrix[tuple[1]][tuple[0]] = abs(temp_dist)
    

    有任何问题,欢迎评论!

    【讨论】:

      【解决方案3】:

      如果您不介意使用蛮力,这可能会有所帮助:

      def calc_medoid(X, Y, f=2):
          n = len(X)
          m = len(Y)
          dist_mat = np.zeros((m, n))
          # compute distance matrix
          for j in range(n):
              center = X[j, :]
              for i in range(m):
                  if i != j:
                      dist_mat[i, j] = np.linalg.norm(Y[i, :] - center, ord=f)
      
          medoid_id = np.argmin(dist_mat.sum(axis=0))  # sum over y
      
          return medoid_id, X[medoid_id, :]
      

      【讨论】:

        【解决方案4】:

        这是一个使用欧几里得距离为单个集群计算中心点的示例。

        import numpy as np, pandas as pd, matplotlib.pyplot as plt
        a, b, c, d = np.array([0,1]), np.array([1, 3]), np.array([4,2]), np.array([3, 1.5])
        vCenroid = np.mean([a, b, c, d], axis=0)
        
        def GetMedoid(vX):
          vMean = np.mean(vX, axis=0)                               # compute centroid
          return vX[np.argmin([sum((x - vMean)**2) for x in vX])]   # pick a point closest to centroid
        
        vMedoid = GetMedoid([a, b, c, d])
        
        print(f'centroid = {vCenroid}')
        print(f'medoid = {vMedoid}')
        
        df = pd.DataFrame([a, b, c, d], columns=['x', 'y'])
        ax = df.plot.scatter('x', 'y', grid=True, title='Centroid in 2D plane', s=100);
        plt.plot(vCenroid[0], vCenroid[1], 'ro', ms=10);   # plot centroid as red circle
        plt.plot(vMedoid[0], vMedoid[1], 'rx', ms=20);     # plot medoid as red star
        

        您还可以使用以下包来计算一个或多个集群的中心点

        !pip -q install scikit-learn-extra > log
        from sklearn_extra.cluster import KMedoids
        GetMedoid = lambda vX: KMedoids(n_clusters=1).fit(vX).cluster_centers_
        GetMedoid([a, b, c, d])[0]
        

        【讨论】:

          【解决方案5】:

          我想说你只需要计算中位数。
          np.median(np.asarray(points), axis=0)

          您的中位数是具有最大中心性的点。
          注意:如果您使用的距离与欧几里得不同,则不成立。

          【讨论】:

          • 这不计算中间值。请注意,当点为 2D 和更高维度时,每个轴上单独取的中位数不是中位数
          猜你喜欢
          • 1970-01-01
          • 2020-11-15
          • 2021-10-16
          • 2020-06-22
          • 2015-01-07
          • 2021-11-24
          • 2017-08-22
          • 1970-01-01
          • 2021-04-19
          相关资源
          最近更新 更多