1. 程式人生 > >自然語言處理基於java實現(1) 之 中文分詞

自然語言處理基於java實現(1) 之 中文分詞

下一篇<自然語言處理基於java實現(2) 之 詞性註釋>
程式原始碼下載
一. 題目如下:
1、針對人民日報語料,編寫程式:
抽取詞表
統計總詞數、不同的詞及其次數。輸出檔案格式:
第一行是語料庫中的總詞數,之後每行一個詞及其次數,按照詞頻從小到大排序。如:
總詞數:10000
#韓國:169
#民族:571
……
去除語料中的分詞和詞性標記,形成未加工的語料(原始文字)
2、基於上述詞表,編寫一個正向最大匹配分詞程式。程式功能:
輸入:沒有分過詞的檔案或一段文字
輸出:分過詞的檔案或一段文字。
3、編寫一個評價程式,自動評價分詞結果的準確率。

人民日報語料擷取小部分如下:
19980101-02-002-001/m 忠誠/a 的/u 共產主義/n 戰士/n ,/w 久經考驗/l 的/u 無產階級/n 革命家/n 劉/nr 瀾濤/nr 同志/n 逝世/v
19980101-02-002-002/m (/w 附/v 圖片/n 1/m 張/q )/w
19980101-02-002-003/m 根據/p 劉/nr 瀾濤/nr 同志/n 生前/t 遺願/n 和/c 家屬/n 的/u 意見/n ,/w 劉/nr 瀾濤/nr 同志/n 的/u 喪事/n 從簡/v ,/w 不/d 舉行/v 儀式/n 、/w 不/d 保留/v 骨灰/n 。/w

二. 我們的目的是:
1. 將如”忠誠”,”的”等等(除去19980101-02-002-001/m,以及詞性標註/w等等)詞,進行統計
2. 對統計的詞進行出現次數升序排序
3. 基於詞庫,用最大正向匹配演算法,對任意句子進行分詞
4. 寫一個評價程式

三. 直接上程式碼:

package experiment1;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import
java.util.Map; import java.util.Map.Entry; /** * 詞庫 */ public class Thesaurus{ /** * 儲存結構為: * Entry<單詞,次數> */ private List<Entry<String, Integer>> list = new ArrayList<>(); /** * 載入詞庫,初始化 */ public Thesaurus(String content){ //進行分詞統計 final Map<String,Integer> MAP = createMAP(content); //排序並存入list中 sortMapByValue(MAP); } /** * 分詞 * @param str 分詞的句子 * @param symbol 分割的符號 * @return */ public String spitWord(final String str,final String symbol){ StringBuilder target = new StringBuilder(); int start = 0; while(start<str.length()){ boolean noWord = true; for(int end = str.length();end>start;end--){ String now = str.substring(start, end); for(Entry<String,Integer> e:list){ if(e.getKey().equals(now)){ target.append(symbol).append(now); start = end; noWord = false; break; } } } if(noWord){ target.append(symbol).append(str.charAt(start++)); } } return target.substring(symbol.length()).toString(); } public int numOfSize(){ return list.size(); } /** * 分詞 * @param str 要分詞的句子 * @return 分詞後的字串陣列 */ public String[] spitWord(final String str){ return spitWord(str,",,,,").split(",,,,"); } /** * 對map按照value排序,並存入list中 * @param map */ private void sortMapByValue(Map<String, Integer> map) { //這裡將map.entrySet()轉換成list list.addAll(map.entrySet()); //然後通過比較器來實現排序 Collections.sort(list,new Comparator<Map.Entry<String,Integer>>() { //升序排序 public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) { return o1.getValue().compareTo(o2.getValue()); } }); } /** * 對文字alls的內容進行分詞統計,存入map中 * @param alls * @return */ private Map<String, Integer> createMAP(String alls) { final Map<String,Integer> map = new HashMap<String,Integer>(); //去掉空白符號 StringBuilder sb = new StringBuilder (alls.replaceAll("\\s", "")); int start = 0; while(start<sb.length()){ int end = sb.indexOf("/",start+1); if(sb.charAt(end+1)!='m'){ String s = sb.substring(start, end); if(map.containsKey(s)){ map.put(s, map.get(s)+1); }else{ map.put(s, 1); } } start = end+2; } return map; } public List<Entry<String, Integer>> getList() { return list; } }

三. 實現步驟:
0. 建一個詞庫類,不需要解釋吧

 **// 儲存結構為:
// Entry<單詞,出現次數>
private  List<Entry<String, Integer>> list = new ArrayList<>();**
  1. 第一步,將文字進行字串切割成詞
  2. 第二步,統計詞彙
    以下把第一二步一次性實現了
/**
     * 對文字alls的內容進行分詞統計,存入map中
     * @param alls
     * @return 
     */
    private Map<String, Integer> createMAP(String alls) {
        final Map<String,Integer> map = new HashMap<String,Integer>();
        //去掉空白符號
        StringBuilder sb = new StringBuilder (alls.replaceAll("\\s", ""));
        int start = 0;
        while(start<sb.length()){
            int end = sb.indexOf("/",start+1);
            if(sb.charAt(end+1)!='m'){
                String s = sb.substring(start, end);
                if(map.containsKey(s)){
                    map.put(s, map.get(s)+1);
                }else{
                    map.put(s, 1);
                }
            }
            start = end+2;
        }
        return map;
    }

3.對獲得的統計容器map進行排序:

/**
     * 對map按照value排序,並存入list中
     * @param map
     */
    private void sortMapByValue(Map<String, Integer> map) {
        //這裡將map.entrySet()轉換成list  
        list.addAll(map.entrySet());  
        //然後通過比較器來實現排序  
        Collections.sort(list,new Comparator<Map.Entry<String,Integer>>() {  
            //升序排序  
            public int compare(Entry<String, Integer> o1,  
                    Entry<String, Integer> o2) {  
                return o1.getValue().compareTo(o2.getValue());  
            }  
        });  
    }

4.正向最大匹配:
正向最大匹配是怎麼回事呢?
比如句子:美國政府把視線轉向亞太地區
1) 向詞庫查詢,”美國政府把視線轉向亞太地區”是否是一個詞,是,則成功匹配,否則執行2)
2) 向詞庫查詢,”美國政府把視線轉向亞太地”是否是一個詞,是,則成功匹配,否則執行3)
3) 向詞庫查詢,”美國政府把視線轉向亞太”是否是一個詞,是,則成功匹配,否則按照規律繼續執行,直至匹配成功

寫了兩個方法,方便不同情況的呼叫

/**
     * 分詞
     * @param str 分詞的句子
     * @param symbol 分割的符號
     * @return
     */
    public String spitWord(final String str,final String symbol){
        StringBuilder target = new StringBuilder();
        int start = 0;
        while(start<str.length()){
            boolean noWord = true;
            for(int end = str.length();end>start;end--){
                String now = str.substring(start, end);
                for(Entry<String,Integer> e:list){
                    if(e.getKey().equals(now)){
                        target.append(symbol).append(now);
                        start = end;
                        noWord = false;
                        break;
                    }
                }
            }
            if(noWord){
                target.append(symbol).append(str.charAt(start++));
            }
        }
        return target.substring(symbol.length()).toString();
    }

    /**
     * 分詞
     * @param str 要分詞的句子
     * @return 分詞後的字串陣列
     */
    public  String[] spitWord(final String str){
        return spitWord(str,",,,,").split(",,,,");
    }

5.評價程式
以下是一個簡單的實現:

package experiment1;

import java.util.HashMap;
import java.util.Map;

public class Assess {

    /**
     * 獲得s1和s2分詞的相似分數0-100分
     * @param s1
     * @param s2
     * @return
     */
    public static int get(String s1, String s2) {
        Map<Integer,Integer> map1 = get(s1);
        Map<Integer,Integer> map2 = get(s2);
        int goal = 0;
        for(int key:map1.keySet()){
            if(map1.get(key)==map2.get(key)){
                goal++;
            }
        }
        return goal*100/map1.size();
    }

    /**
     * 獲得分詞序列號
     * @param s
     * @return
     */
    public static Map<Integer,Integer> get(String s) {
        int start = 0;
        int num = 0;
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        while(start<s.length()){
            int end = s.indexOf("'",start+1);
            if(end==-1){
                end = s.length();
            }
            map.put(start-num, end-num);    
            num++;
            start = end+1;
        }
        return map;
    }

}

6.最後,寫個測試吧:
1) Junit測試

package test;

import static org.junit.Assert.*;

import org.junit.Ignore;
import org.junit.Test;

import experiment1.Assess;


public class AssessTest {

    @Test
    public void testGet() {
        //           0   2  3  4  5  6   8
        String s1 = "你問'我'愛'你'有'多深";
        //           0 1 2  3  4  5  6   8
        String s2 = "你'問'我'愛'你'有'多深";
        assertEquals(83, Assess.get(s1,s2));

        String s3 = "我們'去'小王'家'休息'一會";
        String s4 = "我們'去'小王'家'休息'一'會";
        assertEquals(83, Assess.get(s3, s4));

    }

    @Ignore
    @Test
    public void testGet2() {
        //           0   2  3  4  5  6   8
        String s1 = "你問'我'愛'你'有'多深";
        //           0 1 2  3  4  5  6   8
        String s2 = "你'問'我'愛'你'有'多深";
        assertEquals(Assess.get(s1).keySet(), Assess.get(s2).keySet());

        String s3 = "休息'一會";
        String s4 = "休息'一'會";
        assertEquals(Assess.get(s3).keySet(), Assess.get(s4).keySet());

    }
}

2) main測試

package test;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import experiment1.Assess;
import experiment1.Thesaurus;
import util.FileRW;


/**
 * 測試實驗一
 * @author Administrator
 *
 */
public class Test1 {

    public static void main(String[] args) {
        Thesaurus thesaurus = new Thesaurus(FileRW.read("199801.txt"));
        Scanner in = new Scanner(System.in);
        List<Integer> list = new ArrayList<>();
        System.out.println("請輸入測試的次數");
        int times = in.nextInt();
        in.nextLine();
        while(times-->0){
            System.out.println("請輸入句子:");
            String s1 = in.nextLine();
            System.out.println("請輸入標準答案(請用'分詞):");
            String s2 = in.nextLine();
            String s3 = thesaurus.spitWord(s1, "'");
            System.out.println("系統分詞結果:\n"+s3);
            list.add(Assess.get(s2,s3));
        }
        int average = 0;
        System.out.print("每句分詞成績: ");
        for(int goal :list){
            System.out.print(goal+"  ");
            average += goal;
        }
        average = average/list.size();
        System.out.println("\n平均得分: "+average);
        in.close();
    }

}

相關推薦

自然語言處理基於java實現(1) 中文

下一篇<自然語言處理基於java實現(2) 之 詞性註釋> 程式原始碼下載 一. 題目如下: 1、針對人民日報語料,編寫程式: 抽取詞表 統計總詞數、不同的詞及其次數。輸出檔案格式: 第一行

Python自然語言處理實戰(3):中文技術

3.1、中文分詞簡介       在英文中,單詞本身就是“詞”的表達,一篇英文文章就是“單詞”加分隔符(空格)來表示的,而在漢語中,詞以字為基本單位的,但是一篇文章的語義表達卻仍然是以詞來劃分的。       自中文自動分詞被提出以來,歷經將近30年的探索,提出了很多方法,可

自然語言處理工具HanLP-N最短路徑

本篇給大家分享baiziyu 寫的HanLP 中的N-最短路徑分詞。以為下分享的原文,部分地方有稍作修改,內容

Java呼叫ICTCLAS2016 中文

win7  64位,java呼叫 1.下載ICTCLAS20160405171043_ICTCLAS2016分詞系統下載包 , 2.找到漢語分詞.....20140928/sample/Java/JNA,把該路徑下的JnaTest_NLPIR工程,匯入Myeclipse,

基於python的自然語言處理 分類和標註詞彙5.5N-gram標註

一元標註器unigram tagging一元標註器利用一種簡單的統計演算法,對每個識別符號分配最有可能的標記。建立一元標註器的技術稱為訓練。>>> fromnltk.corpus import brown>>> importnltk>

python自然語言處理(NLP)1------中文1基於規則的中文方法

python中文分詞方法之基於規則的中文分詞 目錄 常見中文分詞方法 推薦中文分詞工具 參考連結 一、四種常見的中文分詞方法: 基於規則的中文分詞 基於統計的中文分詞 深度學習中文分詞 混合分詞方法 基於規則的中

自然語言處理中文器詳解

中文分詞是中文文字處理的一個基礎步驟,也是中文人機自然語言互動的基礎模組,不同於英文的是,中文句子中沒有詞的界限,因此在進行中文自然語言處理時,通常需要先進行分詞,分詞效果將直接影響詞性,句法樹等模組

python自然語言處理(一)中文處理、統計詞頻

一個小的嘗試。。資料來源資料集 一共200條關於手機的中文評論,以XML格式儲存。分詞工具 python-jieba預處理包括去停用詞、去標點符號和數字去停用詞:使用的是他人總結的 停用詞表去標點符號和數字:用正則表示式。原本打算的是中文標點符號從網上覆制,英文標點符號用st

自然語言處理中文器-jieba器詳解及python實戰

中文分詞是中文文字處理的一個基礎步驟,也是中文人機自然語言互動的基礎模組,在進行中文自然語言處理時,通常需要先進行分詞。本文詳細介紹現在非常流行的且開源的分詞器結巴jieba分詞器,並使用python實

利用Tensorflow進行自然語言處理(NLP)系列二高階Word2Vec

一、概述 在上一篇中,我們介紹了Word2Vec即詞向量,對於Word Embeddings即詞嵌入有了些基礎,同時也闡述了Word2Vec演算法的兩個常見模型 :Skip-Gram模型和CBOW模型,本篇會對兩種演算法做出比較分析並給出其擴充套件模型-GloVe模型。

第六章(1.2)自然語言處理實戰——打造屬於自己的中文word2vector工具

一、環境 二、實戰演練 訓練語料source.txt 9月12日隨著頒獎典禮的結束,我院獲得了商委系統運動會系列活動之一——足球比賽的季軍,本次比賽立時十天,十二隻球隊分成兩個小組比賽。我院代表隊以小組第二名的成績出現,在和另一小組第二名石油公

自然語言處理(NLP) - 數學基礎(1) - 總述

正如我在<2019年總結>裡說提到的, 我將開始一系列自然語言處理(NLP)的筆記.   很多人都說, AI並不難啊, 調現有庫和雲的API就可以啦.   然而實際上並不是這樣的. 首先, AI這個領域十分十分大, 而且從1950年圖靈提出圖靈測試, 1956年達特茅

自然語言處理(NLP) - 數學基礎(1) - 排列組合

正如我在<自然語言處理(NLP) - 數學基礎(1) - 總述>一文中所提到的NLP所關聯的概率論(Probability Theory)知識點是如此的多, 飯只能一口一口地吃了, 我們先開始最為大家熟知和最基礎的知識點吧, 排列組合.   雖然排列組合這個知識點大家是相當地熟知,

HanLP《自然語言處理入門》筆記--1.新手上路

1. 新手上路 自然語言處理(Natural Language Processing,NLP)是一門融合了電腦科學、人工智慧及語言學的交叉學科,它們的關係如下圖所示。這門學科研究的是如何通過機器學習等技術,讓計算機學會處理人類語言,乃至實現終極目標--理解人類語言或人工智慧。 美國電腦科學家Bill Ma

中文自然語言處理向量合集(字向量,拼音向量,向量,詞性向量,依存關係向量)

ChineseEmbedding Chinese Embedding collection incling token ,postag ,pinyin,dependency,word embedding.中文自然語言處理向量合集,包括字向量,拼音向量,詞向量,詞性向量,依存關係向量.共5

ElasticSearch-6.4.1安裝中文器Analysis-ik.

一:使用背景和安裝過程.         1. ElasticSearch-6.4.1.(Windows環境下)         &nbs

hanlp原始碼解析中文演算法詳解

詞圖 詞圖指的是句子中所有詞可能構成的圖。如果一個詞A的下一個詞可能是B的話,那麼A和B之間具有一條路徑E(A,B)。一個詞可能有多個後續,同時也可能有多個前驅,它們構成的圖我稱作詞圖。 需要稀疏2維矩陣模型,以一個詞的起始位置作為行,終止位置作為列,可以得到一個二維矩陣。例如:“他說的確實

基於高版本Lucene的中文器(IK器)的DEMO

注意 為了大家方便,我沒有遮蔽資料庫,專案中用的資料來源請各位碼友不要亂搞~謝謝 緣起 日前專案中需要用到Lucene.且需要中文分詞,看了下IK分詞器,但是IK分詞器貌似只支援到lucene的3.X。後期的版本就不支援了,在網上找了一部分資料,自己寫了一個demo.因為中間

Hanlp原始碼解析中文演算法

詞圖 詞圖指的是句子中所有詞可能構成的圖。如果一個詞A的下一個詞可能是B的話,那麼A和B之間具有一條路徑E(A,B)。一個詞可能有多個後續,同時也可能有多個前驅,它們構成的圖我稱作詞圖。 需要稀疏2維矩陣模型,以一個詞的起始位置作為行,終止位置作為列,可以得到一個二維矩陣。例如:“他說的確實

python_NLP實戰中文技術

一、規則分詞 1.1 正向最大匹配演算法 # 正向最大匹配演算法 MM法 規則分詞 class MM(object): def __init__(self): self.window_size=3 def cut(self,text)