【机器学习与算法】python手写算法:Kmeans和Kmeans++算法

  • 背景
  • K-means算法python代码
  • 结果对比

背景

K-Means算法因其算法简单,收敛快等特点而成为最常用的无监督学习方法之一,K-means算法过程如下:

  1. 随机选取K个中心点;
  2. 计算每个样本点到K个中心点的距离,离谁最近就归为哪一类;
  3. 对于每一分类,计算该分类中所有点的均值作为新的中心点;
  4. 重复2-3步知道中心点基本不再变化。

K-means算法的一大缺陷就是它对初值(一开始选取的中心点)比较敏感,初值选不好,聚类效果可能很渣。而K-Means++即是对K-Means算法选取初值的一种优化算法,可以让K-Means聚类效果相对更好,而且收敛更快。K-Means++的算法过程如下:

  1. 先随机选取第一个中心点;
  2. 在这样一个概率密度分布下,选取下一个中心点:
    D(x)2/Σ(D(x)2)D(x)^2/\Sigma(D(x)^2) D(x)2/Σ(D(x)2)
    其中D(x)是样本点距离已选的最近中心点的距离;
  3. 重复第2步直至选出n个初始中心点。

K-means++的核心思想就是把距离转换为概率,选取下一个中心点时,距离已选中心点越远,被选中的概率越大。那为啥不直接选取距离所有已选中心点最远的点呢,算法上不是更简单?不这么做主要是因为这样太容易选到异常离群点,从而影响最终的聚类效果。
更详细的算法描述请参看K-Means++文献。

那给定概率权重的随机采样怎么用python实现呢?主要参考了这篇博客,主要思想就是把每个点的概率权重从头到尾接起来,然后从这个范围内随机采样一个值,看这个值落到哪个点的区间内,代码如下:

import random
def random_weight(weight_data):total = sum(weight_data.values())    # 权重求和ra = random.uniform(0, total)   # 在0与权重和之前获取一个随机数 curr_sum = 0for k in weight_data.keys():curr_sum += weight_data[k]             # 在遍历中,累加当前权重值if ra <= curr_sum:          # 当随机数<=当前权重和时,返回权重keyreturn k

我们用这个函数随机采样10000个样本看下分布:

weight_data = {'1': 0.1, '2': 0.4, '3': 0.5}
from collections import Counter
res = []
for i in range(10000):res.append(random_weight(weight_data))print(Counter(res))#OUTPUT:
Counter({'3': 4970, '2': 4077, '1': 953})

1、2、3被选中的次数基本符合1:4:5,符合我们的预期。

K-means算法python代码

import pandas as pd
import numpy as np
import randomclass K_Means:def __init__(self,n_cluster=3,init = 'k-means++',max_iter=300,tol=0.0001):self.n_cluster = n_cluster #最终要聚成的团簇数,同时也是中心点个数self.init = init #初始点选取的方式:随机选取或K-means++self.max_iter = max_iter #最大迭代次数self.tol = tol #判断迭代结果闭合的标准,两次迭代中心点距离小于tol则停止迭代,和sklearn不同,sklearn用的是所有点到其最近点的距离平方和self.center = None #记录最终的中心点self.flag = [] #记录训练样本最后的分类标签@property #私有化属性——中心点def cluster_centers_(self):return self.center   @property #私有化属性——训练样本分类标签def labels_(self):return np.array(self.flag)    @property #私有化属性——迭代的次数def n_iter_(self):return self.n_iterdef _eula_distance(self, x1, x2):'''计算并返回两个点的欧式距离平方'''return np.sum((x1-x2)**2)def _random_weighted(self, weight_data):'''weight_data:字典的形式存储每个点及其概率权重根据每个点的概率权重,随机采样一个点并返回'''total = sum(weight_data.values())    # 权重求和ra = random.uniform(0, total)   # 在0与权重和之前获取一个随机数 curr_sum = 0for k in weight_data.keys():curr_sum += weight_data[k]             # 在遍历中,累加当前权重值if ra <= curr_sum:          # 当随机数<=当前权重和时,返回权重keyreturn kdef _get_min_eula_dis(self, x, li):'''计算并返回x和数组li中所有点的最小距离平方,及对应下标'''res = []for item in li:res.append(self._eula_distance(x,item))return min(res), res.index(min(res))def _k_means_plus_plus(self,X):'''k-means++方法采样n个初始样本点'''#初始化每个样本点被选为中心点的概率权重都为1,及uniformly选第一个中心点weight = [1]*X.shape[0]point = []for i in range(self.n_cluster):#生成所有样本点及其概率权重的字典weighted_point = {tuple(x):y for x,y in zip(X.values,weight)}#根据每个样本的概率权重随机选一个样本作为中心点point.append(self._random_weighted(weighted_point))#根据已选中的中心点,计算其它样本到已选中心点的最小距离平方,作为新的概率权重weight = list(map(lambda x:self._get_min_eula_dis(x,point)[0],X.values))return np.array(point)def fit(self, X:pd.DataFrame):'''K-means训练拟合'''if self.init ==  'random':#随机选n个点做中心点self.center = X.sample(self.n_cluster,random_state = 1).valueselif self.init == 'k-means++':#使用k-means++方法选取中心点self.center = self._k_means_plus_plus(X)else:raise KeyError('Only random or k-means++ is allowed!')iter_num = 1while iter_num<self.max_iter:#对于训练集中的每个点:把距离最近的中心点的下标返回作为该点的类别标签self.flag = list(map(lambda x:self._get_min_eula_dis(x,self.center)[1],X.values))new_center = []delta = []#对于每一类for i in set(self.flag):#计算该类中所有点的均值new_center.append(X.loc[np.where(np.array(self.flag)==i)].mean(axis=0).values)#计算两次迭代中心点的距离delta.append(self._eula_distance(self.center[i],new_center[i]))#把每类的均值点作为新中心点self.center = np.array(new_center)#如果每个中心点和上次迭代的距离都小于tol阈值,则停止迭代if np.array(list(map(lambda x:x<self.tol, delta))).all():breakiter_num += 1#记录下迭代的次数self.__setattr__('n_iter',iter_num-1)def predict(self, X):'''计算距离最近的中心点的下标作为类别标签'''label = []for p in X.values:label.append(self._get_min_eula_dis(p, self.center)[1])return np.array(label)

结果对比

我们把自己实现的K-means算法用随机采样和K-Means++采样分别跑一下结果,并和sklearn结果做一个对比:

if __name__ == '__main__':import matplotlib.pyplot as pltfrom sklearn.datasets import make_blobsfrom sklearn.cluster import MiniBatchKMeans, KMeansnp.random.seed(0)#定三个中心点,随机生成800个服从各项同性高斯分布的二维点centers = [[1, 1], [-1, -1], [1, -1]]n_clusters = len(centers)X, labels_true = make_blobs(n_samples=800, centers=centers, cluster_std=0.7)#随机采样中心点进行K-means聚类km_r = K_Means(init='random')km_r.fit(pd.DataFrame(X))#k-means++采样中心点进行K-means聚类km_pp = K_Means(init='k-means++')km_pp.fit(pd.DataFrame(X))#调用sklearn包的K-means方法进行对比k_means = KMeans(init='k-means++', n_clusters=3, n_init=1)k_means.fit(X)fig = plt.figure(figsize=(16, 5))colors = ['#4EACC5', '#FF9C34', '#4E9A06']ax = fig.add_subplot(1, 3, 1)for k, col in zip(range(n_clusters), colors):my_members = k_means.labels_ == kcluster_center = k_means.cluster_centers_[k]ax.plot(X[my_members, 0], X[my_members, 1], 'w',markerfacecolor=col, marker='.', markersize=9)ax.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col,markeredgecolor='k', markersize=6)ax.set_title('KMeans-sklearn')ax = fig.add_subplot(1, 3, 2)for k, col in zip(range(n_clusters), colors):my_members = km_r.labels_ == kcluster_center = km_r.cluster_centers_[k]ax.plot(X[my_members, 0], X[my_members, 1], 'w',markerfacecolor=col, marker='.', markersize=9)ax.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col,markeredgecolor='k', markersize=6)ax.set_title('K_Means-python-random')plt.text(-3, 1.8,  'iter_nums: %d' % (km_r.n_iter_))ax = fig.add_subplot(1, 3, 3)for k, col in zip(range(n_clusters), colors):my_members = km_pp.labels_ == kcluster_center = km_pp.cluster_centers_[k]ax.plot(X[my_members, 0], X[my_members, 1], 'w',markerfacecolor=col, marker='.', markersize=9)ax.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col,markeredgecolor='k', markersize=6)ax.set_title('K_Means-python-k-means++')plt.text(-3, 1.8,  'iter_nums: %d' % (km_pp.n_iter_))plt.show()


可以看到两种方法和调用sklearn包跑出的结果基本一致,而且使用K-means++选取初始点后,达到收敛的迭代次数明显比随机采样要少。


最后,欢迎阅读其它算法的python实现:
【机器学习与算法】python手写算法:Cart树
【机器学习与算法】python手写算法:带正则化的逻辑回归
【机器学习与算法】python手写算法:xgboost算法
【机器学习与算法】python手写算法:Kmeans和Kmeans++算法
【机器学习与算法】python手写算法:softmax回归

【机器学习与算法】python手写算法:Kmeans和Kmeans++算法相关推荐

  1. Python手写实现LDA与QDA算法

    Python手写实现LDA与QDA算法 简略版 LDA QDA 完整版 LDA QDA 对IRIS数据集进行实验 近期实验室在上一门机器学习的讨论班,第一次作业中有一道题要求实现LDA算法与QDA算法 ...

  2. 人工智能的本质:最优化 (神经网络优化算法python手写实现)

    人工智能的本质就是最优化.假设把任务比作是一碗饭, 传统的解决方法,就是根据数学公式,然后一口气吃完饭,如果饭碗小,数学公式还行,如果饭碗大,数学公式能一口吃完饭吗? 人工智能的本质就是最优化,得益于 ...

  3. 用Python手写十大经典排序算法

    作者:hustcc 来源:https://github.com/hustcc/JS-Sorting-Algorithm 排序算法是<数据结构与算法>中最基本的算法之一. 排序算法可以分为内 ...

  4. 经典实战案例:用机器学习 KNN 算法实现手写数字识别 | 原力计划

    作者 | 奶糖猫 来源 | CSDN 博客,责编 | 夕颜 头图 | CSDN 下载自视觉中国 出品 | CSDN(ID:CSDNnews) 算法简介 手写数字识别是KNN算法一个特别经典的实例,其数 ...

  5. 开根号的笔算算法图解_机器学习KNN算法之手写数字识别

    1.算法简介 手写数字识别是KNN算法一个特别经典的实例,其数据源获取方式有两种,一种是来自MNIST数据集,另一种是从UCI欧文大学机器学习存储库中下载,本文基于后者讲解该例. 基本思想就是利用KN ...

  6. 【机器学习与算法】python手写算法:Cart树

    [机器学习与算法]python手写算法:Cart树 背景 代码 输出示例 背景 Cart树算法原理即遍历每个变量的每个分裂节点,找到增益(gini或entropy)最大的分裂节点进行二叉分割. 这里只 ...

  7. 用 Python 手写机器学习最简单的 KNN 算法

    作者 | 苏克1900 责编 | 胡巍巍 说实话,相比爬虫,掌握机器学习更实用竞争力也更强些. 目前网上大多这类教程对新手都不友好,要么直接调用 Sklearn 包,要么满篇抽象枯燥的算法公式文字,看 ...

  8. Python 手写机器学习最简单的 kNN 算法

    https://www.toutiao.com/a6698919092876739079/ Python 手写机器学习最简单的 kNN 算法 苏克1900 Python爬虫与数据挖掘 本文 3000 ...

  9. python手写字母识别_机器学习--kNN算法识别手写字母

    本文主要是用kNN算法对字母图片进行特征提取,分类识别.内容如下: kNN算法及相关Python模块介绍 对字母图片进行特征提取 kNN算法实现 kNN算法分析 一.kNN算法介绍 K近邻(kNN,k ...

  10. java手撕KMeans算法实现手写数字聚类(失败案例)

    最近几天刚刚接触机器学习,学完K-Means聚类算法.正好又赶上一个课程项目是识别"手写数字",因为KMeans能够实现聚类,因此自然而然地想要通过KMeans来实现. 前排提示: ...

最新文章

  1. 进程之间的信号通信,类型、处理机制笔记
  2. 禁止COOKIE后对SESSION的影响
  3. 下一步,该怎么做空中国概念股?
  4. GDI+需要Dispose的对象(不断更新中)
  5. GetProcAddress 根据 ordinal 导入函数
  6. java 字符串驻留_java String 以及字符串直接量 与 字符串驻留池 ...
  7. php 一片空白,解决运行PHP一片空白
  8. c语言 java append_C++中append函数的用法和函数定义。谢谢!
  9. 反汇编基础-加法的求值过程(各种类型)
  10. CLR 4.0有哪些新东西? -- 状态错乱异常 Corrupted state Exception
  11. 怎样用一个3升的杯子和一个5升的杯子装出4升水来(杯子没有刻度)?
  12. 永久的CheckBox(单选,全选/反选)!
  13. B+/-Tree原理(mysql索引数据结构)
  14. struts的执行流程
  15. 11.软件架构设计:大型网站技术架构与业务架构融合之道 --- 多副本一致性
  16. heartbeat 高可用工具
  17. 佛罗里达大学计算机专业世界排名,2020年中佛罗里达大学排名TFE Times美国最佳计算机科学硕士专业排名第107...
  18. RTL概念与常用RTL建模
  19. KML转geojson在线工具和数据抽稀工具
  20. 优秀人才有没有什么共同的特质可供识别?“Stay young”的特质,这种人基本没有到天花板。...

热门文章

  1. 迅雷边下边看实现过程分析
  2. python自动上传图片_Python+selenium自动上传博客图片至新浪微博相册
  3. OLED 屏幕的使用
  4. xcode6-beta下载
  5. 「股票」东方财富网公式-缩量
  6. 2022,从阅读开始
  7. 常用软件分类 精选列表(一)
  8. java move函数重新调用_Move Method (搬移函数)
  9. Java基础题26:(多选题)下列哪些选项属于Java技术体系()
  10. 调出软键盘 挤掉标题栏咋办