循环智能-算法工程师 笔试题:手写k-means算法
1.题目描述
数据输出:
一个 N * 1 的一维向量,代表进行聚类之后各个点所属的类id。
要求:
代码可执行、正确、清晰
不得参考任何现成代码,否则自动fail
样例函数:
def clustering(data, k):
N, m = data.shape
…
return data_cluster
算法流程为(使用欧几里得距离):
令S为质心集合,初始化为空集
从数据集中随机选取一个样本点,加入S成为第一个质心
for i = 2 to k:
对于不在S中的每个样本,计算其与当前S中所有质心的距离的最大值D
选取D值最大的点,加入S成为第i个质心
(此时S中包含k个质心)
对每个样本点:
计算其与S中各个质心的距离
将样本点分配至最近质心所属的类
对某个类:
将质心设置为该类所有样本点的均值
在S中更新对应的类的质心
如果S中有质心发生改变,则重复上述过程(4-5)
2.题目解释
相信大家一下子就看出来了,这不就是要实现k-means聚类算法吗?哈哈
3.第一版回答
这是我第一版手写的k-means算法,过于冗余,而且只能处理特征数为2的数据集,并且不能处理重复的数据点…缺点不一而足,后续进行了优化
import numpy as np
#初始化质心
def init_c(data, k):
key_1=np.random.randint(0, len(data))#选取第一个质心
c_list = [] # 质心集合
c_list.append(list(data[key_1]))
temp = np.delete(data,key_1, axis = 0)
length=len(temp)
for i in range(k-1):
max_dis=0
for j in range(0,length):
D=0
for c in c_list:
if dis_E(c,list(temp[j]))>D:
D=dis_E(c,list(temp[j]))
if D>max_dis:
max_dis=D
current_c=j #当前最大值的下标
c_list.append(list(temp[current_c]))
temp = np.delete(temp, current_c, axis=0)
length-=1
return c_list
#计算两点的欧式距离
def dis_E(x,y):
return np.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2)
#计算中心
def c_cal(list_c):
a_x,a_y=0,0
for l in list_c:
a_x+=l[0]
a_y+=l[1]
return [a_x/len(list_c),a_y/len(list_c)]
def clustering(data, k):
N, m = data.shape
c_list=init_c(data, k)
dic={} #存储类簇归属的点的dict
c_type=0
for c in c_list:
l=[]
l.append(c)
dic_temp={c_type:l}
dic.update(dic_temp)
c_type+=1
flag=1
while flag:
for i in range(len(data)):
min_dis=-1
for j in range(len(c_list)):
if min_dis==-1:
min_dis=dis_E(c_list[j],list(data[i]))
current_c=0
if dis_E(c_list[j],list(data[i]))<min_dis:
min_dis=dis_E(c_list[j],list(data[i]))
current_c = j
for j in range(len(c_list)):
list_temp = dic[j]
list_new=[]
for l in list_temp:
if l!=list(data[i]):
list_new.append(l)
dic_temp = {j: list_new}
dic.update(dic_temp)
list_temp=dic[current_c]
list_temp.append(list(data[i]))
dic_temp = {current_c: list_temp}
dic.update(dic_temp)
flag=0
for i in range(len(c_list)):
list_temp = dic[i]
c_new=c_cal(list_temp)
if c_new!=c_list[i]:
flag=1
c_list[i]=c_new
print('当前质心的坐标:')
print(c_list)
print('最终各类的数据点如下:')
print(dic)
#判断每个数据点属于哪一类
result=[]
for i in range(len(data)):
target_i=list(data[i])
for j in range(len(c_list)):
list_temp = dic[j]
for l in list_temp:
if l == target_i:
result.append(j)
print('输出结果如下:')
return result
#主体部分
data = np.random.randint(0,30,size=[40,2]) #随机生成我们的数据集
print('随机生成的数据集:')
print(data)
k = 3 #指定类簇的数量
print(clustering(data,k))