天天看點

資料挖掘-分詞入門

谷歌4億英鎊收購人工智能公司DeepMind,百度目前正推進“百度大腦”項目,騰訊、阿裡等各大巨頭布局深度學習。随着社會化資料大量産生,硬體速度上升、成本降低,大資料技術的落地實作,讓冷冰冰的資料具有智慧逐漸成為新的熱點。要從資料中發現有用的資訊就要用到資料挖掘技術,不過買來的資料挖掘書籍一打開全是大量的數學公式,而課本知識早已還給老師了,難以下手、非常頭大!

我們可以跳過數學公式,先看看我們了解資料挖掘的目的:發現資料中價值。這個才是關鍵,如何發現資料中的價值。那什麼是資料呢?比如大家要上網首先需要輸入網址,打開網頁後會自動判斷哪些是圖檔、哪些是新聞、哪些是使用者名稱、遊戲圖示等。人大腦可以存儲大量的資訊,包括文字、聲音、視訊、圖檔等,每一個都可以轉換資料存儲在電腦。人的大腦可以根據輸入自動進行判斷,電腦可以通過輸入判斷嗎?答案是肯定的! 不過需要我們編寫程式來判斷每一種資訊,就拿文字識别來說吧,怎麼從一個人在社交網絡的言論判斷他今天的心情是高興還是憤怒!比如:“你假如上午沒給我吃冰淇淋,我絕對會不happy的。” 資訊釋出時間為下午2點。對于我們人類一看這個句子就知道他是吃過冰淇淋了,心情肯定不會是憤怒。那計算機怎麼知道呢?

這就是今天的主題,要讓計算機了解句子的語義,必須要有個程式,上面的句子和釋出時間是輸入,輸出就是 “高興”。要得到“高興”就要建立 “高興”的規則,可以建一個感情色彩詞庫,比如 高興(識别詞是高興、happy),憤怒(識别詞是憤怒、生氣)。這裡的識别詞就是輸入中出現的詞語,比如上面的句子中的“happy”就識别出了“高興”這個感情色彩詞。但是光識别出“happy”肯定是不行的,前面的“假如。。。沒。。。,我。。。不。。。”等關鍵詞都需要識别出來,才能完整判斷一個句子的意思。為了達到這個效果,就必須要用分詞技術了。

我們先人工對上面的句子來進行一下切詞,使用斜線分割:“你/假如/上午/沒/給/我/吃/冰淇淋/,/我/絕對/會/不/happy/的/。/”。但是程式如何做到自動切分?這個其實中國的前輩們已經做了很多中文分詞的研究,常見的分詞算法有:

1、基于詞典的分詞,需要先預設一個分詞詞典,比如上面句子切分出來的“假如、上午”這些詞先存放在詞典,然後把句子切分成單字組合成詞語去詞典裡查找,比對上了就挑選出來一個詞。沒有比對上的就切分成單字。

2、基于統計的分詞,需要先擷取大量的文本語料庫(比如新聞、微網誌等),然後統計文本裡相鄰的字同時出現的次數,次數越多就越可能構成一個詞。當達到一定次數時就構成了一個詞即可形成語料機率庫。再對上面句子進行單字切分,把字與字結合後在語料機率庫裡查找對應的機率,如果機率大于一定值就挑選出來形成一個詞。這個是大概描述,實際生産環境中還需要對句子的上下文進行結合才能更準确的分詞。

3、基于語義的分詞,簡而言之就是模拟人類對句子的了解來進行分詞。需要先整理出中文語句的句法、語義資訊作為知識庫,然後結合句子的上下文,對句子進行單字切分後組合成詞逐個帶入知識庫進行識别,識别出來就挑選出一個詞。目前還沒有特别成熟的基于語義的分詞系統。

為了讓大家快速的了解分詞技術,我們采用第一個方式來做測試:基于詞典的分詞,這種方式簡單暴力可以解決百分之七八十的問題。基于詞典的分詞大概分為以下幾種方式:

1、正向最大比對,沿着我們看到的句子逐字拆分後組合成詞語到詞典裡去比對,直到比對不到詞語為止。舉個實際的例子:“人民大會堂真雄偉”,我們先拆分為單字“人”去詞典裡去查找,發現有“人”這個詞,繼續組合句子裡的單字組合“人民”去詞典裡查找,發現有“人民”這個詞,以此類推發現到“人民大會堂”,然後會結合“人民大會堂真”去詞典裡查找沒有找到這個詞,第一個詞“人民大會堂”查找結束。最終分詞的結果為:“人民大會堂/真/雄偉”。

資料挖掘-分詞入門

2、逆向最大比對,這個和上面相反,就是倒着推理。比如“沿海南方向”,我們按正向最大比對來做就會切分成 “沿海/南方/向”,這樣就明顯不對。采用逆向最大比對法則來解決這個問題,從句子的最後取得“方向”這兩個字查找詞典找到“方向”這個詞。再加上“南方向”組成三字組合查找詞典沒有這個詞,查找結束,找到“方向”這個詞。以此類推,最終分出“沿/海南/方向”。

3、雙向最大比對,顧名思義就是結合正向最大比對和逆向最大比對,最終取其中合理的結果。最早由哈工大王曉龍博士理論化的取最小切分詞數,比如“我在×××家的院子裡看書”,正向最大比對切分出來為“我/在/×××/家/的/院子/裡/看書”工8個詞語,逆向最大比對切分出來為“我/在/中華/人民/共/和/國家/的/院子/裡/看書”共11個詞語。取正向最大比對切出來的結果就是正确的。但是如果把上面那個例子“沿海南方向”雙向切分,都是3個詞語,改如何選擇?看第4個《最佳比對法則》。

4、最佳比對法則,先準備一堆文本語料庫、一個詞庫,統計詞庫裡的每一個詞在語料庫裡出現的次數記錄下來。最後按照詞頻高的優先選出,比如“沿海南方向”,正向切分為:“沿海/南方/向”,逆向切分為:“沿/海南/方向”。其中“海南”的頻度最高,優先取出來。剩下“沿”、“方向”也就正常切分了。是不是這就是基于詞典分詞的最佳方案?比如數學之美中提到的:“把手擡起來” 和 “這扇門的把手”,可以分為“把”、“手”、“把手”,不管怎麼分總有一句話的意思不對。後續再介紹如何通過統計的分詞處理這些問題。

說了這麼多,我們來實戰一下如何基于詞典的分詞:

public class TestPositiveMatch {

    public static void main(String[] args) {

        String str = "我愛這個×××大家庭";

        List<String> normalDict = new ArrayList<String>();

        normalDict.add("");

        normalDict.add("愛");

        normalDict.add("中華");   //測試詞庫裡有中華和×××,按照最大比對應該比對出×××

        normalDict.add("×××");

        int strLen = str.length();  //傳入字元串的長度

        int j = 0;

        String matchWord = ""; //根據詞庫裡識别出來的詞

        int matchPos = 0; //根據詞庫裡識别出來詞後目前句子中的位置

        while (j < strLen) {      //從0字元比對到字元串結束

            int matchPosTmp = 0;   //截取字元串的位置

            int i = 1;

            while (matchPosTmp < strLen) {   //從目前位置直到整句結束,比對最大長度

                matchPosTmp = i + j;

                String keyTmp = str.substring(j, matchPosTmp);//切出最大字元串

                if (normalDict.contains(keyTmp)) { //判斷目前字元串是否在詞典中

                    matchWord = keyTmp;  //如果在詞典中比對上了就指派

                    matchPos = matchPosTmp; //同時儲存好比對位置

                }

                i++;

            }

            if (!matchWord.isEmpty()) {

                //有比對結果就輸出最大長度比對字元串

                j = matchPos;

                //儲存位置,下次從目前位置繼續往後截取

                System.out.print(matchWord + " ");

            } else {

                //從目前詞開始往後都沒有能夠比對上的詞,則按照單字切分的原則切分

                System.out.print(str.substring(j, ++j) + " ");

            matchWord = "";

        }

    }

}

輸出結果為: 我 愛 這 個 ××× 大 家 庭

按照這樣我們一個基本的分詞程式開發完成。

對于文章一開始提到的問題還沒解決,如何讓程式識别文本中的感情色彩。現在我們先要建構一個感情色彩詞庫“高興”,修飾詞庫“沒”、”不”。再完善一下我們的程式:

public class TestSentimentPositiveMatch {

        String str = "你假如上午沒給我吃冰淇淋,我絕對會不happy的。";

        //語義映射

        Map<String, String> sentimentMap = new HashMap<String, String>();

        sentimentMap.put("happy", "高興");

        //情感詞庫

        List<String> sentimentDict = new ArrayList<String>();

        sentimentDict.add("happy");

        //修飾詞

        List<String> decorativeDict = new ArrayList<String>();

        decorativeDict.add("不");

        decorativeDict.add("沒");

        //修飾詞衡量分數

        Map<String, Double> decorativeScoreMap = new HashMap<String, Double>();

        decorativeScoreMap.put("不", -0.5);

        decorativeScoreMap.put("沒", -0.5);

        List<String> decorativeWordList = new ArrayList<String>();  //修飾詞

        String sentimentResult = ""; //情感結果

        String matchSentimentWord = ""; //根據詞庫裡識别出來的情感詞

        String matchDecorativeWord = ""; //根據詞庫裡識别出來的修飾詞

                if (sentimentDict.contains(keyTmp)) { //判斷目前字元串是否在詞典中

                    matchSentimentWord = keyTmp;  //如果在詞典中比對上了就指派

                if (decorativeDict.contains(keyTmp)) { //判斷目前字元串是否在詞典中

                    matchDecorativeWord = keyTmp;  //如果在詞典中比對上了就指派

            if (!matchSentimentWord.isEmpty()) {

                System.out.print(matchSentimentWord + " ");

                sentimentResult = sentimentMap.get(matchSentimentWord);

            if (!matchDecorativeWord.isEmpty()) {

                System.out.print(matchDecorativeWord + " ");

                decorativeWordList.add(matchDecorativeWord);

            matchSentimentWord = "";

            matchDecorativeWord = "";

        double totalScore = 1;

        for (String decorativeWord : decorativeWordList) {

            Double scoreTmp = decorativeScoreMap.get(decorativeWord);

            totalScore *= scoreTmp;

        System.out.print("\r\n");

        if (totalScore > 0) {

            System.out.println("目前心情是:" + sentimentResult);

        } else {

            System.out.println("目前心情是:不" + sentimentResult);

通過傳入“你假如上午沒給我吃冰淇淋,我絕對會不happy的。”,結果輸出為:“目前心情是:高興”。當然你也可以改變其中的修飾詞,比如改為:“你假如上午沒給我吃冰淇淋,我絕對會happy的。”,結果輸出為:“目前心情是:不高興”。

機器再也不是冷冰冰的,看起來他能讀懂你的意思了。不過這隻是一個開始,抛出幾個問題:

1、如何讓程式識别句子中的時間?比如“上午”、“下午2點”。

2、如何處理“把手擡起來” 和 “這扇門的把手”中的“把”與“手”的問題?

3、如何建構海量的知識庫,讓程式從“嬰兒”變成“成年人”?

4、如何使用有限的存儲空間海量的知識庫?

5、如何提高程式在海量知識庫中查找定位資訊的效率?

6、如何識别新詞、人名、新鮮事物等未知領域?

資料挖掘-分詞入門

這是《紐約時報》刊登的2張照片,一張是老鼠的腦細胞(左),一張是宇宙(右)。早期宇宙中星系互連關系,和大腦神經元互相連接配接,幾乎無法分辨兩張圖之間的不同,大腦細胞與整個宇宙擁有一樣的結構。

宇宙芸芸衆生都是相通的,大腦也許就是一個小宇宙,在這個小宇宙又有很多星球、住着很多生物。而電腦也是宇宙中地球上的一個産物,隻要存儲計算速度發展到足夠強大一定可以建構成一個強大的大腦。

你看這個單詞 “testaword” 認識嗎?可能不認識,因為我們五官先擷取到的資訊,然後根據大腦以往學習的經驗做出判斷。但是你看這個短語 ” test a word” 認識嗎?再看看開始那個單詞“testaword”是不是就親切多了?

上一篇: Go資料類型