一、聚类算法
1. 聚类问题
给定一个元素集合 D,其中每个元素具有 n 个可观察属性,使用某 种算法将 D 划分成 k 个子集,要求每个子集内部的元素之间相异度尽可能低,而不同子集的 元素相异度尽可能高。其中每个子集叫做一个簇。
2. 聚类和分类的区分
- 聚类:而聚类是观察式学习,在聚类前可以 不知道类别甚至不给定类别数量,是无监督学习的一种
- 分类:分类是示例式学习,要求分类前明确各个类别,并断言每个元素映射到一个类别
二、K-means介绍
K-means是K均值算法,需要提前指定K值,K值决定了数据集被分成多少个子集。
无监督算法中存在一种算法叫聚类算法,聚类算法中最经典的是K-means算法。
三、K-means原理
1、从 D 中随机取 k 个元素,作为 k 个簇的各自的中心(质心)。
2、分别计算剩下的元素到 k 个簇中心的相异度,将这些元素分别划归到相异度最低的簇。
3、根据聚类结果,重新计算 k 个簇各自的中心,计算方法是取簇中所有元素各自维度 的算术平均数。
4、将 D 中全部元素按照新的中心重新聚类。
5、重复第 4 步,直到聚类结果不再变化。
6、将结果输出。
n: 元素个数,k:第一步中选取的元素个数,m: 每个元素的特征项个数,T: 第 5 步中 迭代的次数
K-means聚类原理
四、K-means特点
- 需要指定K值:预先指定的参数,称为超参数
- 受初始值(初始聚类中心)的影响,达到局部最优效果
- 受离群点(异常值)的影响。通常处理方式是剔除异常值
- 距离表征相似度,特征量级不同,需要进行数据标准化
注意:K-means算法之前,通常要进行数据预处理:数据异常值剔除、数据标准化
五、K-means简单代码示例
"""
步骤:
1. 第一次分类得到分组结果
2. 修改第一次的代码:得到最终分组结果
3. 代码优化:停止替换聚类中心的条件(有时候结果很接近但是达不到准确的相等结果所以增加了运算的次数)
4. 可视化,查看聚类的结果
5. 数据标准化,可视化,查看每次聚类时聚类中心的变化
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = "SimHei"
# 本身可以支持负号,设置支持中文之后,负号无法正常显示,设置如下代码使其支持负号
plt.rcParams['axes.unicode_minus'] = False
def build_data():
company = pd.read_csv('../data_ML/company.csv', encoding='ANSI')
# 取有价值的特征
data = company[['平均每次消费金额', '平均消费周期(天)']]
return data
def stand_scalar(val):
"""标准差标准化"""
mean_val = val.mean()
std_val = val.std()
return (val - mean_val) / std_val
# def min_max_scalar(val):
# """离差标准化"""
# return (val - val.min()) / (val.max() - val.min())
def main(center):
"""
以旧的聚类中心为参数
输出新的聚类中心
"""
# 新建一个空列表,用来存放每条记录的类别
label = []
# 计算每条记录到K的距离,选出最小值,得到索引
for sample in data[['平均每次消费金额', '平均消费周期(天)']].values:
# 每个样本到K点的欧氏距离的平方
dis = ((sample - center) ** 2).sum(axis=1)
# 得到最小的举例的索引,索引表示分类
ind = np.argmin(dis)
label.append(ind)
# 将分类添加data中
data['label'] = label
# 新的聚类中心
new_center = data.groupby('label').mean()
return new_center
def matp(center):
"""
数据可视化
:param data:
:return:
"""
# 画布清理
plt.cla()
for cls in range(3):
part_data = data.loc[data['label'] == cls, :]
plt.scatter(part_data['平均每次消费金额'], part_data['平均消费周期(天)'])
# 聚类中心可视化
print(center)
plt.scatter(
center[:, 0],
center[:, 1],
marker='*',
s=200,
c=['b', 'r', 'g'])
plt.legend(["类0", "类1", "类2"])
plt.xlabel('平均每次消费金额')
plt.ylabel('平均每次消费金额')
# 等待一秒
plt.pause(1)
if __name__ == '__main__':
# 打开开关
plt.ion()
# 取初始K值-聚类的中心
data = build_data()
center = np.array([[13, 1],
[100, 4],
[78, 9]])
# 添加一条全零的label列表
label = [0] * data.shape[0]
times = 0
data['label'] = 0
while True:
# 可视化
matp(center)
new_center = main(center)
times += 1
print('第%d次' % times)
new_label = data['label']
# if np.all(new_center.values == center) or np.all(new_label == label):
if np.all(new_center.values == center):
break
# 替换聚类中心
center = new_center.values
label = new_label
print('新的聚类中心', new_center)
print('最终分组结果', data)
# 关闭开关
plt.ioff()
# 展示
plt.show()
小拓展-动态可视化matplotlib
- 打开开关:
plt.ion()
- 打开开关:
- 画布清理:
plt.cla()
- 画布清理:
- 画图:
- 关闭开关:
plt.ioff()
- 关闭开关:
- 展示:
plt.show()
- 展示:
六、sklearn的K-means算法应用
导包:
# 导包:kmeans
from sklearn.cluster import KMeans
# 预处理
from sklearn.preprocessing import StandardScaler # 标准差标准化
from sklearn.preprocessing import MinMaxScaler # 离差标准化
from sklearn.preprocessing import MaxAbsScaler # 小数定标标准化
函数:km = KMeans()
参数:
- n_clusters:K值的设置(聚类中心的数量)
- init:聚类中心初始化的方式,默认值k-means++
- max_iter:最大迭代次数
- random_state:相当于数组里面的随机种子,随机生成后的值不再变化
方法:
最终的聚类中心:km.cluster_centers_
聚类中心初始化——k-means++:
- 随机选取一个点作为聚类中心1
- 选择与该点最远的一个点作为聚类中心2
- 选择距离前两个
聚类中心和
最远的点作为聚类中心3
简单代码示例:
import pandas as pd
import matplotlib.pyplot as plt
# 导包:kmeans
from sklearn.cluster import KMeans
# 预处理
from sklearn.preprocessing import StandardScaler # 标准差标准化
from sklearn.preprocessing import MinMaxScaler # 离差标准化
from sklearn.preprocessing import MaxAbsScaler # 小数定标标准化
# 默认不支持中文,可以设置rc参数,使其显示中文
plt.rcParams["font.sans-serif"] = "SimHei"
# 本身可以支持负号,设置支持中文之后,负号无法正常显示,设置如下代码使其支持负号
plt.rcParams['axes.unicode_minus'] = False
def build_data():
company = pd.read_csv('../data_ML/company.csv', encoding='ANSI')
# 取有价值的特征
data = company[['平均每次消费金额', '平均消费周期(天)']]
return data
def k_means(data):
"""
K均值处理
:return: 返回最终的聚类中心
"""
# 1. 实例化算法
# n_clusters:K值的设置
# random_state:相当于数组里面的随机种子,随机生成后的值不再变化
km = KMeans(n_clusters=3, random_state=1)
# 2.拟合:无监督算法没有标签,参数为数据的特征
km.fit(data)
# 3.预测
y_pred = km.predict(data)
data['类别'] = y_pred
print(data)
print('预测结果:', y_pred)
# 最终的聚类中心
print(km.cluster_centers_)
return km.cluster_centers_
def show_result(data, center):
for cls in range(3):
part_data = data.loc[data["类别"] == cls, :]
plt.scatter(part_data["平均每次消费金额"], part_data["平均消费周期(天)"])
# print(part_data)
# 聚类中心可视化
plt.scatter(center[:, 0], center[:, 1],
marker='*', s=200, c=['b', 'r', 'g'],
alpha=0.2)
plt.legend(["类0", "类1", "类2"])
plt.xlabel("平均每次消费金额")
plt.ylabel("平均消费周期(天)")
plt.show()
def main():
"""
主函数:主要写实现的逻辑
:return:
"""
# 获取数据
data = build_data()
# 数据标准化
std = StandardScaler()
data_std = std.fit_transform(data)
print('转换后:\n', data_std) # sklearn 返回值通常为数组
data["平均每次消费金额"] = data_std[:, 0]
data["平均消费周期(天)"] = data_std[:, 1]
# kmeans处理
new_center = k_means(data)
# 可视化
show_result(data, new_center)
if __name__ == '__main__':
main()
七、轮廓系数
1. 轮廓系数的目的:对聚类中心的效果进行评估
2. 原理
轮廓系数原理
3. 轮廓系数结论
i为已聚类数据中的样本
bi为i到其他类中所有点的距离平均值,越大越好(说明类与类之间距离较远)
ai为i到其内部类中所有点的距离的平均值,越小越好(说明类内连接紧密)
轮廓系数的范围是[-1, 1],值越大,效果越好。
4.sklearn应用
# 导入
from sklearn.metrics import silhouette_score
# 计算轮廓系数
# 参数1:参与聚类的所有数据的样本
# 参数2:经过K-means算法预测的预测结果
score = silhouette_score(data, y_pred)