为了提高阅读体验,请移步到:Query 聚类
背景
搜索系统优化长尾 query。想了解一下长尾 query 长什么样?大体上都有几类?最好能归类,一类一类处理。
Query 数据源:包含“什么”,“怎么”,“如何” 关键词的 Query。
![](https://i-blog.csdnimg.cn/blog_migrate/69861ba982dd552007122ef5dbce47d0.jpeg)
K-means
聚类概念
生活中的聚类例子:班级分组。
一个班级有 40 名学生,班主任分别让小明,小红,小强,小李将班级中学生分成两组。
小明:男生一组,女生一组。
小红:前三排一组,后三排一组。
小强:左三列一组,又三列一组。
小李:住校生一组,走读生一组。
为什么造成大家的分组不一样?是因为老师没有给明确定分组规则。
聚类是无监督学习。
无监督学习不需要标注数据。
有监督学习需要标注数据。NB,LR。
聚类:将数据划分到不同的类里,使相似(距离相近)的数据在同一类里,不相似(距离较远)的数据在不同的类里。
![](https://i-blog.csdnimg.cn/blog_migrate/5630fc292ec860ce164561aed4201121.jpeg)
Demo
生成模拟数据
from sklearn.datasets import make_blobsimport matplotlib.pyplot as plt# 生成:样本数500,特征数为2,4 个中心的样本集X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)plt.scatter(X[:, 0], X[:, 1], marker='o', s=8)plt.show()
X = [[-6.92324165e+00 -1.06695320e+01][-8.63062033e+00 -7.13940564e+00][-9.63048069e+00 -2.72044935e+00][-2.30647659e+00 5.30797676e+00]]
模拟的数据的分布:
![](https://i-blog.csdnimg.cn/blog_migrate/f15460d318f2ca5c6507fb25e7289e14.jpeg)
聚类及可视化代码(使用 sklearn 库中的 KMeans):
from sklearn.datasets import make_blobsimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeans# 生成:样本数500,特征数为2,4 个中心的样本集X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)# 聚类n_clusters = 4cluster = KMeans(n_clusters=n_clusters, random_state=0).fit(X)# 可视化 -- 样本color = ["red", "pink", "orange", "gray"]y_pred = cluster.labels_for i in range(n_clusters): plt.scatter(X[y_pred == i, 0], X[y_pred == i, 1], marker='o', s=8, c=color[i])# 可视化 -- 质心centroid = cluster.cluster_centers_plt.scatter(centroid[:,0], centroid[:,1], marker='x', s=15, c="black")plt.show()
聚类的结果:不同颜色表示不同类型
![](https://i-blog.csdnimg.cn/blog_migrate/62dba350a75065fb02b76e74e2bcdf30.jpeg)
欧式距离
点 X 到点 Y 的距离。
如图:点 与点 之间的距离为:
![](https://i-blog.csdnimg.cn/blog_migrate/a1a289b1f1a7e10f5bf31dd46af021ba.jpeg)
K-Means 算法
算法描述
从数据集中随机选取 K 个样本,作为初始质心。
重新对样本划分类别:计算每个样本 ,计算它到每一个质心的距离,将其分配到距离最小质心所对应的类中。
重新计算每个质心。
当满足一定条件,如类别划分不在变化时或者达到最大迭代轮数,则终止算法,否则继续步骤 2 和 3。
![](https://i-blog.csdnimg.cn/blog_migrate/5b11b9f69e5403e3f89c6617a7c6c2b2.jpeg)
例如:绿色类中点:
跟新绿色质心:
注意:此时的质心是虚拟的点(不是训练集中的样本,后续优化点)
![](https://i-blog.csdnimg.cn/blog_migrate/7e20141d7bfeb2b32dcc5301dc36b5ad.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/b0e1a6cfa2814257c69e87cc2fedf3c3.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/9fa73cff828f822be6e2377255f01474.jpeg)
关键点:
计算样本数据与中心点的距离
欧式距离:
计算聚类的中心点(更新质心)
均值。
算法终止条件:最小化 WCSS
Kmeans 聚类代码(自己实现方便后根据业务需求优化聚类过程):
import mathfrom random import sampleclass Kmeans: def __init__(self): self.centorids = [] self.labels = [] # 训练 def train(self, train_data, n_clusters=10, max_iter=300): last_wcss = 0.0 iter_count = 0 centorids = [train_data[i] for i in sample(range(len(train_data)), n_clusters)] print("kmeans train start:", centorids) while True: labels = [[] for _ in range(n_clusters)] wcss = 0 # 聚类 for x_id in range(len(train_data)): min_distance = math.inf for cluster_id in range(n_clusters): distance = self.calc_distance(train_data[x_id], centorids[cluster_id]) if min_distance > distance: min_distance = distance cluster = cluster_id labels[cluster].append(x_id) wcss += min_distance print("kmeans wcss:", wcss, iter_count) # modify centers for cluster_id in range(n_clusters): centorids[cluster_id] = self.calc_centroid(train_data, labels[cluster_id]) iter_count += 1 if last_wcss == wcss or iter_count == max_iter: break last_wcss = wcss self.centorids = centorids tmp = sorted([(x_id, cluster_id) for cluster_id in range(len(labels)) for x_id in labels[cluster_id]]) self.labels = [cluster_id for x_id, cluster_id in tmp] print("kmeans train Over") # 计算质心 def calc_centroid(self, train_data, cluster_data): x_dimension = len(train_data[0]) centroid = [0.0] * x_dimension for x_id in cluster_data: for i in range(x_dimension): centroid[i] += train_data[x_id][i] return [item / len(cluster_data) for item in centroid] # 计算距离 def calc_distance(self, x, y): return math.sqrt(sum([math.pow(i - j, 2) for i, j in zip(x, y)])) # 测试from sklearn.datasets import make_blobsimport matplotlib.pyplot as pltimport numpy as np# 生成:样本数500,特征数为2,4 个中心的样本集X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)# 聚类kmeans = Kmeans()kmeans.train(X, k=4)# 可视化color = ["red", "pink", "orange", "gray"]# 可视化 -- 样本y_pred = np.array(kmeans.labels)for i in range(n_clusters): plt.scatter(X[y_pred == i, 0], X[y_pred == i, 1], marker='o', s=8, c=color[i])# 可视化 -- 质心centroid = np.array(kmeans.centorids)plt.scatter(centroid[:, 0], centroid[:, 1], marker='x', s=15, c="black")plt.show()
聚类的结果:不同颜色表示不同类型