PHP:N-gramを使用したテキスト言語の定義。 パート1

:何らかの理由で、転送を復元できませんでした。そのため、招待を受け取り、どこかで消えました。 したがって、私はそれを再び公開します。

通常、テキストを見るときは、テキストを単語に分割し、これらの単語を使用して、テキストの記述言語を決定します。 ただし、他のテキスト単位を比較することでこれを行う方法は多数あります。 たとえば、文字n-gram。

N-gramは、ドキュメントから抽出された単純なn文字のシーケンスです。 たとえば、トライグラム(3文字のシーケンス)に分解された「constable」という単語は、{"con"、 "ons"、 "nst"、 "ste"、 "teb"、 "fuck"、 "shit"}のようになります。 そのようなシーケンスを抽出する方法は多数あります。 以下で多かれ少なかれ明らかです。 この関数を使用すると、入力文字列からn-gramを抽出できます。 デフォルトでは、トライグラムが取得されます。



<?php

function getNgrams ( $ word , $ n = 3 ) {
$ ngrams = array ( ) ;
for ( $ i = 0 ; $ i < strlen ( $ match ) ; $ i + + ) {
if ( $ i > ( $ n - 2 ) ) {
$ ng = ' ' ;
for ( $ j = $ n - 1 ; $ j > = 0 ; $ j - - ) {
$ ng . = $ match [ $ i - $ j ] ;
}
$ ngrams [ ] = $ ng ;
}
}
return $ ngrams ;
}
FractalizeR's HabraSyntax Source Code Highlighter .


言語定義


n-gramに分割されたテキストを見ると、それらの助けを借りて、それが書かれている言語を決定するのが非常に簡単であることがわかります。 これを行うには、異なる「類似性」係数を計算する2グラムまたは3グラムを使用する多くのアルゴリズムがありますが、それらはすべて1つに同意します。 。 この例では、トライグラムとベクトル空間の類似度のコサイン尺度を使用します(ベクトル空間スタイルのコサイン類似度)。

最も明白な質問の1つは、「スペースをどうするか」です。 この例では、それらを無視し、単語からのみトライグラムを生成します。 また、3文字未満の単語は無視します。 このテキストでトライグラムが発生する頻度のみを考慮します。 原則として、たとえば、トリグラムのグローバルな重みをアルゴリズムに導入することにより、このトリグラムがモデルのすべての言語に対してどれほど一般的であるかを示すことにより、決定の精度を高めることができます。 しかし、これがなくても、特に少数の言語では、トライグラム法は非常に正確に機能します。

以下は、検出を実装する小さなクラスです。 主要なメソッドはaddDocumentです。これは、入力ドキュメントをトライグラムに分割し、各言語で発生する頻度を内部辞書に保存します(モデルのティーチングメソッド、約Transl。)。そして、検出し、検出されたそれぞれに対して同じように着信テキストを分割しますtrigramsは、モデルの各言語での存在頻度をチェックします。

<?php

class LangDetector {
private $ index = array ( ) ;
private $ languages = array ( ) ;

public function addDocument ( $ document , $ language ) {
if ( ! isset ( $ this -> languages [ $ language ] ) ) {
$ this -> languages [ $ language ] = 0 ;
}

$ words = $ this -> getWords ( $ document ) ;
foreach ( $ words as $ match ) {
$ trigrams = $ this -> getNgrams ( $ match ) ;
foreach ( $ trigrams as $ trigram ) {
if ( ! isset ( $ this -> index [ $ trigram ] ) ) {
$ this -> index [ $ trigram ] = array ( ) ;
}
if ( ! isset ( $ this -> index [ $ trigram ] [ $ language ] ) ) {
$ this -> index [ $ trigram ] [ $ language ] = 0 ;
}
$ this -> index [ $ trigram ] [ $ language ] + + ;
}
$ this -> languages [ $ language ] + = count ( $ trigrams ) ;
}
}

public function detect ( $ document ) {
$ words = $ this -> getWords ( $ document ) ;
$ trigrams = array ( ) ;
foreach ( $ words as $ word ) {
foreach ( $ this -> getNgrams ( $ word ) as $ trigram ) {
if ( ! isset ( $ trigrams [ $ trigram ] ) ) {
$ trigrams [ $ trigram ] = 0 ;
}
$ trigrams [ $ trigram ] + + ;
}
}
$ total = array_sum ( $ trigrams ) ;

$ scores = array ( ) ;
foreach ( $ trigrams as $ trigram = > $ count ) {
if ( ! isset ( $ this -> index [ $ trigram ] ) ) {
continue ;
}
foreach ( $ this -> index [ $ trigram ] as $ language = > $ lCount ) {
if ( ! isset ( $ scores [ $ language ] ) ) {
$ scores [ $ language ] = = 0 ;
}
$ score = ( $ lCount / $ this -> languages [ $ language ] )
* ( $ count / $ total ) ;
$ scores [ $ language ] + = $ score ;
}
}
arsort ( $ scores ) ;
return key ( $ scores ) ;
}

private function getWords ( $ document ) {
$ document = strtolower ( $ document ) ;
preg_match_all ( ' /\w+/ ' , $ document , $ matches ) ;
return $ matches [ 0 ] ;
}

private function getNgrams ( $ match , $ n = 3 ) {
$ ngrams = array ( ) ;
for ( $ i = 0 ; $ i < strlen ( $ match ) ; $ i + + ) {
if ( $ i > ( $ n - 2 ) ) {
$ ng = ' ' ;
for ( $ j = $ n - 1 ; $ j > = 0 ; $ j - - ) {
$ ng . = $ match [ $ i - $ j ] ;
}
$ ngrams [ ] = $ ng ;
}
}
return $ ngrams ;
}
}
?>
FractalizeR's HabraSyntax Source Code Highlighter .


記事の続きはこちら

Source: https://habr.com/ru/post/J75509/


All Articles