single-pass单遍聚类方法
一.通常关于文本聚类也都是针对已有的一堆历史数据进行聚类,比如常用的方法有kmeans,dbscan等。如果有个需求需要针对流式文本进行聚类(即来一条聚一条),那么这些方法都不太适用了,当然也有很多其它针对流式数据进行动态聚类方法,动态聚类也有很多挑战,比如聚类个数是不固定的,聚类的相似阈值也不好设。这些都有待继续研究下去。本文实现一个简单single-pass单遍聚类方法,文本间的相似度是利用余弦距离,文本向量可以用tfidf(这里的idf可以在一个大的文档集里统计得到,然后在新的文本中的词直接利用),也可以用一些如word2vec,bert等中文预训练模型对文本进行向量表示。
二.程序
import numpy as np
import os
import sys
import pickle
import collections
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import TruncatedSVD
from gensim import corpora, models, matutils
from utils.tokenizer import load_stopwords, load_samples, tokenizer, word_segment, load_data, read_data_to_list
from gensim.models import doc2vec, Doc2Vec
from sklearn.metrics.pairwise import cosine_similarity '''
大体流程:
input:doc vector;threshold
output:cluster
begin
input doc vector
input threshold
first doc as first cluster and it's vector as the center of the cluster
while(doc vectors){
while(clusters){
max_sim,max_cluster = simlarity(doc vector,cluster);
}
if(max_sim > threshold){
max_cluster.put(doc vector);
max_cluster.update_center()
}
else{
build new cluster(doc vector);
}
}
end
'''
class SingelPassCluster(object): '''
1.利用tfidf vec计算cossim
'''
def tfidf_vec(self, corpus, pivot=10, slope=0.25):
dictionary = corpora.Dictionary(corpus) # 形成词典映射
self.dict_size = len(dictionary)
print('dictionary size:{}'.format(len(dictionary)))
corpus = [dictionary.doc2bow(text) for text in corpus] # 词的向量表示
tfidf = models.TfidfModel(corpus, pivot=pivot, slope=slope)
corpus_tfidf = tfidf[corpus]
return corpus_tfidf def get_max_similarity(self, cluster_cores, vector):
max_value = 0
max_index = -1
print('vector:{}'.format(vector))
for k, core in cluster_cores.items():
print('core:{}'.format(core))
similarity = matutils.cossim(vector, core)
if similarity > max_value:
max_value = similarity
max_index = k
return max_index, max_value def single_pass(self, corpus_vec, corpus, theta):
clusters = {}
cluster_cores = {}
cluster_text = {}
num_topic = 0
cnt = 0
for vector, text in zip(corpus_vec, corpus):
if num_topic == 0:
clusters.setdefault(num_topic, []).append(vector)
cluster_cores[num_topic] = vector
cluster_text.setdefault(num_topic, []).append(text)
num_topic += 1
else:
max_index, max_value = self.get_max_similarity(cluster_cores, vector)
if max_value > theta:
clusters[max_index].append(vector)
text_matrix = matutils.corpus2dense(clusters[max_index], num_terms=self.dict_size,
num_docs=len(clusters[max_index])).T # 稀疏转稠密
core = np.mean(text_matrix, axis=0) # 更新簇中心
core = matutils.any2sparse(core) # 将稠密向量core转为稀疏向量
cluster_cores[max_index] = core
cluster_text[max_index].append(text)
else: # 创建一个新簇
clusters.setdefault(num_topic, []).append(vector)
cluster_cores[num_topic] = vector
cluster_text.setdefault(num_topic, []).append(text)
num_topic += 1
cnt += 1
if cnt % 100 == 0:
print('processing {}...'.format(cnt))
return clusters, cluster_text def fit_transform(self, corpus, raw_data, theta=0.5):
tfidf_vec = self.tfidf_vec(corpus) # tfidf_vec是稀疏向量
clusters, cluster_text = self.single_pass(tfidf_vec, raw_data, theta)
return clusters, cluster_text '''
2.利用doc2vec计算cossim
'''
def fit(self, doc2vec_model, corpus, raw_data, theta=0.5):
doc_vec = self.doc_vec(doc2vec_model, corpus)
clusters, cluster_text = self.doc2vec_single_pass(doc_vec, raw_data, theta)
return clusters, cluster_text def fit_2(self, doc_vec, text2index, theta):
clusters, cluster_text = self.doc2vec_single_pass(doc_vec, text2index, theta)
return clusters, cluster_text def doc_vec(self, doc2vec_model, x_train):
print('doc2vec infered vec...')
infered_vectors_list = []
for text, label in x_train:
vector = doc2vec_model.infer_vector(text)
infered_vectors_list.append(vector)
print('infered vector size:{}'.format(len(infered_vectors_list)))
if len(infered_vectors_list) >= 100:
break
return infered_vectors_list def get_doc2vec_similarity(self, cluster_cores, vector):
max_value = 0
max_index = -1
for k, core in cluster_cores.items(): # core -> np.ndarray
similarity = cosine_similarity(vector.reshape(1, -1), core.reshape(1, -1))
similarity = similarity[0, 0]
if similarity > max_value:
max_value = similarity
max_index = k
return max_index, max_value def doc2vec_single_pass(self, corpus_vec, corpus, theta):
clusters = {}
cluster_cores = {}
cluster_text = {}
num_topic = 0
cnt = 0
for vector, text in zip(corpus_vec, corpus):
if num_topic == 0:
clusters.setdefault(num_topic, []).append(vector)
cluster_cores[num_topic] = vector
cluster_text.setdefault(num_topic, []).append(text)
num_topic += 1
else:
max_index, max_value = self.get_doc2vec_similarity(cluster_cores, vector)
if max_value > theta:
clusters[max_index].append(vector)
core = np.mean(clusters[max_index], axis=0) # 更新簇中心
cluster_cores[max_index] = core
cluster_text[max_index].append(text)
else: # 创建一个新簇
clusters.setdefault(num_topic, []).append(vector)
cluster_cores[num_topic] = vector
cluster_text.setdefault(num_topic, []).append(text)
num_topic += 1
cnt += 1
if cnt % 100 == 0:
print('processing {}...'.format(cnt))
return clusters, cluster_text def sim(doc_vec):
vector = doc_vec[0]
print('vector:{}'.format(type(vector)))
for core in doc_vec:
similarity = cosine_similarity(vector.reshape(1,-1), core.reshape(1,-1))
similarity = similarity[0, 0]
print("similarity:{}".format(similarity)) if __name__ == '__main__':
base_path = os.path.abspath(os.path.join(os.getcwd(), '../..'))
process_text = base_path + '/data/process_text.txt' # 处理后的样本路径
doc2vec_path = base_path + '/data/doc2vec.pkl'
cluster_result = base_path + '/data/cluster_result.txt'
doc_vec_path = base_path + '/data/doc_vec.vec' # 经过doc2vec推荐的文本向量 corpus = load_data(process_text)
raw_text = load_samples(process_text) index2corpus = collections.OrderedDict()
for index, line in enumerate(raw_text):
index2corpus[index] = line
text2index = list(index2corpus.keys())
print('docs total size:{}'.format(len(text2index))) single_cluster = SingelPassCluster() cal_vec_type = 'doc2vec' if cal_vec_type == 'tfidf':
clusters, cluster_text = single_cluster.fit_transform(corpus, text2index, theta=0.4) if cal_vec_type == 'doc2vec':
with open(doc_vec_path, 'rb') as file:
infered_vectors_list = pickle.load(file)
clusters, cluster_text = single_cluster.fit_2(infered_vectors_list, text2index, theta=0.6) '''
if os.path.exists(doc2vec_path):
print('doc2vec model loading...')
doc2vec_model = Doc2Vec.load(doc2vec_path)
x_train = read_data_to_list(process_text)
clusters, cluster_text = single_cluster.fit(doc2vec_model, x_train, text2index, theta=0.6)
''' if cal_vec_type == 'd2vsim':
if os.path.exists(doc2vec_path):
print('doc2vec model loading...')
doc2vec_model = Doc2Vec.load(doc2vec_path)
x_train = read_data_to_list(process_text)
doc_vec = single_cluster.doc_vec(doc2vec_model, x_train)
sim(doc_vec) print("............................................................................................")
print("得到的类数量有: {} 个 ...".format(len(clusters)))
print("............................................................................................\n")
# 按聚类语句数量对聚类结果进行降序排列
clusterTopic_list = sorted(cluster_text.items(), key=lambda x: len(x[1]), reverse=True)
with open(cluster_result, 'w', encoding='utf-8') as file_write:
for k in clusterTopic_list:
cluster_text = []
for index, value in enumerate(k[1],start=1):
cluster_text.append('(' + str(index) + '): ' + index2corpus[value])
cluster_text = '\n'.join(cluster_text)
file_write.write("【簇索引】:{} \n【簇中文档数】:{} \n【簇中文档】 :\n{}".format(k[0], len(k[1]), cluster_text))
file_write.write('\n')
file_write.flush()
single-pass单遍聚类方法的更多相关文章
- python实现一个层次聚类方法
层次聚类(Hierarchical Clustering) 一.概念 层次聚类不需要指定聚类的数目,首先它是将数据中的每个实例看作一个类,然后将最相似的两个类合并,该过程迭代计算只到剩下一个类为止,类 ...
- Radmin Server-3.5 完美绿色破解版(x32 x64通用) 第三版 + 单文件制作方法
Radmin Server v3.5 汉化破解绿色版(x32 x64通用) 第三版 下载链接: https://pan.baidu.com/s/1qYVcSQo 2016年7月8日更新第三版1.修复在 ...
- springdata 查询思路:基本的单表查询方法(id,sort) ---->较复杂的单表查询(注解方式,原生sql)--->实现继承类---->复杂的多表联合查询 onetomany
springdata 查询思路:基本的单表查询方法(id,sort) ---->较复杂的单表查询(注解方式,原生sql)--->实现继承类---->复杂的多表联合查询 onetoma ...
- html中form表单的使用方法和介绍
from表单的使用方法 一.表单赏析 二.了解表单功能:用于搜集不同类型的用户输入的内容 有了表单,网页的内容可以由用户自己创建,那么对于网页来说,我们既是网页创建都者,也是网页的消费者. 三.常用的 ...
- Learning to rank的讲解,单文档方法(Pointwise),文档对方法(Pairwise),文档列表方法(Listwise)
学习排序(Learning to Rank) LTR(Learning torank)学习排序是一种监督学习(SupervisedLearning)的排序方法.LTR已经被广泛应用到文本挖掘的很多领域 ...
- 学习排序算法(一):单文档方法 Pointwise
学习排序算法(一):单文档方法 Pointwise 1. 基本思想 这样的方法主要是将搜索结果的文档变为特征向量,然后将排序问题转化成了机器学习中的常规的分类问题,并且是个多类分类问题. 2. 方法流 ...
- vue中的表单异步校验方法封装
在vue项目的开发中,表单的验证必不可少,在开发的过程中,用的是vue+iview的一套,我们知道iview的表单验证是基于async-validator,对于async-validator不熟悉的可 ...
- EF中使用Linq时First、FirstOrDefault、Single、SingleOrDefault几个方法的区别
在使用EntityFramework开发时,.NET的System.Linq.Enumerable类为我们提供了许多Linq方法. 给大家分享一下关于First.FirstOrDefault.Sing ...
- 表单提交Post方法、Get方法
表单用来接受用户的输入,并将用户的输入以“name=value值对”集合的形式提交到服务器进行处理.那么表单是怎样将数据提交到服务器的?服务器是怎样对表单数据进行处理的?下面我将为大家揭开表单提交背 ...
随机推荐
- Lua模除运算的大坑
问题 对负数进行模除运算遇到的坑,Lua的%运算与C++的%有差异 实践 结论 Lua%运算的基本公式 a % b = a - ( ( a // b ) * b ) 1.在C,C++中 %运算符的取整 ...
- 数据库设计规范、E-R图、模型图
(1)数据库设计的优劣: 糟糕的数据库设计: ①数据冗余冗余.存储空间浪费. ②数据更新和插入异常. ③程序性能差. 良好的数据库设计 ①节省数据的存储空间. ②能够保证数据的完整新. ③方便进行数据 ...
- Lambda表达式使用方法整理
匿名内部类 Lambda表达式 匿名内部类 ...
- Image 对象事件
以前没怎么注意image上的事件 Image 对象事件 事件 描述 W3C onabort 当用户放弃图像的装载时调用的事件句柄. Yes onerror 在装载图像的过程中发生错误时调用的事件句柄. ...
- mpvue + 微信小程序 picker 实现自定义多级联动 超简洁
微信小程序官网只提供了省市区的三级联动,实际开发中更多的是自定义的多级联动: 依照微信小程序官网提供的自定义多级联动,需要使用到picker 的多列选择器,即设置 mode = multiSelect ...
- requests模块发送数据
通过json dumps发送 import requests import json def agent(): """ 执行命令采集硬件信息 将执行的信息发送给API : ...
- docker-compose deploy replicaSet in standalone MongoDB cluster and with auth
经过两天的折腾,终于实现了自己想要的效果,就是通过docker-compose 部署最新的mongodb replicaSet, 主要是为了测试 4.2 最新的多文档事务,下面将整个步骤分享一下: d ...
- echo打印换行
shell环境中,echo是常用的数据命令,但有的时候,想通过“\n”使输出换行却换不了,这个时候需要增加-e选项: $ echo "Hellow.\nHey man~" Hell ...
- 【Java并发】锁机制
一.重入锁 二.读写锁 三.悲观锁.乐观锁 3.1 悲观锁 3.2 乐观锁 3.3 CAS操作方式 3.4 CAS算法理解 3.5 CAS(乐观锁算法) 3.6 CAS缺点 四.原子类 4.1 概述 ...
- 玩转springcloud(三):服务的提供者与调用者(注册于发现)
一.简介 上文我们实践了cloud的注册中心的单服务于多节点的搭建,房子造好了得有人来住不是,这篇我们实践下服务提供者于调用者的案例,也就是服务端和客户端的调用. 本文会设计三个module:注册中心 ...