MikiTech

文系新卒エンジニアの学習記録

【Python】言語処理100本ノック2020 05. n-gram

問題

nlp100.github.io

与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,”I am an NLPer”という文から単語bi-gram,文字bi-gramを得よ

コード

n-gramってなんじゃらほい』となりましたが、とりあえずコードを提示します。

text = "I am an NLPer"


def nGramWord(text, num):
    #スライス
    result = [text[index : index+num ] for index in range(len(text)-num+1)]

    return result


for i in range(1,5):
    print(str(i)+"番目")
    #単語n-gram
    print(nGramWord(text.split(),i))
    #文字n-gram
    print(nGramWord(text.replace(' ', ''),i))

#出力結果
'''
1番目
[['I'], ['am'], ['an'], ['NLPer']]
['I', 'a', 'm', 'a', 'n', 'N', 'L', 'P', 'e', 'r']
2番目
[['I', 'am'], ['am', 'an'], ['an', 'NLPer']]
['Ia', 'am', 'ma', 'an', 'nN', 'NL', 'LP', 'Pe', 'er']
3番目
[['I', 'am', 'an'], ['am', 'an', 'NLPer']]
['Iam', 'ama', 'man', 'anN', 'nNL', 'NLP', 'LPe', 'Per']
4番目
[['I', 'am', 'an', 'NLPer']]
['Iama', 'aman', 'manN', 'anNL', 'nNLP', 'NLPe', 'LPer']
'''

n-gramとは

自然言語処理界隈では当たり前らしいn-gram。 一言でいうと、連続するn個の単語・文字の区切られたまとまりのようです。
n=1だとuni-gram、n=2だとbi-gram、n=3だとtri-gramと言うそうです。(4からはわかりません)

例えば、
『私はりんごを食べた』という文章を単語でuni-gramにした場合。
{私}{は}{りんご}{を}{食べた}になっていればOKだと思います。

今回は英文でスペースなどが空いているため、比較的処理は単純になりました。
n-gramについて詳しくはこちら。

mojitoba.com

コード

関数一つだけの処理で、引数にテキストを加工して渡しています。
単語n-gramでは、splitメソッドを使ってテキストを分割し渡しました。
文字n-gramの方では、英文のスペースをreplceメソッドで削除しています。

def nGramWord(text, num):
    #スライス
    result = [text[index : index+num ] for index in range(len(text)-num+1)]

    return result

さて、問題の関数部分ですが非常に悩みました。
テキストはI am an NLPer
これをbi-gramにすると…

[I,am],[am,an],[an,NLPer]}

となります。
まず[I,am]を作り出すには、スライスが有効的。
渡されているデータは、{I,am,an,NLPer}です。

[0:2]が合っていそうです。

続いて、[am,an]。
[1:3]が良さそう。

続いて、[an,NLPer]。
[2:4]が良さそうです。

左側の数字は1ずつ増えており、右側の数字は初期値がNでNずつ増えています。
全体で塊がいくつあるかというと、3(for文で「2」回です)つあります。

そしてtri-gram(n-gramの3Version)。
3つずつとりだすので、このようになります。

['I', 'am', 'an'], ['am', 'an', 'NLPer']

繰り返しは2(for文では0,1回です)ですね。

ここに法則性を見出す必要があります。
テキストの長さは5
bi-gramのときはfor文の繰り返しが2
tri-gramのときは、for文の繰り返しが1

biは2。
triは1。

つまり5(テキスト長さ)- ? =2(繰り返し数)
であり、
?の部分はbiやtriつまりNを渡しますが、どちらも1足りません。

なので…
5(テキスト長さ)- N+1 =2(繰り返し数)
になるというわけです。

うーん。
いきなりレベルがあがった気がします。
n-gramの作り方はこの記事が参考になります。

qiita.com

何かこうした方がいいとあれば教えて下さい!!