數據挖掘入門——分詞

數據挖掘入門——分詞

 

谷歌4億英鎊收購人工智能公司DeepMind,百度目前正推動「百度大腦」項目,騰訊、阿里等各大巨頭也在積極佈局深度學習。隨着社會化數據大量產生,硬件速度上升、成本下降,大數據技術的落地實現,讓冷冰冰的數據具備智慧逐漸成爲新的熱點。要從數據中發現有用的信息就要用到數據挖掘技術,不過買來的數據挖掘書籍一打開全是大量的數學公式,而課本知識早已還給老師了,着實難如下手、很是頭大!算法

咱們不妨先跳過數學公式,看看咱們瞭解數據挖掘的目的——發現數據中價值。這個纔是關鍵,如何發現數據中的價值。那什麼是數據呢?好比你們要上網首先須要輸入網址,打開網頁後會自動判斷哪些是圖片、哪些是新聞、哪些是用戶名稱、遊戲圖標等。大腦能夠存儲大量的信息,包括文字、聲音、視頻、圖片等,這些一樣能夠轉換成數據存儲在電腦。人的大腦能夠根據輸入自動進行判斷,電腦能夠經過輸入判斷嗎?網絡

答案是確定的! 不過須要咱們編寫程序來判斷每一種信息,就拿文字識別來講吧,怎麼從一我的在社交網絡的言論判斷他今天的心情是高興仍是憤怒!好比:「你假如上午沒給我吃冰淇淋,我絕對會不happy的。」 信息發佈時間爲下午2點。對於咱們人類一看這個句子就知道他是吃過冰淇淋了,心情確定不會是憤怒。那計算機怎麼知道呢?架構

這就是今天的主題,要讓計算機理解句子的語義,必需要有個程序,上面的句子和發佈時間是輸入,輸出就是 「高興」。要獲得「高興」就要創建 「高興」的規則,能夠建一個感情色彩詞庫,好比高興(識別詞是高興、happy),憤怒(識別詞是憤怒、生氣)。這裏的識別詞就是輸入中出現的詞語,好比上面的句子中的「happy」就識別出了「高興」這個感情色彩詞。可是光識別出「happy」確定是不行的,前面的「假如……沒……,我……不……」等關鍵詞都須要識別出來,才能完整判斷一個句子的意思。爲了達到這個效果,就必需要用分詞技術了。app

分詞

咱們先人工對上面的句子來進行一下切詞,使用斜線分割:「你/假如/上午/沒/給/我/吃/冰淇淋/,/我/絕對/會/不/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 {
   public static void main(String[] args) {
   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 = ""; //情感結果

  int strLen = str.length();  //傳入字符串的長度
   int j = 0;
  String matchSentimentWord = ""; //根據詞庫裏識別出來的情感詞
  String matchDecorativeWord = ""; //根據詞庫裏識別出來的修飾詞
  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 (sentimentDict.contains(keyTmp)) { //判斷當前字符串是否在詞典中
  matchSentimentWord = keyTmp;  //若是在詞典中匹配上了就賦值
  matchPos = matchPosTmp; //同時保存好匹配位置
   }
  if (decorativeDict.contains(keyTmp)) { //判斷當前字符串是否在詞典中
  matchDecorativeWord = keyTmp;  //若是在詞典中匹配上了就賦值
  matchPos = matchPosTmp; //同時保存好匹配位置
   }
   i++;
   }
   if (!matchSentimentWord.isEmpty()) {
  //有匹配結果就輸出最大長度匹配字符串
   j = matchPos;
  //保存位置,下次從當前位置繼續日後截取
   System.out.print(matchSentimentWord + " ");
   sentimentResult = sentimentMap.get(matchSentimentWord);
   }
   if (!matchDecorativeWord.isEmpty()) {
  //有匹配結果就輸出最大長度匹配字符串
   j = matchPos;
  //保存位置,下次從當前位置繼續日後截取
   System.out.print(matchDecorativeWord + " ");
   decorativeWordList.add(matchDecorativeWord);
   } else {
  //從當前詞開始日後都沒有可以匹配上的詞,則按照單字切分的原則切分
   System.out.print(str.substring(j, ++j) + " ");
   }
   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. 如何識別新詞、人名、新鮮事物等未知領域?

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

你看這個單詞 「testaword」 認識嗎?可能不認識,由於咱們五官先獲取到的信息,而後根據大腦以往學習的經驗作出判斷。可是你看這個短語 」 test a word」 認識嗎?再看看開始那個單詞「testaword」是否是就親切多了?

To Be Continued……

關於做者:嚴瀾現成都創行負責人,歷任上海創行科技技術總監。曾任中國平安平臺開發工程師,騰訊拍拍網B2C架構工程師。Web3.0語義搜索引擎探索者,海量數據處理,互聯網高性能低成本平臺架構搭建實踐者,構建讓更多普通開發者快速掌握高性能技術的框架,自由機器人研發愛好者。

相關文章
相關標籤/搜索