Chinaunix首页 | 论坛 | 博客
  • 博客访问: 54188
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 152
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-06 21:55
文章分类

全部博文(14)

文章存档

2015年(2)

2014年(12)

我的朋友

分类: Python/Ruby

2014-02-16 14:27:45

语料库是上万个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代码如下:
 

点击(此处)折叠或打开

  1. import sys,os

  2. import numpy, math
  3. from nltk.cluster import KMeansClusterer, GAAClusterer, euclidean_distance
  4. import nltk.corpus
  5. from nltk import decorators
  6. import nltk.stem
  7. import codecs

  8. #从corpus_res2中读取,先生成set;每个文件进行2阶normalization;结合numpy和nltk.cluster来做
  9. 输入是文件夹:每个文件是一个topic, 文件内容是降序排好的特征词:tf*idf值,如:
  10. #演讲 0.375399
    #励志 0.337192
    #马云 0.242213
  11. def get_words(corpus_dir):
  12.     words=set()
  13.     for f in os.listdir(corpus_dir):
  14.         #只保留30个,单机内存不足
  15.         fr=codecs.open(corpus_dir+f, 'r', encoding='utf-8')
  16.         cnt=0
  17.         for line in fr:
  18.             if cnt>=20:
  19.                 break
  20.             word=line.split('\t')[0].strip()
  21.             #如果特征词是一个中文字符,直接舍弃
  22.             if len(word)<2:
  23.                 continue
  24.             #是否去掉停用词?
  25.             words.add(word)
  26.             cnt+=1
  27.     print 'total words:', len(words)
  28.     return list(words)

  29. #求topic的特征词向量
  30. def vectorspaced(title):
  31.     #求出模长
  32.     mod=0
  33.     tw_dict={}
  34.     cnt=0
  35.     for line in title.readlines():
  36.         if cnt>=20:
  37.             break
  38.         items=line.split('\t')
  39.         token=items[0].strip()
  40.         #一个中文字符,舍弃
  41.         if len(token)<2:
  42.             continue
  43.         w=float(items[1].strip())
  44.         tw_dict[token]=w
  45.         mod=mod+w**2
  46.         cnt+=1
  47.     
  48.     mod=math.sqrt(mod)
  49.     w_vec=[]
  50.     for word in words:
  51.         if not word in tw_dict:
  52.             w_vec.append(0)
  53.         else:
  54.             w_vec.append(tw_dict[word]/mod)

  55.     return numpy.array(w_vec, numpy.float)


  56. if __name__ == '__main__':
  57.     corpus_dir='D:/python_workspace/corpus_res2/sigram/'
  58.     #corpus_dir='D:/python_workspace/corpus_test/'
  59.     words=get_words(corpus_dir)
  60.     vec_space=[]
  61.     indf_dict={}
  62.     index=0
  63.     #写对应关系
  64.     fw1=open('D:/python_workspace/corpus_res2/index_file.txt', 'w')
  65.     #写结果
  66.     fw2=open('D:/python_workspace/corpus_res2/cluser_res.txt', 'w')
  67.     for f in os.listdir(corpus_dir):
  68.         index+=1
  69.         print 'already handle file:', index
  70.         indf_dict[index]=f
  71.         with codecs.open(corpus_dir+f, 'r', encoding='utf-8') as title:
  72.             vec_space.append(vectorspaced(title))
  73.     
  74.     #如何根据hisgram判断分类数目?
  75.     cluster = GAAClusterer(40)
  76.     clustered=cluster.cluster(vec_space, True)
  77.         #cluster.dendrogram().show()
  78.     for k, v in indf_dict.items():
  79.         fw1.write('%s\t%s\n' % (str(k), str(v)))
  80.     fw1.close()
  81.     
  82.     fw2.write('%s\n' % ','.join([str(v) for v in clustered]))
  83.     fw2.close()

阅读(1870) | 评论(0) | 转发(0) |
0

上一篇:Linux netstat命令详解

下一篇:python多线程(1)

给主人留下些什么吧!~~