K-Means算法(python实现)

k-means

  • 计算过程
  1. 估计样本中的总分类个数 K K K
  2. 随机选取K个聚类质心点 μ 1 , μ 2 , ⋯   , μ k \mu_1,\mu_2,\cdots,\mu_k μ1,μ2,,μk
  3. 对于每一个样本,分别计算到每个质心点的距离 d 1 , d 2 , ⋯   , d k d_1,d_2,\cdots,d_k d1,d2,,dk,取最近的一个距离,作为该样本暂时所属的分类k。可以选择euclidean距离作为参考依据。至此,每个样本都归入某个类别下
  4. 对于每个类别,计算其所辖的每个样本到其质心的距离之和,作为累积距离偏差 W k W_k Wk
  5. 针对每个类别,重新计算质心: μ k = ∑ i = 1 N k x i N k \mu_k=\dfrac{\sum_{i=1}^{N_k} x_i}{N_k} μk=Nki=1Nkxi,其中, N k N_k Nk表示当前该类别下的样本数量
  6. 利用新的质心,再次计算累积距离偏差 W k ′ W_k' Wk
  7. 对于两次计算出的 W k W_k Wk,如果其差值小于指定的误差限(例如0.00001),则可认为已经收敛;否则再次进行步骤5)和6)
  • 算法的优缺点

    1.算法简单,易于实现
    2.初始质心选择很重要,有可能会导致找不到全局收敛解(只找到局部收敛解);但是又没有什么好的办法来优化质心的选择
    3.K值的选取也很重要。K值越大,对训练数据的分类将很好,但有可能造成overfit。也并没有太好的办法确定K值,只能多实验几次。

  • 代码实现

''' 自定义k-means算法实现对数据分类 '''

%matplotlib inline

import numpy as np 
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs

# 计算两点之间距离
def distance(pt1, pt2):
    return np.sum((pt1 - pt2) ** 2)

# 计算当前各个中心点中离给定点pt最近的一个
def classify(pt, centers):
    temp = [distance(pt, centers[i]) for i in range(len(centers))]
    index = np.argmin(temp)
    dist = temp[index]
    return (index, dist)

# 将每个点归入到离它最近的中心点类别下
def re_category(X, categories, centers):
    for category in categories:
        category.clear()
    newcost = 0.0
    for pt in X:                                
        index, dist = classify(pt, centers)
        categories[index].append(pt)            # 将pt纳入离它最近的中心点类别下
        newcost += dist
    return newcost / M    # 计算每个点到离它最近的中心点的平均距离

# 根据当前的类别划分,重新计算每个类别下新的中心点
def calc_centers(categories, centers):
    for i in range(len(categories)):
        # categorise[i]中的每行数据有两列,分别代表横坐标和纵坐标,因此按列求平均值,就可得出新的质心横坐标和纵坐标
        centers[i] = np.mean(categories[i], 0)  

M = 100
K = 4
# 围绕K个中心点,生成M个随机二维数据点
X, y = make_blobs(n_samples=M, centers=K, cluster_std=2.0, random_state=20)
cost = 1e10             # 初始误差,设置为很大
epsilon = 1e-8
max_iter = 100
categories = [[] for i in range(K)]

# 随机选择K个中心点作为初始点
init_indecies = np.random.randint(0, M, K)
centers = X[init_indecies]
# 计算分类
newcost = re_category(X, categories, centers)
iter = 0
while iter < max_iter:
    iter += 1
    if np.abs(newcost - cost) > epsilon :
        cost = newcost
        # 重新计算各类中心点
        calc_centers(categories, centers)
        # 再次计算
        newcost = re_category(X, categories, centers)
    else:
        break

print("经过",iter,"次循环,质心计算完成...")

yPredicts = np.zeros(M)
# 计算每个样本所属的类别
for i in np.arange(M):
    category, _ = classify(X[i], centers)
    yPredicts[i] = category

# 查看原始分类情况
plt.figure(1)
plt.title("Origin Classification")
plt.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=plt.cm.Paired)

# 查看K-Means分类结果
plt.figure(2)
plt.title("KMeans Classification")
plt.scatter(X[:, 0], X[:, 1], c=yPredicts, s=30, cmap=plt.cm.Paired)
plt.show()

经过 7 次循环,质心计算完成…
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值