利用IKAnalyzer中文分詞,計算句子相似度

jopen 9年前發布 | 175K 次閱讀 中文分詞 IKanalyzer

IKAnalyzer中文分詞,計算句子相似度

一、簡介

    IKAnalyzer是一個開源的,基于java語言開發的輕量級的中文分詞工具包。以開源項目Luence為應用主體的,結合詞典分詞和文法分析算法的中文分詞組件。獨立于Lucene項目,同時提供了對Lucene的默認優化實現。(簡介來源:百度百科

二、準備

    項目結構:

    利用IKAnalyzer中文分詞,計算句子相似度

    IKAnalyzer2012FF_u1.jar 下載

    lucene-core-4.6.1.jar 下載

    ext.dic

    stopword.dic

    IKAnalyzer.cfg.xml

三、分詞

    分詞由于比較簡單,就直接粘貼代碼了

public static Vector<String> participle( String str ) {

    Vector<String> str1 = new Vector<String>() ;//對輸入進行分詞

    try {

        StringReader reader = new StringReader( str ); 
        IKSegmenter ik = new IKSegmenter(reader,true);//當為true時,分詞器進行最大詞長切分 
        Lexeme lexeme = null ;          

        while( ( lexeme = ik.next() ) != null ) {
        str1.add( lexeme.getLexemeText() ); 
        }           

        if( str1.size() == 0 ) {
            return null ;
        }
        
       //分詞后
        System.out.println( "str分詞后:" + str1 );
        
    } catch ( IOException e1 ) {
        System.out.println();
    }
    return str1;
}


四、計算相似度

    計算句子相似度,①常用方法有基于語義和詞序相似度計算方法②基于關系向量模型

    基于語義和詞序的句子相似度計算方法簡介

    定義1:給定一個句子Ti,經過漢語分詞系統分詞后,得到的所有詞W1構成的向量稱為句子Ti的向量表示,表示為Ti = {w1,w2,.....wn}。

    例子1:T1:這個中文分詞可不可以,用著方不方便。分詞后:T1=[這個, 中文分詞, 可不可以, 用著, 方, 不, 方便]。向量表示T1={這個, 中文分詞, 可不可以, 用著, 方, 不, 方便}

                T2:這個中文分詞比較方便,用著方便還可以。分詞后:T2=[這個, 中文分詞, 比較方便, 用著, 方便, 還可以]向量表示T2={這個, 中文分詞, 比較方便, 用著, 方便, 還可以}

    定義2:給定一個句子Ti的向量表示,Ti中詞的個數稱為Ti的向量長度,表示為Len(Ti).

    例子2:對于句子T1和T2的向量長度表示為:Len(T1)=7,Len(T1)=6。

    定義3:給定兩個句子Ti、Tj的向量表示,將Ti、Tj中的所有詞Wi進行合并,并且對于重復初想的詞只保留一個,由此得到兩個向量之和,稱為Ti、Tj的并集,表示T=T1 U T2={這個, 中文分詞, 可不可以, 比較方便,用著, 方, 不, 方便,還可以},很顯然,并集長度Len(T)<=Len(T1)+Len(T2)。

    定義4:給定一個句子Ti的向量表示Ti = {w1,w2,.....wn}和一個詞wi,依次計算wi和Ti中每一個詞的相似度(值為0到1之間),所以所有結果中的最大值稱為wi在Ti中的語義分數,表示為Ci。

    定義5:給定兩個句子Ti、Tj的向量表示,Ti和Tj的集合T={w1、w2,....wn},對T中的每一個詞Wi,計算Wi在Ti中的語義分數Ci,T中每個分詞的語義分數組成的一個向量稱為Ti基于T的語義向量,表示為Si={C1,C2,...,Cn}。

           在該算法中,基于T分別計算Ti和Tj的語義向量Si、Sj,以計算Si作為說明,過程如下:

    1、對于T中的每一個詞wi,如果wi 在Ti 中出現,則在語義向量Si中將wi 的語義分數Ci設為1。

    2、如果Ti中不包含wi,則計算wi 在 Ti 中的語義分數 Ci=a(a為預先設定的閾值 , 無閾值設為0 ,本文中閾值為0.2 ) 。

        根據語義向量計算語義相似度方法如下圖:

        利用IKAnalyzer中文分詞,計算句子相似度

         詞序相似度計算法方法如下:

         利用IKAnalyzer中文分詞,計算句子相似度       

    其中r1、r2 分別為T1、T2的詞序向量,以T1為例,其計算方法如下:

    1、對于T中的每一個詞wi,如果T1中包含該次,則r1中該次的取值為該詞在T1中出現的詞序。否則在T1中找出與wi最相似的詞Wi。

    2、如果wi 和 wi 的相似度大于一個給定的閾值(實驗取值為0.4),wi在r1中的取值設為wi在Ti中出現的詞序。

    3、如果兩種情況均為發生,則wi在r1中的取值設為null。 

    然而,根據語義向量計算語義相似度方法中,想到了之前看過的一篇博客,通過余玄定理來實現,計算方法如下

//閾值
public static double YUZHI = 0.2 ;

/**
 * 返回百分比
 * @author: Administrator
 * @Date: 2015年1月22日
 * @param T1
 * @param T2
 * @return
 */
public static double getSimilarity(Vector<String> T1, Vector<String> T2) throws Exception {
    int size = 0 , size2 = 0 ;
    if ( T1 != null && ( size = T1.size() ) > 0 && T2 != null && ( size2 = T2.size() ) > 0 ) {
        
        Map<String, double[]> T = new HashMap<String, double[]>();
        
        //T1和T2的并集T
        String index = null ;
        for ( int i = 0 ; i < size ; i++ ) {
            index = T1.get(i) ;
            if( index != null){
                double[] c = T.get(index);
                c = new double[2];
                c[0] = 1; //T1的語義分數Ci
                c[1] = YUZHI;//T2的語義分數Ci
                T.put( index, c );
            }
        }
 
        for ( int i = 0; i < size2 ; i++ ) {
            index = T2.get(i) ;
            if( index != null ){
                double[] c = T.get( index );
                if( c != null && c.length == 2 ){
                    c[1] = 1; //T2中也存在,T2的語義分數=1
                }else {
                    c = new double[2];
                    c[0] = YUZHI; //T1的語義分數Ci
                    c[1] = 1; //T2的語義分數Ci
                    T.put( index , c );
                }
            }
        }
            
        //開始計算,百分比
        Iterator<String> it = T.keySet().iterator();
        double s1 = 0 , s2 = 0, Ssum = 0;  //S1、S2
        while( it.hasNext() ){
            double[] c = T.get( it.next() );
            Ssum += c[0]*c[1];
            s1 += c[0]*c[0];
            s2 += c[1]*c[1];
        }
        //百分比
        return Ssum / Math.sqrt( s1*s2 );
    } else {
        throw new Exception("傳入參數有問題!");
    }
}


測試結果

str分詞后:[這個, 中文分詞, 可不可以, 用著, 方, 不, 方便]
str分詞后:[這個, 中文分詞, 比較方便, 用著, 方便, 還可以]
相似度:0.7595872466989299



代碼地址twosnail源碼地址

原創作者:twosnail(兩只蝸牛)

來自:http://my.oschina.net/twosnail/blog/370744

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!