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值对”集合的形式提交到服务器进行处理.那么表单是怎样将数据提交到服务器的?服务器是怎样对表单数据进行处理的?下面我将为大家揭开表单提交背 ...
随机推荐
- 第十二章 ZYNQ-MIZ702 PS读写PL端BRAM
本篇文章目的是使用Block Memory进行PS和PL的数据交互或者数据共享,通过zynq PS端的Master GP0端口向BRAM写数据,然后再通过PS端的Mater GP1把数据读出来,将 ...
- oracle多表关联删除的两种方法
oracle多表关联删除的两种方法 第一种使用exists方法 delete from tableA where exits ( select 1 from tableB Where tableA.i ...
- poj 1753高斯
和前面的开关问题差不多,就是要理解一下我们方程等号的右端代表的含义是什么.我们建立的方程是想让对位的位置变或者不变,然后生成增广矩阵的时候要多注意一点. ac代码: #include #include ...
- 电脑无法上网,DNS出现fec0:0:0:ffff::1%1问题
具体描述:qq,微信可用网,但其他不能用. 一.win+r 输入cmd 打开命令行:ipconfig /all 查看DNS 二.打开文本编辑器,输入如下文本: @Echo onpushd\window ...
- Python 数字(函数)
Python支持4种不同数值类型: 整型(Int) - 通常被称为是整型或整数,是正或负整数,不带小数点. 长整型(long integers) - 无限大小的整数,整数最后是一个大写或小写的L. 浮 ...
- wepy2创建项目
1.首先 在桌面(自己选定目录下)新建一个文件夹,注意需要使用英文名. 2.Cmd中 进入到该文件目录下 3.安装 wepy 命令行工具. npm install wepy-cli -g wepy ...
- 把app(apk和ipa文件)安装包放在服务器上供用户下方法
怎么把app(apk和ipa文件)安装包放在服务器上供用户下载? IIS服务器网站不能下载.apk文件的原因:IIS的默认MIME类型中没有.apk文件,所以无法下载.解决办法:给.apk格式文件添加 ...
- es的相关知识二(检索文档)
一.es的使用 1.检索文档: 想要从Elasticsearch中获取文档,我们使用同样的 _index . _type . _id ,但是HTTP方法改为 GET : GET /{index ...
- JAVA8初探-让方法参数具备行为能力并引入Lambda表达式
关于JAVA8学习的意义先来贴一下某网站上的对它的简单介绍:“Java 8可谓Java语言历史上变化最大的一个版本,其承诺要调整Java编程向着函数式风格迈进,这有助于编写出更为简洁.表达力更强,并且 ...
- mybatis的简单搭建和使用(一)
前言 mybatis是一个持久层的框架,那么问题来了,什么是持久层的框架呢,持久层就是把数据持久化的保存到数据库中,这种过程一般叫数据持久化的过程,现为了程序员能够很方便的操作数据库,于是就出现持久层 ...