笔试题,一小时手写k-means算法

循环智能-算法工程师 笔试题:手写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))

4.优化后的算法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值