原標題:利用word2vec對關鍵詞進行聚類

按照一般的思路,可以用新聞ID向量來表示某個關鍵詞,這就像廣告推薦系統裡面用使用者訪問類別向量來表示使用者一樣,然後就可以用kmeans的方法進行聚類了。不過對於新聞來說存在一個問題,那就量太大,如果給你十萬篇新聞,那每一個關鍵詞將需要十萬維的向量表示,隨著新聞數迅速增加,那維度就更大了,這計算起來難度太大。於是,這個方法思路簡單但是不可行。

好在我們有word2vec這個工具,這是google的一個開源工具,能夠僅僅根據輸入的詞的集合計算出詞與詞直接的距離,既然距離知道了自然也就能聚類了,而且這個工具本身就自帶了聚類功能,很是強大。下面正式介紹如何使用該工具進行詞的分析,關鍵詞分析和聚類自然也就包含其中了。word2vec官網地址看這裡:https://code.google.com/p/word2vec/

1、尋找語料

要分析,第一步肯定是收集數據,這裡不可能一下子就得到所有詞的集合,最常見的方法是自己寫個爬蟲去收集網頁上的數據。不過,如果不需要實時性,我們可以使用別人提供好的網頁數據,例如搜狗2012年6月到7月的新聞數據:http://www.sogou.com/labs/dl/ca.html 直接下載完整版,註冊一個帳號,然後用ftp下載,ubuntu下推薦用filezilla

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

下載得到的數據有1.5G

利用word2vec對關鍵詞進行聚類

2、分詞

我們得到的1.5的數據是包含一些html標籤的,我們只需要新聞內容,也就是content其中的值。首先可以通過簡單的命令把非content的標籤幹掉

  1. cat news_tensite_xml.dat | iconv -f gbk -t utf-8 -c | grep “<content>” > corpus.txt

得到了corpus.txt文件只含有content標籤之間的內容,再對內容進行分詞即可,這裡推薦使用之前提到過的ANSJ,沒聽過的看這

里:http://blog.csdn.net/zhaoxinfan/article/details/10403917

下面是調用ANSJ進行分詞的程式:

  1. importjava.util.HashSet;

  2. importjava.util.List;

  3. importjava.util.Set;

  4. importjava.io.BufferedReader;

  5. importjava.io.BufferedWriter;

  6. importjava.io.File;

  7. importjava.io.FileInputStream;

  8. importjava.io.FileReader;

  9. importjava.io.FileWriter;

  10. importjava.io.IOException;

  11. importjava.io.InputStreamReader;

  12. importjava.io.PrintWriter;

  13. importjava.io.StringReader;

  14. importjava.util.Iterator;

  15. importlove.cq.util.IOUtil;

  16. importorg.ansj.app.newWord.LearnTool;

  17. importorg.ansj.domain.Term;

  18. importorg.ansj.recognition.NatureRecognition;

  19. importorg.ansj.splitWord.Analysis;

  20. importorg.ansj.splitWord.analysis.NlpAnalysis;

  21. importorg.ansj.splitWord.analysis.ToAnalysis;

  22. importorg.ansj.util.*;

  23. importorg.ansj.recognition.*;

  24. publicclasstest {

  25. publicstaticfinalString TAG_START_CONTENT = “<content>”;

  26. publicstaticfinalString TAG_END_CONTENT = “</content>”;

  27. publicstaticvoidmain(String[] args) {

  28. String temp = null;

  29. BufferedReader reader = null;

  30. PrintWriter pw = null;

  31. try{

  32. reader = IOUtil.getReader(“corpus.txt”, “UTF-8”) ;

  33. ToAnalysis.parse(“test 123 孫”) ;

  34. pw = newPrintWriter(“resultbig.txt”);

  35. longstart = System.currentTimeMillis() ;

  36. intallCount =0;

  37. inttermcnt = 0;

  38. Set<String> set = newHashSet<String>();

  39. while((temp=reader.readLine())!=null){

  40. temp = temp.trim();

  41. if(temp.startsWith(TAG_START_CONTENT)) {

  42. intend = temp.indexOf(TAG_END_CONTENT);

  43. String content = temp.substring(TAG_START_CONTENT.length(), end);

  44. //System.out.println(content);

  45. if(content.length() > 0) {

  46. allCount += content.length() ;

  47. List<Term> result = ToAnalysis.parse(content);

  48. for(Term term: result) {

  49. String item = term.getName().trim();

  50. if(item.length() > 0) {

  51. termcnt++;

  52. pw.print(item.trim() + ” “);

  53. set.add(item);

  54. }

  55. }

  56. pw.println();

  57. }

  58. }

  59. }

  60. longend = System.currentTimeMillis() ;

  61. System.out.println(“共”+ termcnt + “個term,”+ set.size() + “個不同的詞,共 “

  62. +allCount+” 個字元,每秒處理了:”+(allCount*1000.0/(end-start)));

  63. } catch(IOException e) {

  64. e.printStackTrace();

  65. } finally{

  66. if(null!= reader) {

  67. try{

  68. reader.close();

  69. } catch(IOException e) {

  70. e.printStackTrace();

  71. }

  72. }

  73. if(null!= pw) {

  74. pw.close();

  75. }

  76. }

  77. }

  78. }

經過對新聞內容分詞之後,得到的輸出文件resultbig.txt有2.2G,其中的格式如下:

利用word2vec對關鍵詞進行聚類

這個文件就是word2vec工具的輸入文件

3、本地運行word2vec進行分析

首先要做的肯定是從官網上下載word2vec的源碼:http://word2vec.googlecode.com/svn/trunk/ ,然後把其中makefile文件的.txt後綴去掉,在終端下執行make操作,這時能發現word2vec文件夾下多了好幾個東西。接下來就是輸入resultbig.txt進行分析了:

  1. ./word2vec -train resultbig.txt -output vectors.bin -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -binary 1

這裡我們指定輸出為vectors.bin文件,顯然輸出到文件便於以後重複利用,省得每次都要計算一遍,要知道處理這2.2G的詞集合需要接近半個小時的時間:

利用word2vec對關鍵詞進行聚類

下面再輸入計算距離的命令即可計算與每個詞最接近的詞了:

[plain]view plaincopyprint?

  1. ./distance vectors.bin

這裡列出一些有意思的輸出:

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

利用word2vec對關鍵詞進行聚類

怎麼樣,是不是覺得還挺靠譜的?補充一點,由於word2vec計算的是餘弦值,距離範圍為0-1之間,值越大代表這兩個詞關聯度越高,所以越排在上面的詞與輸入的詞越緊密。

至於聚類,只需要另一個命令即可:

  1. ./word2vec -train resultbig.txt -output classes.txt -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -classes 500

按類別排序:

  1. sort classes.txt -k 2 -n > classes.sorted.txt

後記:如果想要了解word2vec的實現原理,應該讀一讀官網後面的三篇參考文獻。顯然,最主要的應該是這篇:Distributed Representations of Words and Phrases and their Compositionality

https://arxiv.org/pdf/1310.4546.pdf

這篇文章的基礎是 Natural Language Processing (almost) from

Scratch

http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//pubs/archive/35671.pdf

其中第四部分提到了把deep learning用在NLP上。

最後感謝曉陽童鞋向我提到這個工具,不愧是立志要成為NLP專家的人。

附:一個在線測試的網站,貌似是一位清華教授做的:http://cikuapi.com/index.php