本文中介绍的是一种常见的无监督学习算法,名字叫做K均值算法:K-Means算法
。
K-Means
算法在无监督学习,尤其是聚类算法中是最为基础和重要的一个算法。它实现起来非常简单。聚类效果也很不错的,因此应用非常广泛。
本文将会从以下8
个方面进行详细的讲解:
在正式介绍K-Means
算法之前,我们先解释一下无监督学习。用一句很通俗的话来解释:
是否有监督(supervised),我们只需要看输入的数据是否有标签
输入的数据如果带有标签,则是有监督学习,比如KNN算法(K近邻)就是监督学习的典型算法;如果没有标签,则认为是无监督学习,比如本文中即将介绍的K-Means算法
我们看看无监督学习聚类算法的应用:
K-Means
聚类算法是一种迭代求解的聚类分析算法。算法思想是:我们需要随机选择K个对象作为初始的聚类中心,然后计算每个对象和各个聚类中心之间的距离,然后将每个对象分配给距离它最近的聚类中心。
聚类中心及分配给它们的对象就代表着一个聚类。每分配一个样本,聚类的中心会根据聚类中现有的对象被重新计算。此过程将不断重复,直至满足设置的终止条件。
K-Means
算法的具体步骤如下:
1、给定需要进行聚类划分的数据集
2、随机选择2个聚类中心(K=2)
3、计算每个数据点到质心的距离,并将数据点划分到离它最近的质心的类中
4、计算2个数据集的各自的质心(红点、蓝点的均值),将聚类中心移动到均值处,变成新的聚类中心
5、找到新的聚类中心。如果
K-Means
算法需要运行多次才能达到图f的效果。注:以上图形来自吴恩达老师在机器学习视频的讲解截图
k值决定了我们将数据划分成多少个簇类。k个初始化的质心的位置选择对最后的聚类结果和整个大代码的运行时间都有非常大的影响。因此需要选择合适的k个质心
一般k值是通过先验知识来选取的。如果没有什么先验知识,我们可以通过交叉验证的方式来选择一个合适的k值。
在机器学习中,我们常用的距离有以下几种:
1、两个集合之间的 x i , x j x_i,x_j xi,xj的 L p L_p Lp距离定义为:
2、当p=1则表示为曼哈顿距离:
3、当p=2则表示为我们常用的欧式距离:
4、当p趋于无穷时,表示为切比雪夫距离,它是各个坐标距离的最大值:
在K-Means
算法中一般采用的是欧式距离
下面讲解一种利用Python实现k-means算法的代码:
import numpy as np
import pandas as pd
import random # 随机模块
import re
import matplotlib.pyplot as plt
# 导入数据
def loadDataSet():
dataset = np.loadtext("user/skl/cluster/dataset.csv") # 个人文件路径
return dataset # 返回数据集
# 绘图函数
def show_fig():
dataset = loadDataSet() # 导入数据
fig = plt.figure() # 确定画布
ax = fig.add_subplot(111) # 一个子图
ax.scatter(dataset[:,0], dataset[:,1]) # 传入绘图数据
plt.show()
# 定义欧式距离公式
# 两个向量间的欧式距离公式:[(x_1 - x_2)^2 + (y_1 - y_2)^2 + (x_n - y_n)^2]
def calcudistance(vec1,vec2): # 传入两个向量
return np.sqrt(np.sum(np.square(vec1 - vec2))) # 向量相减在平方,最后再求和
# 初始化质心
def initCentroids(dataset, k):
# 初始化执行;dataset是传入的数据
# k:选择分类簇的个数
dataset = list(dataset) # 数据列表化
return random.sample(dataset,k) # 随机选取k的模块
# 计算每个数据点和质心的距离,并归属到距离最小的类别中
def minDisctance(dataset, centroidList): # 传入数据集和选取的质心列表
clusterDict = dict() # 保存簇类结果
k = len(centroidList) # 质心列表的长度:总共多少个质心表示分成多少类
for item in dataset: # 原始数据中的每个元素
vec1 = item # 数据中的向量
flag = -1 # 标志位
minDis = float("inf") # 初始化为无穷大值
for i in range(k):
vec2 = centroidList[i] # 取出第i个质心
distcance = calcudistance(vec1, vec2) # 计算欧式距离
if distance < minDis:
minDis = distance # 如果算出来的实际距离小于最小值的初始值,则将真实值distance赋值给最小值(更新最小值)
flag = i # 循环结束时,flag保存与当前item最近的簇标记
if flag not in clusterDict.keys():
clusterDict.setdefault(flag,[])
clusterDict[flag].append(item) # 加入到相应的簇类中
return clusterDict # 不同的类别
# 重新计算质心
def getcentroids(clusterDict):
# 重新计算k个质心
centroidList = [] # 质心空列表
for key in clusterDict.keys(): #
centroid = np.mean(clusterDict[key], axis=0) # 现有数据点的平均值
centroidList.append(centroid)
return centroidList # 得到新的质心
# 计算均方误差
def getVar(centroidList, clusterDict):
# 将簇类中各个向量和质心的距离累加求和
sum = 0.0 # 初始值
for key in clusterDict.keys(): # 簇类中的键
vec1 = centroidList[key] # 取出某个质心
distance = 0.0 # 距离初始化值
for item in clusterDict[key]: # 簇类的键
vec2 = item
distance += calcudistance(vec1, vec2) # 求距离
sum += distance # 累加
return sum
# 显示簇类
def showCluster(centroidList, clusterDict):
# 显示簇类结果
color_mark = ["or","ob","og","ok","oy","ow"]
centroid_mark = ["dr","db","dg","dk","dy","dw"]
for key in clusterDict.keys():
plt.plot(centroidList[key][0], centroidList[key][1], centroidMark[key],markersize=12) # 质心点
for item in clusterDict[key]:
plt.plot(item[0],item[1],colorMark[key])
plt.show()
# 主函数
def main():
dataset = loadDataSet() # 导入数据
centroidList = initCentroids(dataset,4) # 质心列表
clusterDict = minDistance(dataset, centroidList) # 簇类的字典数据
newVar = getVar(centroidList, clusterDict) # 质心和簇类中数据得到新的误差
oldVar = 1 # 当两次聚类的误差小于某个值时,说明质心基本稳定
times = 2
while abs(newVar - oldVar) >= 0.00001: # 当新旧误差的绝对值小于某个很小的值
centroidList = getCentroids(clusterDict) # 得到质心列表
oldVar = newVar # 将新的误差赋值给旧误差
newVar = getVar(centroidList, clusterDict) # 新误差
times += 1
showCluster(centroidList, clusterDict) # 显示聚类结果
if __name__ == "__main__":
show_fig()
main()
传统的K-Means
算法存在一些缺陷,比如K
值的选取不是很好把握、对异常数据敏感等,于是提出了很多在其基础上改进的聚类算法:
1、K-Means++(初始化优化)
针对K-Means算法中随机初始化质心的方法进行了优化
2、elkan K-Means(距离优化)
在传统的K-Means
算法中,在每轮迭代中我们都需要计算所有的样本点到质心的距离,这样是非常耗时的。
elkan K-Means
算法利用:两边之和大于等于第三边,以及两边之差小于第三边的三角形性质,来减少距离的计算。
3、Mini Batch K-Means算法(大样本优化)
在传统的K-Means
算法中,要计算所有的样本点到所有的质心的距离。现在大数据时代,如果样本量非常大,传统的算法将会非常耗时。
Mini Batch K-Means
就是从原始的样本集中随机选择一部分样本做传统的K-Means
。这样可以避免样本量太大的计算难题,同时也加速算法的收敛。当然,此时的代价就是我们最终聚类的精度会降低一些。
为了增加算法的准确性,我们一般会多跑几次Mini Batch K-Means
算法,用得到不同的随机样本集来得到聚类簇,选择其中最优的聚类簇。
1、李航老师—《统计学习方法》一书
2、吴恩达老师—《机器学习》视频
3、刘建平老师—博客:https://www.cnblogs.com/pinard/
一切看似逝去的,都不曾离开,你所给与的爱与温暖,让我执着地守护着这里。
尤而小屋,一个温馨的小屋。小屋主人,一手代码谋求生存,一手掌勺享受生活,欢迎你的光临