语料库是上万个topic的视频标题,主题比如重庆、春节这种,每个topic下有几千到上万个视频标题。这些topic不是正交的,现在要把它们聚成几类,做法如下:
1. 将每个topic下的视频标题分词,计算TF*IDF并降序排列,取top n的特征词+tfidf值作为该topic的向量. 详细步骤和脚本在另一篇博文里:
http://blog.chinaunix.net/uid-15588024-id-4107927.html
2. 采用cosine距离和层次聚类法:初始时每个topic单独一类,然后递归把两个夹角最近的topic合并,最后所有的topic合为一类。聚类的结果就是一棵树,想聚成几类只需到对应深度的层去取结果就好了
在聚类前需要将每个topic向量做正则化, 这是为了防止视频过多的topic轻易与其它topic相似。这里采用二阶正则:除以向量的模
NLTK中有相应的层次聚类算法
GAAClusterer, 参数为元素是Numpy.array的list,代表整个文本向量空间。主要python代码如下:
-
import sys,os
-
-
import numpy, math
-
from nltk.cluster import KMeansClusterer, GAAClusterer, euclidean_distance
-
import nltk.corpus
-
from nltk import decorators
-
import nltk.stem
-
import codecs
-
-
#从corpus_res2中读取,先生成set;每个文件进行2阶normalization;结合numpy和nltk.cluster来做
-
输入是文件夹:每个文件是一个topic, 文件内容是降序排好的特征词:tf*idf值,如:
-
#演讲 0.375399
#励志 0.337192
#马云 0.242213
-
def get_words(corpus_dir):
-
words=set()
-
for f in os.listdir(corpus_dir):
-
#只保留30个,单机内存不足
-
fr=codecs.open(corpus_dir+f, 'r', encoding='utf-8')
-
cnt=0
-
for line in fr:
-
if cnt>=20:
-
break
-
word=line.split('\t')[0].strip()
-
#如果特征词是一个中文字符,直接舍弃
-
if len(word)<2:
-
continue
-
#是否去掉停用词?
-
words.add(word)
-
cnt+=1
-
print 'total words:', len(words)
-
return list(words)
-
-
#求topic的特征词向量
-
def vectorspaced(title):
-
#求出模长
-
mod=0
-
tw_dict={}
-
cnt=0
-
for line in title.readlines():
-
if cnt>=20:
-
break
-
items=line.split('\t')
-
token=items[0].strip()
-
#一个中文字符,舍弃
-
if len(token)<2:
-
continue
-
w=float(items[1].strip())
-
tw_dict[token]=w
-
mod=mod+w**2
-
cnt+=1
-
-
mod=math.sqrt(mod)
-
w_vec=[]
-
for word in words:
-
if not word in tw_dict:
-
w_vec.append(0)
-
else:
-
w_vec.append(tw_dict[word]/mod)
-
-
return numpy.array(w_vec, numpy.float)
-
-
-
if __name__ == '__main__':
-
corpus_dir='D:/python_workspace/corpus_res2/sigram/'
-
#corpus_dir='D:/python_workspace/corpus_test/'
-
words=get_words(corpus_dir)
-
vec_space=[]
-
indf_dict={}
-
index=0
-
#写对应关系
-
fw1=open('D:/python_workspace/corpus_res2/index_file.txt', 'w')
-
#写结果
-
fw2=open('D:/python_workspace/corpus_res2/cluser_res.txt', 'w')
-
for f in os.listdir(corpus_dir):
-
index+=1
-
print 'already handle file:', index
-
indf_dict[index]=f
-
with codecs.open(corpus_dir+f, 'r', encoding='utf-8') as title:
-
vec_space.append(vectorspaced(title))
-
-
#如何根据hisgram判断分类数目?
-
cluster = GAAClusterer(40)
-
clustered=cluster.cluster(vec_space, True)
-
#cluster.dendrogram().show()
-
for k, v in indf_dict.items():
-
fw1.write('%s\t%s\n' % (str(k), str(v)))
-
fw1.close()
-
-
fw2.write('%s\n' % ','.join([str(v) for v in clustered]))
-
fw2.close()
阅读(1870) | 评论(0) | 转发(0) |