基于bert语义聚类的案例demo
1、获取embedding向量
#macber链接https://github.com/ymcui/MacBERT
from sklearn.manifold import TSNE
from matplotlib import pyplot as plt
from matplotlib.colors import ListedColormap
import pandas as pd
import numpy as np
dt=pd.read_csv('./test.csv',encoding='gb18030')
#采用macbert语义向量
from bert_serving.client import BertClient
bc = BertClient(ip="localhost",port=5555, port_out=5556)
emb=list(bc.encode(list(dt['相似问'])))
tsne = TSNE(n_components=2,init='pca', metric='cosine', random_state= 0)
tsne_bert = tsne.fit_transform(np.array(emb))
plt.scatter(tsne_bert[:,0],tsne_bert[:,1],c=dt['相似问ID'],marker="*", s=20,alpha=0.8,cmap='tab20')
二、聚类demo
1、kmeans,kmeas缺点主要有以下几点
a、需提前设定类别数
b、受异常点影响较为严重
c、高维情况下迭代过慢
d、受初始点影响较大
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=5)
kmeans.fit(tsne_bert)
labels = kmeans.labels_
2、DBSCAN密度聚类
a、受领域半径影响较大,对于不同类别件间距不一的样本无法统一度量
b、因密度直达与密度不可达的不对称性,容易出现大量噪音点
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=0.05,
metric='cosine',
#algorithm='ball_tree', #algorithm{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}
min_samples=3).fit(emb)
labels = list(dbscan.labels_)
3、optics聚类
from sklearn.cluster import OPTICS
clustering = OPTICS(min_samples=5, xi=0.03,metric='cosine')
clustering.fit(emb)
labels = clustering.labels_
reachability_distances = clustering.reachability_
print("Labels:", labels)
print("Reachability Distances:", reachability_distances)
4、层次聚类
缺点:需人工设定类别数,对于数据量大的样本需不断调试
from scipy.cluster.hierarchy import linkage, fcluster
from scipy.spatial.distance import pdist
# 示例用法
X = emb
distances = pdist(X, metric='cosine')
linkage_matrix = linkage(distances, method='ward')
labels = fcluster(linkage_matrix, t=8, criterion='maxclust')
print("Labels:", labels)
plt.scatter(tsne_bert[:,0],tsne_bert[:,1],c=labels,marker="*", s=20,alpha=0.8,cmap=cmap)
5、louvain图聚类
缺点:社群内容易出现大量噪音点,对噪音点鲁棒较差
import networkx as nx
from community.community_louvain import best_partition
# 生成随机样本数据
X = np.array(emb)
# 计算点积相似度矩阵
dot_product_matrix = np.dot(X, X.T)
# 创建带权重的图
G = nx.Graph()
for i in range(len(dot_product_matrix)):
for j in range(i+1, len(dot_product_matrix)):
G.add_edge(i, j, weight=dot_product_matrix[i, j])
# 使用Louvain算法检测带权重图的社区
partition = best_partition(G, weight='weight')
labels=list(partition.values())
6、谱聚类
from sklearn.metrics import pairwise
from sklearn.cluster import SpectralClustering
cos_mat=pairwise.cosine_similarity(emb)
labels = SpectralClustering(
affinity='precomputed',
n_neighbors=5,
assign_labels='discretize').fit_predict(cos_mat)
labels=list(labels)
三、效果评估
from sklearn import metrics
sc=metrics.silhouette_score(emb, labels, metric='cosine')
print ("sc:"+str(sc))
sse=metrics.calinski_harabasz_score(emb, labels)
print ("sse:"+str(sse))
-
metrics.calinski_harabasz_score
(也称为CH指数)是一个内部评估指标,用于衡量聚类结果的紧密度和分离度。它基于聚类间的差异与聚类内的差异之比来计算分数。较高的CH指数表示簇之间的差异大且簇内的差异小,即较好的聚类结果。 -
metrics.silhouette_score
是另一个内部评估指标,用于衡量聚类结果的紧密度和分离度。它基于样本与其所属簇以及最接近的其他簇之间的距离来计算分数。较高的轮廓系数表示样本在其所属簇内更紧密,并与最接近的其他簇之间更分离。
区别:虽然两个评估指标都用于评估聚类算法的性能,但CH指数更侧重于簇内和簇间的差异比较,而轮廓系数更侧重于样本与簇内和最接近的其他簇之间的距离比较
- 计算方式:CH指数通过计算聚类间的差异与聚类内的差异之比得出分数,而轮廓系数通过计算样本与其所属簇以及最接近的其他簇之间的距离得出分数。
- 解释性:CH指数的值越高表示聚类效果越好,而轮廓系数在-1到1之间,值越接近于1表示聚类效果越好,接近于-1表示聚类效果较差。
- 评估侧重点:CH指数同时关注聚类内的紧密度和聚类间的分离度,而轮廓系数主要关注样本与簇内和最接近的其他簇之间的距离。
可视化:
colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'pink', 'brown', 'gray', 'cyan',
'lightgreen', 'lightblue', 'darkred', 'darkblue', 'darkgreen', 'violet', 'salmon', 'gold',
'teal', 'magenta', 'olive', 'indigo', 'khaki', 'navy', 'tomato', 'lime', 'skyblue',
'orchid', 'coral', 'sienna', 'steelblue', 'peru', 'slateblue', 'tan', 'crimson', 'chartreuse',
'turquoise', 'fuchsia', 'mediumseagreen', 'mediumaquamarine', 'dodgerblue', 'darkorange',
'mediumvioletred', 'mediumspringgreen', 'limegreen', 'deepskyblue', 'darkviolet', 'darkkhaki']
# 自定义颜色列表
num_colors = len(colors)
# 创建自定义颜色映射
cmap = ListedColormap(colors, name='custom_cmap', N=num_colors)
plt.scatter(tsne_bert[:,0][labels != -1],tsne_bert[:,1][labels != -1],c=labels[labels != -1],marker="*", s=20,alpha=0.8,cmap=cmap)