聚类分析介绍
关键词:没有先验知识、亲密程度、相似性个体、自动分类;
K-Means聚类
K均值聚类是一种动态聚类法,为了改进之前的算法在样品个数很大时内存和时间都消耗极大的缺点;即一种动态聚类法,先粗略分一下类,然后按照某种最优原则进行修正,直到分类比较合理为止;
思想:
先假定样本可分为C类,选定C个初始聚类中心,然后根据最小距离原则将每个样本分配到某一类中,之后不断迭代计算各类的聚类中心,并依据新的聚类中心调整聚类情况,直到迭代收敛 or 聚类中心不再改变;
如何确定簇数 K ?
拐点法:
在不同的 K 值下计算簇内距离差平方和,然后通过可视化的方法找到拐点所对应的 K 值,重点关注斜率的变化,当斜率由大突然变小时,并且之后斜率变化缓慢,则认为突然变化的点就是目标点 K,因为之后随着 K 的增大聚类效果不会有大的变化;
这里随机生成三组二维正态分布数据,然后模拟数据,使用拐点法
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
mean = np.array([[-2, -2], [2, 2], [6, 6]])
cov = np.array([[[0.3, 0], [0, 0.3]], [[0.4, 0], [0, 0.4]], [[0.5, 0], [0, 0.5]]])
x0 = []
y0 = []
for i in range(3):
x, y = np.random.multivariate_normal(mean[i], cov[i], 1000).T
x0 = np.hstack([x0, x])
y0 = np.hstack([y0, y])
plt.rc('font', size=16)
plt.rc('font', family='SimHei')
plt.rc('axes', unicode_minus=False)
plt.subplot(121)
plt.scatter(x0, y0, marker='.') # 画模拟数据散点图
X = np.vstack([x0, y0]).T
np.save("Pzdata11_1.npy", X) # 保存数据供下面使用
TSSE = []
K = 10
for k in range(1, K + 1):
SSE = []
md = KMeans(n_clusters=k)
md.fit(X)
labels = md.labels_
centers = md.cluster_centers_
for label in set(labels):
SSE.append(np.sum((X[labels == label, :] - centers[label, :]) ** 2))
TSSE.append(np.sum(SSE))
plt.subplot(122)
plt.style.use('ggplot')
plt.plot(range(1, K + 1), TSSE, 'b*-')
plt.xlabel('簇的个数')
plt.ylabel('簇内离差平方和之和')
plt.show()
结果如图:
很明显拐点即K=3的时候;
案例:
步骤:
- 判断要不要标准化,像这个案例,量纲在同一级,可以不用标准化;
- 选择 K 值,可以认为判断,也可以用前面说的 拐点法 选择;
# 程序文件Pex11_14.py
import numpy as np;
import pandas as pd
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
a = pd.read_csv("iris.csv")
b = a.iloc[:, :-1]
md = KMeans(3)
md.fit(b) # 构建模型并求解模型
labels = md.labels_
centers = md.cluster_centers_
b['cluster'] = labels # 数据框b添加一个列变量cluster
c = b.cluster.value_counts() # 各类频数统计
plt.rc('font', family='SimHei')
plt.rc('font', size=16)
str1 = ['^r', '.k', '*b']
plt.subplot(121)
for i in range(len(centers)):
plt.plot(b['Petal_Length'][labels == i], b['Petal_Width']
[labels == i], str1[i], markersize=3, label=str(i))
plt.legend()
plt.xlabel("(a)KMeans聚类结果")
plt.subplot(122)
str2 = ['setosa', 'versicolour', 'virginica']
ind = np.hstack([np.zeros(50), np.ones(50), 2 * np.ones(50)])
for i in range(3):
plt.plot(b['Petal_Length'][ind == i], b['Petal_Width'][ind == i],
str1[i], markersize=3, label=str2[i])
plt.legend(loc='lower right')
plt.xlabel("(b)原数据的类别")
plt.show()
可以发现 K-Means 的准确率还是挺高的,就那么十来个点有问题,大概错误率不到10%;