使用python实现最短距离聚类

写在前面

  最近老师布置了一个作业,内容是对国内各省份生产总值与固定资产投资的数据,采用最短距离法进行聚类。原本这种关于矩阵运算的问题用Matlab是比较合适的,奈何Matlab我运用的不是太熟练,所以选择采用python完成。写这篇博客的目的是记录一下代码中使用到的关于Numpy库的一些函数,以及整理一下实现的流程以供需要完成类似功能的小伙伴参考。

使用的Numpy函数

  1. np.zeros:功能是创建一个0矩阵,具体使用
  2. np.max:返回矩阵的最大值,可以根据行或列,具体使用
  3. np.column_stack:将两矩阵按列合并,具体使用
  4. np.shape:返回矩阵的维度,具体使用
  5. np.fabs:得到矩阵的绝对值
  6. np.argwhere:返回查找某数的位置信息,具体使用
  7. np.where:类似于三元表达式,具体使用
  8. np.min:同np.max
  9. np.delete:删除指定行或指定列,具体使用
  10. np.append:添加数据到已有矩阵,具体使用

具体实现流程

1. 读取数据

  实验数据格式如下所示。
使用python实现最短距离聚类_第1张图片

  读取数据部分思路即将数据逐行读入,设置一个标识以不存入第一行数据,最后根据逗号分割每行的内容并将其分别存入对应的列表中。直接附上源码吧!

def getData(data_file):
    x_data = []
    y_data = []
    global name
    name = []
    iden = 1
    f = open(data_file, "r", encoding='utf_8')
    line = f.readline()
    while line != '':
        # 去除第一行
        if iden == 1:
            iden = iden + 1
            line = f.readline()
            continue
        # 存入数据至两个列表
        tem = line.strip('\n').split(',')
        name.append(tem[0])
        x_data.append(tem[1])
        y_data.append(tem[2])
        line = f.readline()
    return list(map(float, x_data)), list(map(float, y_data))

2.数据预处理

极大值标准化

  利用np.max函数将数据进行极大值标准化,

# 极大值标准化
    x_max = np.max(x_data)
    y_max = np.max(y_data)
    x = x_data / x_max
    y = y_data / y_max
    maum_value = np.column_stack((x, y))

生成绝对值距离矩阵

  由最短距离聚类法的的实现过程可知,需要一个距离矩阵,此处采用较为简单的绝对值距离,公式与代码如下。
使用python实现最短距离聚类_第2张图片

# 求数据的绝对值距离矩阵
    abs_matrix = np.zeros((len(x_data), len(y_data)))
    for i in range(len(x_data)):
        for j in range(len(y_data)):
            if i > j:
                tem = 0
                for k in range(np.shape(maum_value)[1]):
                    tem = tem + np.fabs(maum_value[i][k] - maum_value[j][k])
                abs_matrix[i][j] = tem
    return abs_matrix

3.最短距离聚类法

寻找矩阵最小值的索引

  由于数据预处理得到的结果是一个下三角矩阵,若直接使用np.min找最小值会将0值找出,所以此处我采用较为直接的办法,直接将矩阵的0所由0值变为100。如果有更好的办法,欢迎交流。

 # 寻找矩阵中最小的值的索引
 abs_matrix[(abs_matrix == 0)] = 100
 min_arg1 = np.argwhere(abs_matrix == np.min(abs_matrix))[0][0]
 min_arg2 = np.argwhere(abs_matrix == np.min(abs_matrix))[0][1]

计算新类与各类的距离

  因为绝对值矩阵的右上边全为100,导致寻找新类与各类矩阵的距离代码实现较为繁琐,所以此处我将下三角矩阵转为对称矩阵。而后只需取出两行在判断每列的最小值(两行的索引就是前面最小值所在的行与列)。最后删除要聚类的两个数据即为新类到各类的距离。

# 将下三角矩阵变为对称矩阵
 abs_matrix[(abs_matrix == 100)] = 0
 tem_matrix = np.where(abs_matrix, abs_matrix, abs_matrix.T)
 # 获取选出的两行比较最小值,赋值到新建的行
 tem_matrix = tem_matrix[[min_arg1, min_arg2], :]
 new_list = np.min(tem_matrix, axis=0)
 # 删除要聚类的两个数据,并加上一个自己到自己的距离0
 new_list = np.delete(new_list, [min_arg1, min_arg2], axis=0)
 new_list = np.append(new_list, 0)

将名字加入矩阵

  由于最后想知道聚类的过程,所以此处我选择将各类的名字加入绝对值矩阵,以便打印信息。

 # 将名字加入矩阵中,以便后期知道哪个和哪个聚类
abs_matrix = np.column_stack((name, abs_matrix))
# 向name的第一个位置补一个0
name.insert(0, '0')
abs_matrix = np.row_stack((name, abs_matrix))
# 取出聚类的信息,以便打印名字
name_1 = abs_matrix[min_arg1 + 1, 0]
name_2 = abs_matrix[min_arg2 + 1, 0]
print(f"{name_1}{name_2}聚为一类,记为{name_1},{name_2}")

删除对应的行和列

  根据最短距离聚类法的思想,需要将参与聚类的类从原矩阵中删除。

# 删除对应的行和列
abs_matrix = np.delete(abs_matrix, [min_arg1 + 1, min_arg2 + 1], axis=0)
abs_matrix = np.delete(abs_matrix, [min_arg1 + 1, min_arg2 + 1], axis=1)

除去矩阵的名字

  由于需要计算矩阵的最小值,所以需要将前面加入的名字去除,并将矩阵由字符型转换为浮点型。

# 去除名字并变为浮点型矩阵
 abs_matrix = np.delete(abs_matrix, 0, axis=0)
 abs_matrix = np.delete(abs_matrix, 0, axis=1)
 abs_matrix = abs_matrix.astype("float32")

将新类到各类的距离加入距离矩阵

  此处需要将前面得到的新类到各类的距离矩阵中加入一个0,因为自己到自己的距离为0。

# 创建一个加入新类后的矩阵
 one_list = np.zeros((np.shape(abs_matrix)[0], 1))
 abs_matrix = np.column_stack((abs_matrix, one_list))
 abs_matrix = np.row_stack((abs_matrix, new_list))

处理名字列表

  由于代码中需要将名字加入距离矩阵,所以需要删除名字列表中已经聚类的名字,并且需要加入新类的名称。

# 处理名字列表
 name.pop(0)
 name.remove(name_1)
 name.remove(name_2)
 new_name = name_1 + "," + name_2
 name.append(new_name)

设置循环条件

  至此算法主要逻辑已经完成,最后只需要根据某个条件重复上述过程即可。很显然,结束条件即最终的距离矩阵大小为1*1时,标志着聚类完成。所以此处我的思路为设置一个标识另其初始值为0,当聚类完成时值变为1。

while biaoshi == 0:
    min_cluster(abs_matrix)

写在后面

  由于我对于算法之类的基础知识比较薄弱,所以代码逻辑的思路较为简单。如果读者有更好的思路或者我有什么错误的地方,欢迎交流指正!

你可能感兴趣的:(python,其他)