聚类算法
聚类算法和分类算法一样,都是将样本类别划分,区别在于:
- 分类算法是有监督的算法。去寻找x的特征和y的映射关系,在根据这个关系去做x的划分。
- 聚类算法是无监督的算法。也就是说没有标签y,只有特征属性x。模型是通过找x特征的关系将x划分
常用的聚类算法就是Kmeans、GMM高斯混合聚类。作为前期的数据处理过程中的一种数据标注的方式
聚类就是对于大量未标注的数据集,按照数据内部存在的数据特征将数据划分为多个类别,使得类别内的数据比较相似,类别间的数据相似度比较低。
这里相似度就是样本之间的距离
相似度的计算
距离
这三个距离的应用场景都是比较明确的。
夹角余弦相似度
杰卡尔德相似度
A交B除以A并B,结果越大(比例越大),整明A和B越相似。这个应用的是两个样本都这个特征就认为是相似的,不会去比较这个特征的值。比如你评论了我也评论了认为我们在这个特征上是相似的,适合于稀疏矩阵,比如文本特征,两个文章相同的关键词越多越相似
Pearson相关系数
协方差除以标准差的乘积。
聚类的思想
给定一个m个样本的数据集,构建一个具有k个簇的模型,K<=m,将样本分到这k个簇中。也就是说每个簇中至少有一个样本,一个样本也只能在一个簇中。
- 首先选择k个类别中心,随机初始化。a1,a2…ak
- 判断每一个样本距离哪一个初始化的点更近。这里用欧氏距离来度量。认为最近的点就是他所属的类别
- 更新a1,a2…ak。更新为每个中心点包含样本的均值
- 重复上面操作,直至停止迭代条件。
停止迭代的条件
迭代次数,样本到中心点的距离平方和,簇中心变化率
损失函数
当每个中心点所拥有的样本到它的距离最小的时候,是最优的时候。所有我们可以求解这个损失函数。我们只计算第k个中心点的样本
Kmeans的思考
- 异常点敏感。使用的是均值来更新中心点。这样异常点很有可能影响中心值得位置。这时候我们可以使用k中值聚类。使用得不是一个簇得中心点是中位数、
- 初值敏感。刚开始给定的值是比较敏感,不同的初始值会有不同得划分。我们可以多次初始值构建,然后选择一个最优得划分。
Kmeans的问题
- K值是我们给的。但是我在做处理的时候这个k值是未知的。所以不同的k值有不同的划分。我们只能根据自己的经验给定。
- 不适合非凸形状(比如环状,条状,月牙状)的簇或者差别过大的簇比
Kmeans代码
make_blobs:产生一个团状的数据。
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
# 1. 产生模拟数据
N = 1000 #样本的个数
n_centers = 4 #中心点的个数
X, Y = make_blobs(n_samples=N, n_features=2, centers=n_centers, random_state=14)
# n_features=2数据有两个属性
from sklearn.metrics.pairwise import pairwise_distances_argmin
# 数据的可视化一下
plt.scatter(X[:, 0], X[:, 1], c=Y, s=30)
plt.show()
# 2. 模型构建
model = KMeans(n_clusters=4)
model.fit(X, Y)
# 3. 输出模型得到的中心点和目标函数的损失值
print("中心点坐标:")
print(model.cluster_centers_)
print("目标函数的损失值(所有样本到对应簇中心点的距离平方和):")
print(model.inertia_)
print(model.inertia_ / N)
# 4. 预测
print(X[:2])
y_hat = model.predict(X[:10])
print("预测值:{}".format(y_hat))
print("实际值:{}".format(Y[:10]))
print("模型的Score评估值:{}".format(model.score(X, Y)))
# 1. 产生模拟数据
N = 3000
n_centers = 4
x, y = make_blobs(n_samples=N, n_features=2, centers=[(-5, 5), (-5, -5), (5, -5), (5, 5)],center_box=[-100,100])
# print(y)
# 可视化
plt.scatter(x[:, 0], x[:,1],c=y,s=30)
plt.show()
# 模型构建
algo = KMeans(n_clusters=4)
"""
n_clusters=8, 给定划分成为几个类别 也就是k值
init='k-means++', 初始化k值的方式 还有一种是random 就是随机初始化 簇中心
n_init=10,
max_iter=300, 最大的迭代次数
tol=1e-4, 迭代之间的损失函数的阈值
precompute_distances='auto', 是否在预先计算样本的距离
"""
# 模型训练
algo.fit(x)
# 预测模型数据
x_test = [
[4,6],
[-4,7],
[-1,-1],
[6,-3]
]
# print("预测值为:{}".format(algo.predict(x_test)))
print("簇中心的坐标点:{}".format(algo.cluster_centers_))
print("簇中心的坐标点的对应的标签:{}".format(algo.predict(algo.cluster_centers_)))
print("目标函数值:{}".format(algo.inertia_))
print("训练集中每个样本所属的标签:{}".format(algo.labels_))
二分K-Means算法
解决KMeans初始值敏感的问题,它是一种弱化初始质心的算法。只是弱化没有解决。
- 那所有的样本作为一个簇放到队列中。
- 从队列中选择一个簇来进行KMeans划分,划分为两个子簇,再放回队列中(放回的是划分后的两个子簇,划分前的不存在了)
- 循环第二步,直到满足停止条件。条件看前面
- 队列中的簇就是最终的分类
- 只有当初始化的点再对角线的顶点附近才会划分失,如果有点偏依然可以划分好。就是依然有可能划分不开,所以只是缓解了。
这里划分簇的时候,会计算所有簇的误差和,选择误差和大的划分,也就是分隔的更开的。
K-Means++算法
K-Means++算法也是为了解决初始值敏感的问题。在K-Means中初始值是随机初始化的,我们来看看K-Means++的方法
在K-Means出现初始值敏感的原因就是初始值随机到一个簇中,离得比较近,久划分不开。
线性概率选择下一个点的我们会计算距离当前点较远的点,从n个较远的点中随机选一个,避免异常点的干扰。
由于第二个点依赖第一个点,第三个以来第二个这样可能性能会有影响。我们一般解决初始值异常就是用K-means++以及初始多套随机值选择效果好的
Min Batch K-Means
Min Batch K-Means是K-means的一种优化变种。用小规模数据集做中心质点的变化,减少了计算量。每次中心质点做了变化都会重新抽一次
,