【ExcelVBA】N-gramを実装してみた【言語処理】
どうも、じゃらしです。
今回はExcelVBAのネタです。
ExcelVBAで「言語処理100本ノック」に挑戦してみようと思い、N-gramというテキスト分割方法について実装してみました。
※「言語処理100本ノック」について気になる人はググってみて下さいませ
①文字単位のN-gramを行うクラスとして「CharNgram.cls」
②単語単位のN-gramを行うクラスとして「WordNgram.cls」
を作成します。
連想配列としてDictionary型を使用するので、事前に参照設定から
「Microsoft Scripting Runtime」にチェックを付けておきましょう。
早速本題です。
'CharNgram.cls Private N_ As Long Public Property Let N(ByVal hoge As Long) N_ = hoge End Property Public Property Get N() As Long N = N_ End Property Public Function ToNgram(ByRef hoge As String) As Dictionary Dim letters As String letters = Replace(hoge, " ", "") Dim length As Long length = Len(letters) Dim dic As New Dictionary Dim char As String Dim i As Long For i = 1 To length - N + 1 char = Mid(letters, i, N) If Not dic.Exists(char) Then dic.Add char, char End If Next i Set ToNgram = dic End Function
↑は、文字単位にN-gramを行う「CharNgram.cls」です。
使い方ですが、あらかじめNに数値を設定しておきます。
そして、N-gramしたい文章を引数としてToNgramを実行すると、N文字で分割された連想配列を返します。
'WordNgram.cls Private N_ As Long Public Property Let N(ByVal hoge As Long) N_ = hoge End Property Public Property Get N() As Long N = N_ End Property Public Function ToNgram(ByRef hoge As String) As Dictionary Dim arrHoge() As String arrHoge = Split(hoge) Dim dic As New Dictionary Dim word As String Dim i As Long For i = LBound(arrHoge) To UBound(arrHoge) - N + 1 word = ConcatWords(arrHoge, i) If Not dic.Exists(word) Then dic.Add word, word End If Next i Set ToNgram = dic End Function Private Function ConcatWords(ByRef arrHoge As Variant, ByVal index As Long) As String Dim arr() As String Dim i As Long For i = 1 To N ReDim Preserve arr(1 To i) As String arr(i) = arrHoge(index + i - 1) Next i ConcatWords = Join(arr) End Function
↑は、単語単位にN-gramを行う「CharNgram.cls」です。
使い方は先ほどと同様、N-gramしたい文章を引数としてToNgramを実行すると、N単語で分割された連想配列を返します。
<実行例1>
'Module1.bas Sub test() Dim sentence As String sentence = "I am an NLPer" With New CharNgram Dim i As Long For i = 1 To 3 .N = i Debug.Print Join(.ToNgram(sentence).Items, ",") Next i End With With New WordNgram For i = 1 To 3 .N = i Debug.Print Join(.ToNgram(sentence).Items, ",") Next i End With End Sub
"I am an NLPer"という文章を文字・単語単位で分割して出力します。
Nが1~3の場合でそれぞれ分割しています。
<実行例2>
'Module2.bas Sub test() Dim x As String, y As String x = "paraparaparadise" y = "paragraph" With New CharNgram .N = 2 Debug.Print Join(.ToNgram(x).Items, ",") Debug.Print Join(.ToNgram(y).Items, ",") End With End Sub
分割した要素は重複しないよ、という例です。
ExcelVBAでテキスト分析するかどうかはさておき、実装を考えるのは楽しかったです。(粉みかん)
以上、それではまた。