K-means
使用的校内数据集
楼主彩笔
#by ql_Da-qiong
import dm2022exp #老师的数据集
import numpy as np
import matplotlib.pyplot as plot
from numpy import random
import math
from sklearn.model_selection import train_test_split
X, y = dm2022exp.load_ex4_data()
# print(X)
# print(y)
class KMeans(object):
def __init__(self, num_cluster: int, max_iter: int = 1000,
tol: float = 1e-4):
self.num_cluster = num_cluster
self.max_iter = max_iter
self.tol = tol
"""
参数解释:
- num_cluster : 需要将数据分成几个簇,一簇表示一类
- max_iter : 最大迭代次数,kmeans算法当本次计算的候选点和上次
候选点的距离小于某个值之后才会停止,如果始终没有收
敛就会一直算下去,这个值表示最大的迭代次数,当大于
这个迭代次数即使没有收敛也要停下来,如果实验当中
你没有实现这个参数可能会造成超时的情况
- tol : 在参数 `max_iter` 中提到的本次候选点和上次候选点
之间的距离,这个距离可以用高维空间中两个点之间的距
离表示
"""
def fit(self, X: np.ndarray) -> np.ndarray:
# init pre list
pre_list = [-1]*len(X)
centre_list = []
high = len(X)
i = np.random.randint(low=0, high=high, size=self.num_cluster)
for t in i:
centre_list.append(X[t])
print(centre_list)
return self.k_means(X, 0, pre_list, centre_list)
"""
参数解释:
- X : 训练数据,数据维度为(n, m),其中 n 表述数据个数,m 表示属性个数
返回值:
返回值是一个 np.ndarray 对象,内容是每个属性的属于的那一簇,从0开始标记
比如一共5个属性,分成三个簇你的返回值可以是
[0, 0, 1, 2, 2] 或者 [1, 1, 2, 0, 0] 或者 [2, 2, 1, 0, 0]
你只需要用某个值表示某一类即可,具体用哪个数字表示无所谓,你只需要
保证同一类别的数据用的是同一个数字即可
"""
pass
def distance(self, a, b):
return (a[0] - b[0])**2 + (a[1] - b[1])**2
def k_means(self, X, depth, pre_list, centre_list):
print("iter: ",depth + 1,"times")
if depth >= self.max_iter:
return np.array(pre_list)
# classify
for i in range(len(X)):
min_dis = 99999
for j in range(self.num_cluster):
dis = self.distance(X[i], centre_list[j])
if dis <= min_dis:
min_dis = dis
pre_list[i] = j
# print(pre_list)
# re_cal centre
centre_list_t = []
for i in range(self.num_cluster):
sum_x = 0
sum_y = 0
t = []
for j in pre_list:
if i == j:
t.append(True)
else:
t.append(False)
# print("***************************")
# print(pre_list)
# print(sum(t))
# print(X[t])
len_ = sum(t)
if len_ > 0:
# print(X[t])
sum_x = sum(X[t][i][0] for i in range(len(X[t])))
sum_y = sum(X[t][i][1] for i in range(len(X[t])))
# print(sum_x)
# print(sum_y)
list_ = [sum_x / len_, sum_y / len_]
# print("cen:" , list_)
centre_list_t.append(np.array(list_))
else:
centre_list_t.append(centre_list[i])
flag = True
for i in range(self.num_cluster):
if self.distance(centre_list[i], centre_list_t[i]) >= self.tol:
flag = False
if flag:
return np.array(pre_list)
return(self.k_means(X, depth + 1, pre_list, centre_list_t))
m = KMeans(num_cluster = 8, max_iter = 1000,tol = 1e-4)
pre = m.fit(X)
dm2022exp.show_exp4_data(X, pre)
结果可视化