1. 程式人生 > >利用word2vec對關鍵詞進行聚類

利用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

下載得到的資料有1.5G

2、分詞

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

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進行分詞的程式:

import java.util.HashSet;import java.util.List;import java.util.Set;import
java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileInputStream;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.io.StringReader;import java.util.Iterator;import love.cq.util.IOUtil;import org.ansj.app.newWord.LearnTool;import org.ansj.domain.Term;import org.ansj.recognition.NatureRecognition;import org.ansj.splitWord.Analysis;import org.ansj.splitWord.analysis.NlpAnalysis;import org.ansj.splitWord.analysis.ToAnalysis;import org.ansj.util.*;import org.ansj.recognition.*;public class test public static final String TAG_START_CONTENT = "<content>";    public static final String TAG_END_CONTENT = "</content>";        public static void main(String[] args) {        String temp = null ;                BufferedReader reader = null;        PrintWriter pw = null;        try {            reader = IOUtil.getReader("corpus.txt", "UTF-8") ;            ToAnalysis.parse("test 123 孫") ;            pw = new PrintWriter("resultbig.txt");            long start = System.currentTimeMillis()  ;            int allCount =0 ;            int termcnt = 0;            Set<String> set = new HashSet<String>();            while((temp=reader.readLine())!=null){                temp = temp.trim();                if (temp.startsWith(TAG_START_CONTENT)) {                    int end = temp.indexOf(TAG_END_CONTENT);                    String content = temp.substring(TAG_START_CONTENT.length(), end);                    //System.out.println(content);                    if (content.length() > 0) {                        allCount += content.length() ;                        List<Term> result = ToAnalysis.parse(content);                        for (Term term: result) {                            String item = term.getName().trim();                            if (item.length() > 0) {                                termcnt++;                                pw.print(item.trim() + " ");                                set.add(item);                            }                        }                        pw.println();                    }                }            }            long end = System.currentTimeMillis() ;            System.out.println("共" + termcnt + "個term," + set.size() + "個不同的詞,共 "                    +allCount+" 個字元,每秒處理了:"+(allCount*1000.0/(end-start)));        } catch (IOException e) {             e.printStackTrace();        } finally {            if (null != reader) {                try {                    reader.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if (null != pw) {                pw.close();            }        }    }}
經過對新聞內容分詞之後,得到的輸出檔案resultbig.txt有2.2G,其中的格式如下:

這個檔案就是word2vec工具的輸入檔案

3、本地執行word2vec進行分析

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

./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的詞集合需要接近半個小時的時間:

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

./distance vectors.bin
這裡列出一些有意思的輸出:

怎麼樣,是不是覺得還挺靠譜的?補充一點,由於word2vec計算的是餘弦值,距離範圍為0-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

按類別排序:

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

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