目录
前言
通过本文您可以学到K-means的基本思想,以及2种代码实现方法!
一、K-means是什么?
K-menas是机器学习中的一种无监督的算法,属于聚类的算法。作用是将一堆数据,按照相关的联系分为几个类别。一般用于客户分类等方面。
二、主要思想
1. 核心思想:
核心思想其实都已经包含与算法的名字内。K是要划分的类别,means是求均值。这个俩个贯穿了整个K-means算法的核心。
2. 2个for循环:
整个算法是依靠2个for循环来实现的,第一个for循环的作用是将所有样本进行分类。第二个for循环的作用是聚类中心得移动。
3.实现流程:
1.我们需要先在样本中随机生成k个聚类中心。
2.需要考虑一下用什么数据结构来存【样本类别(k个),样本到此类中心的min距离】
这个非常重要。
3.开始第一个for循环。计算样本中每个点到k个聚类中心的距离,距离哪个点最小,划分
为哪一类,并标记好距离是多少。
4.开始第二个for循环。跟据上述步骤我们已经将所有样本分为k个类别了,现在我们要将
每一类别的样本数据求均值。此时,我们就得到了k个新的聚类中心点。
5.判断分类操作什么时候停止。一个是看样本类别是否变更,另一个是聚类中心点是否变更。
6.我们将3,4,5几个步骤放到一个大的循环里面,让2个for循环一直执行,直到聚类中心停止。
三、代码实现
1.方法一
import numpy as np
import random
import copy
import time
import matplotlib.pyplot as plt
Data = np.random.rand(100,2)
def initCentroidrs(data,k):
num = len(data)
random.seed(66)
index = np.random.choice(num,k,replace=False) # flase不放回抽样
centroidrs = data[index]
return centroidrs
c = initCentroidrs(Data,4)
iters = 300
count = 0
a = time.time()
while (iters>0):
B = []
iters -=1
for i in c:
# dis是一个列表,里面是每一个样本到聚类中心的距离。
dis = np.sqrt(((Data-i)**2).sum(axis=1))
# B是外侧列表[]里面放置4个dis内侧列表
B.append(dis)
# 矩阵化
B = np.array(B)
# 按列求最小值的下标,此下标即为每一个样本所属于的类别
index = np.argmin(B,axis=0)
c_ = copy.deepcopy(c) # 深拷贝,复制中心点数据。
# 第二个循环求,分好类之后,每一类样本的平均值,即为类的聚类中心点坐标。然后更新聚类中心。
for i in range(len(c)):
# [index==i] 返回的是【ture,false,....】长度等于样本个数。
# 当i=0时,Data只取对应位置为ture的数据,所以Data_i为0类别所有样本的数据。
Data_i = Data[index == i,:]
# 对此数据按列求均值即为本类的新的聚类中心点。
c[i] = np.mean(Data_i,axis=0)
# 判断新的聚类中心,与上一次的聚类中心是否一致。如果一致,则不需更新聚类中心点。
count +=1
if (c_==c).all():
break
b = time.time()
print('最终聚类中心')
print(c)
print('上一次循环聚类中心')
print(c_)
print('循环次数',count)
print('用时时长',b-a)
plt.scatter(c[:,0],c[:,1])
plt.scatter(Data[:,0],Data[:,1])
plt.show()
结果展示
最终聚类中心
[[0.13850262 0.26604074]
[0.3046347 0.71009279]
[0.66872951 0.25949051]
[0.74085396 0.71999526]]
上一次循环聚类中心
[[0.13850262 0.26604074]
[0.3046347 0.71009279]
[0.66872951 0.25949051]
[0.74085396 0.71999526]]
循环次数 9
用时时长 0.0009975433349609375
Process finished with exit code 0
2.方法二
import numpy as np
import random
import copy
import time
np.set_printoptions(suppress=True)
Data = np.random.rand(100,2)
K = 4
def dist(x1,x2):
return np.square(sum((x1-x2)**2))
def initCentroidrs(data,k):
num = len(data)
random.seed(66)
index = np.random.choice(num,k,replace=False) # flase不放回抽样
centroidrs = data[index]
return centroidrs
a = time.time()
def k_means(data,k):
m,n = data.shape # m为样本个数,n为特征个数
class_dist = np.zeros((m,2)) # 构建一个都是0的(m,2)矩阵,第一列放类别,第二列放最小距离。
centroidrs = initCentroidrs(data, k)
change_center = True
count = 0
while change_center:
change_center = False
for i in range(m): # 循环所有样本
# 设置初始的类别,跟距离
min_dist = np.inf # 无限大
class_index = 0
# 计算第i个点到k个质心的距离,并以最小的距离将其进行归类(0到k-1类)。
for j in range(k):
dist_x2c = dist(data[i],centroidrs[j])
if dist_x2c < min_dist:
min_dist = dist_x2c
class_index = int(j)
# 判断初始设的类别与上述的分类是否一致,如果否就变更类别。(初始类别都是0)
if class_dist[i,0] != class_index:
class_dist[i,0] = class_index
class_dist[i, 1] = min_dist
change_center = True
count +=1
c_=copy.deepcopy(centroidrs)
for j in range(k):
# class_dist[:,0] == j 是bool类型[ True True False False False False]
data_j = data[class_dist[:,0] == j,:] # 类别是j的所有数据
centroidrs[j] = np.mean(data_j,axis=0)
return centroidrs,class_dist,c_,count
# 5. 打印最终的聚类中心和每个样本所属的簇
centroidrs, class_dist,c_,count = k_means(Data,4)
b = time.time()
print('最终聚类中心')
print(centroidrs)
print('上一次循环聚类中心')
print(c_)
print('循环次数',count)
print('用时时长',b-a)
# print(class_dist)
结果展示
最终聚类中心
[[0.38176368 0.33070398]
[0.17384564 0.69145547]
[0.62558847 0.79347614]
[0.79725016 0.29485955]]
上一次循环聚类中心
[[0.38176368 0.33070398]
[0.17384564 0.69145547]
[0.62558847 0.79347614]
[0.79725016 0.29485955]]
循环次数 115
用时时长 0.023465871810913086
总结
本文介绍了k-means的核心思想,基本实现流程,以及代码实现部分。欢迎大家一起学习交流!