机器学习(二):k-means算法(基础篇)
k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。
K-means算法的实现原理
计算距离的方法
每种距离的计算方式都有自己的限制,再具体使用中需要结合样本的特点和场景不同合理选择描述样本之间相似性的算法,在这里我们说一下常见的几种算法。
- 欧式距离
上面公式是一个通用公式,当p=2时即欧式距离,欧氏距离是我们最常用的距离计算方式,也成为几何距离,表示两个点的距离差平方和,简单直观 - 曼哈顿距离
当p=1时表示这个距离,计算的是两个点之间的实地走的距离,欧式距离时两点之间的空间直线距离,不考虑其它影响 - 切比雪夫距离
当p趋于无穷大时,公式如下:
- 向量內积
向量的內积在很多场合都在使用,向量內积是在向量空间里面,公式如下:
內积的结果是一个标量,大小没有限制,上下没有界限因此不好表示两个向量的相关性,于是有人提出来使用余弦来表示相似性,它有大小限制容易表示相似性。
损失函数(目标函数)SSE
误差平方和(SSE):表示样本中的每个样本点到质心的距离的平方和,最优解为:聚类结果应使 SSE 达到最小值。用通俗易懂的话讲:就是每个样本中有一个质心,当样本中的点到质心的距离平方和最小的时候,该质心为我们所求的质心。
算法实现步骤
- List item选择合适 k 值,从数据集可以得出 k=3
- 随机生成 k 个质点作为起始质点
- 将数据集中的每一个点分配到每一个簇,即每一个点找到距离近的质心作为所对应的簇
- 对每一个簇,计算簇中所有点的均值将其作为新的质心
- 重复 cd 两个过程直到分配的所有点不再改变
K-means算法的实践
基本任务
- 理解 k-means 算法的思想。
- 使用 Python 实现 k-means 算法。
- 使用 UCI 上面的 Iris 数据集进行算法测试。
- 对参数 k 进行调整,记录结果。
扩展任务
- 现二分 K-means 代码并进行测试(会在下一节中提到)
数据集
- 网址 http://archive.ics.uci.edu/ml/index.php
- 内容:Iris 数据集
第一步:对数据集进行分析:
1) 数据集介绍:
Iris.data 数据集主要有如下:
sl | 花萼长度 |
---|---|
sw | 花萼宽度 |
pl | 花瓣长度 |
pw | 花瓣宽度 |
variety | 花的品种 |
2)数据特征相关分析:
采用Preson相关系数对四个特征值进行两两之间的相关性分析
3)数据特征画图:
使用python对数据之间两两关系图画出来
代码如下:
# -*- coding:utf-8 -*-
import math
import warnings
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
import matplotlib.patches as mpatchs
warnings.filterwarnings('ignore') #忽略警告
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
def loadDataSet(filename):
"""
函数说明:从文件中下载数据,并将分离除连续型变量和标签变量
:parameter:
data - Iris数据集
attributes - 鸢尾花的属性
type - 鸢尾花的类别
sl-花萼长度 , sw-花萼宽度, pl-花瓣长度, pw-花瓣宽度
:return:
"""
iris_data = pd.read_csv(filename) #打开文件
iris_data = pd.DataFrame(data=np.array(iris_data), columns=['sl', 'sw', 'pl', 'pw', 'type'], index=range(149)) #给数据集添加列名,方便后面的操作
attributes = iris_data[['sl', 'sw', 'pl', 'pw']] #分离出花的属性
iris_data['type'] = iris_data['type'].apply(lambda x: x.split('-')[1]) # 最后类别一列,感觉前面的'Iris-'有点多余即把class这一列的数据按'-'进行切分取切分后的第二个数据
labels = iris_data['type'] #分理出花的类别
return attributes, labels
def showdatas(attributes, datinglabels):
"""
函数说明:画出花的属性两两之间的关系图
:parameter:
attributes - 花的属性
datinglabels - 花的类别
:return:none
"""
fig, axs = plt.subplots(nrows=3, ncols=2, figsize=(20, 8)) #定义一个3行2列的画布
LabelsColors = [] #建立一个颜色标签列表
for i in datinglabels: #遍历花的类型
if i == 'setosa': #setosa类型的花画成黑色的点
LabelsColors.append('black')
if i == 'versicolor': #versicolor类型的花画成橙色的点
LabelsColors.append('orange')
if i == 'virginica': #virginica类型的花画成红色的点
LabelsColors.append('red')
#在画板第一行第一列的位置绘制花萼长度和花萼宽度之间的关系
axs[0][0].scatter(x=attributes['sl'], y=attributes['sw'], color=LabelsColors, s=15, alpha=.5) #x轴为花萼长度,y轴为花萼宽度, 点大小为15, 透明度为0.5
axs0_title_text = axs[0][0].set_title(u'花萼长度和花萼宽度') #设置title
axs0_xlabel_text = axs[0][0].set_xlabel(u'花萼长度') #设置x轴的标签
axs0_ylabel_text = axs[0][0].set_ylabel(u'花萼宽度') #设置y轴的标签
plt.setp(axs0_title_text, size=9, weight='bold', color='red')
plt.setp(axs0_xlabel_text, size=7, weight='bold', color='black')
plt.setp(axs0_ylabel_text, size=7, weight='bold', color='black')
#在画板第一行第二列的位置绘制花萼长度和花瓣长度之间的关系
axs[0][1].scatter(x=attributes['sl'], y=attributes