聚类算法的编程结构

Posted

技术标签:

【中文标题】聚类算法的编程结构【英文标题】:Which programming structure for clustering algorithm 【发布时间】:2015-11-13 16:30:57 【问题描述】:

我正在尝试实现以下(分裂)聚类算法(以下是该算法的简短形式,完整描述可在 here 获得):

从样本 x, i = 1, ..., n 开始,将其视为由 n 个数据点组成的单个集群,并为所有点对定义一个相异矩阵 D。修复一个阈值T,用于决定是否拆分集群。

    首先确定所有数据点对之间的距离,并选择它们之间距离(​​Dmax)最大的一对。

    将 Dmax 与 T 进行比较。如果 Dmax > T,则将所选对作为两个新簇中的第一个元素,将单个簇一分为二。剩余的 n - 2 个数据点被放入两个新集群之一。如果 D(x_i, x_l)

    在第二阶段,在两个新集群之一中找到值 D(x_i, x_j),以在集群中找到它们之间距离 Dmax 最大的对。如果 Dmax

输出是聚类数据记录的层次结构。请问如何实现聚类算法。

编辑 1:我附上了定义距离(相关系数)的 Python 函数和在数据矩阵中找到最大距离的函数。

# Read data from GitHub
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/nico/collectiveintelligence-book/master/blogdata.txt', sep = '\t', index_col = 0)
data = df.values.tolist()
data = data[1:10]

# Define correlation coefficient as distance of choice
def pearson(v1, v2):
  # Simple sums
  sum1 = sum(v1)
  sum2 = sum(v2)
  # Sums of the squares
  sum1Sq = sum([pow(v, 2) for v in v1])
  sum2Sq = sum([pow(v, 2) for v in v2]) 
  # Sum of the products
  pSum=sum([v1[i] * v2[i] for i in range(len(v1))])
  # Calculate r (Pearson score)
  num = pSum - (sum1 * sum2 / len(v1))
  den = sqrt((sum1Sq - pow(sum1,2) / len(v1)) * (sum2Sq - pow(sum2, 2) / len(v1)))
  if den == 0: return 0
  return num / den


# Find largest distance
dist=
max_dist = pearson(data[0], data[0])
# Loop over upper triangle of data matrix
for i in range(len(data)):
  for j in range(i + 1, len(data)):
     # Compute distance for each pair
     dist_curr = pearson(data[i], data[j])
     # Store distance in dict
     dist[(i, j)] = dist_curr
     # Store max distance
     if dist_curr > max_dist:
       max_dist = dist_curr

编辑 2:下面粘贴的是 Dschoni 回答中的函数。

# Euclidean distance
def euclidean(x,y):
  x = numpy.array(x)
  y = numpy.array(y) 
  return numpy.sqrt(numpy.sum((x-y)**2))

# Create matrix
def dist_mat(data):
  dist = 
  for i in range(len(data)):
    for j in range(i + 1, len(data)):
      dist[(i, j)] = euclidean(data[i], data[j])
  return dist


# Returns i & k for max distance
def my_max(dict):
    return max(dict)

# Sort function
list1 = []
list2 = []
def sort (rcd, i, k):
  list1.append(i)
  list2.append(k)
  for j in range(len(rcd)):
    if (euclidean(rcd[j], rcd[i]) < euclidean(rcd[j], rcd[k])):
      list1.append(j)
    else:
      list2.append(j)

编辑 3: 当我运行@Dschoni 提供的代码时,算法按预期工作。然后我修改了create_distance_list 函数,以便我们可以计算多元数据点之间的距离。我使用欧几里得距离。对于玩具示例,我加载 iris 数据。我只对数据集的前 50 个实例进行聚类。

import pandas as pd
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', header = None, sep = ',')
df = df.drop(4, 1)
df = df[1:50]
data = df.values.tolist()

idl=range(len(data))
dist = create_distance_list(data)
print sort(dist, idl)

结果如下:

[[24], [17], [4], [7], [40], [13], [14], [15], [26, 27, 38], [3, 16, 39], [25], [42], [18, 20, 45], [43], [1, 2, 11, 46], [12, 37, 41], [5], [21], [22], [10, 23, 28, 29], [6, 34, 48], [0, 8, 33, 36, 44], [31], [32], [19], [30], [35], [9, 47]]

一些数据点仍然聚集在一起。我通过在sort 函数中的actual 字典中添加少量数据噪声来解决这个问题:

# Add small random noise
for key in actual:    
  actual[key] +=  np.random.normal(0, 0.005)

知道如何正确解决这个问题吗?

【问题讨论】:

我不完全确定如何回答所问的问题。您能否扩展“编程结构”的含义?如果您指的是数据结构,那么您的算法的哪一部分需要结构,以及对数据结构的要求是什么?如果您只想重复拆分一组元素而不关心数据的最终表示方式,那么数组或链表可能会起作用。或者,您可以考虑某种形式的树(例如二叉搜索树)。 我只需要反复拆分数据点。我怀疑一个数组就足够了。您知道从哪里/如何开始吗? 您心中有一种编程语言吗?你有一个算法,所以你只需要将算法的步骤转换成一些代码。我会说从编写一个函数开始。 我用 Python 编程,但无论哪种语言都可以。我只需要第 2 步和第 3 步的帮助。 我附上了我最初尝试的代码。 【参考方案1】:

欧几里得距离的正确工作示例:

import numpy as np
#For random number generation


def create_distance_list(l):
'''Create a distance list for every
unique tuple of pairs'''
    dist=
    for i in range(len(l)):
        for k in range(i+1,len(l)):
            dist[(i,k)]=abs(l[i]-l[k])
    return dist

def maximum(distance_dict):
'''Returns the key of the maximum value if unique
or a random key with the maximum value.'''
    maximum = max(distance_dict.values())
    max_key = [key for key, value in distance_dict.items() if value == maximum]
    if len(max_key)>1:
        random_key = np.random.random_integers(0,len(max_key)-1)
        return (max_key[random_key],)
    else:
        return max_key

def construct_new_dict(distance_dict,index_list):
'''Helper function to create a distance map for a subset
of data points.'''
    new=
    for i in range(len(index_list)):
        for k in range(i+1,len(index_list)):
            m = index_list[i]
            n = index_list[k]
            new[(m,n)]=distance_dict[(m,n)]
    return new

def sort(distance_dict,idl,threshold=4):
    result=[idl]
    i=0
    try:
        while True:
            if len(result[i])>=2:
            actual=construct_new_dict(dist,result[i]) 
                act_max=maximum(actual)
                if distance_dict[act_max[0]]>threshold:
                    j = act_max[0][0]
                    k = act_max[0][1]
                    result[i].remove(j)
                    result[i].remove(k)
                    l1=[j]
                    l2=[k]
                    for iterr in range(len(result[i])):
                        s = result[i][iterr]
                        if s>j:
                            c1=(j,s)
                        else:
                            c1=(s,j)
                        if s>k:
                            c2=(k,s)
                        else: 
                            c2=(s,k)
                        if actual[c1]<actual[c2]:
                            l1.append(s)
                        else:
                            l2.append(s)
                    result.remove(result[i])
    #What to do if distance is equal?
                    l1.sort()
                    l2.sort()
                    result.append(l1)
                    result.append(l2)
                else:
                    i+=1
            else:
                i+=1
    except:
        return result


#This is the dataset
a = [1,2,2.5,5]
#Giving each entry a unique ID
idl=range(len(a))
dist = create_distance_list(a)
print sort(dist,idl)  

我编写代码是为了便于阅读,有很多东西可以使代码变得更快、更可靠和更漂亮。这只是为了让您了解如何做到这一点。

【讨论】:

我在上面粘贴了相应的函数。你能帮我解决排序函数中的递归问题吗? 您需要按层次排列的集群吗?还是只是集群? 结果是输入中数据列表的索引聚集在一起。如果需要数据值,只需将索引列表中的每个值设置为输入列表的值即可。 你能告诉我这是什么,你在找什么吗? 是的,这正是我想要的。谢谢。【参考方案2】:

一些数据点仍然聚集在一起。我解决了这个问题 在排序中向实际字典中添加少量数据噪声 功能。

If Dmax &gt; T then divide single cluster in two

您的描述不一定会创建n 集群。 如果一个集群有两条距离小于T的记录, 它们将聚集在一起(我错过了什么吗?)

【讨论】:

以上是关于聚类算法的编程结构的主要内容,如果未能解决你的问题,请参考以下文章

大数据聚类算法知多少?如何无需编程快速实践?算法干货

聚类算法研究

层次聚类算法原理总结

人工智能算法之聚类算法

聚类算法(K-means聚类算法)

OPTICS聚类算法详解