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值对”集合的形式提交到服务器进行处理.那么表单是怎样将数据提交到服务器的?服务器是怎样对表单数据进行处理的?下面我将为大家揭开表单提交背 ...
随机推荐
- mysql replace substring 字符串截取处理
SELECT a1,a2,replace(a2, "豫ICP备16006180号-", "") a22,a3,a4,a5 FROM `aaab` order b ...
- java怎么解除文件占用(Dom4j操作完xml后怎么关流)
一.背景 项目中要解析xml,由于Dom4j的诸多优点,我就用Dom4j解析xml,代码如下: public void readXML() { SAXReader reader = new SAXRe ...
- luogu2261余数求和题解--整除分块
题目链接 https://www.luogu.org/problemnew/show/P2261 分析 显然\(k\) \(mod\) \(i=k-\lfloor {k/i}\rfloor\) \(\ ...
- 在Pytorch上使用稀疏矩阵
在Pytorch上使用稀疏矩阵 最近在写一个NLP的小项目,用到了Pytorch做神经网络模型.但是众所周知NLP的一个特点就是特征矩阵是稀疏矩阵,当时处理稀疏矩阵用的是scipy.sparse,现在 ...
- 网络编程之NIO
传统的BIO(Blocking IO)的缺点: 1.基于阻塞式IO建立起来的,导致服务端一直阻塞等待着客户端发起请求,如果客户端不发起,服务端的的业务线程会一直存. 2.弹性伸缩能力差,线程数和客户端 ...
- SpringCloud之RabbitMQ安装
本文介绍Linux以及MAC OS下的RabbitMQ安装及配置: 一.Linux环境下的RabbitMQ安装(CentOS) 1.安装ErLang Erlang(['ə:læŋ])是一种通用的面向并 ...
- Spring OAuth2 Could not decode JSON for additional information: BaseClientDetails
错误消息: 2019-10-08 14:48:16.703 WARN o.s.s.o.p.c.JdbcClientDetailsService : Could not decode JSON for ...
- CDH5.16.1的agent启动报错:ERROR Error, CM server guid updated, expected d9bcadb4-f983-41b8-a667-66760f47bc91, received a67f5efa-8473-4f6a-94d6-231d1f432ef0
1 详细错误 0/Oct/2019 14:56:13 +0000] 28577 MainThread agent ERROR Error, CM server guid updated, expect ...
- cnblogs排版样式预览
说明:关于本博主题及样式来源于[GitHub]:本博总体排版目录样式风格参照博文[修仙成神之路]进行预览:参照本博设置可参考博文[设置跟本博一样的效果]本博之前发表过的博文存在样式不协调,后期会逐一完 ...
- 九:MVC主从表数据加载
EF对关联表数据加载的三种方式: 延迟加载:只有在需要的时候加载数据.EF默认的加载方式. 贪婪加载:一次性组织好数据,全部加载到内存中. 显式加载:需要通过代码手动加载关联表. 延迟加载 virtu ...