TIL

Today I Learned. 知ったこと、学んだことを書いていく

05. n-gram

自分の力では文字列のみにしか対応できなかった。 間違った出力をしていたため、できていなかった...

できるだけ、自分の力でできるようにしたい

ほかの人の回答を見る前に書いたソース

#!/bin/usr/env python

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

def ws_bigram_str(sequence):
    '''
        与えられたシーケンスをもとに文字bi-gramと単語bi-gramを作成する
        今はstrのみ対応
        :return: word-bi-gram, str-bi-gram
    '''
    
    # 単語bi-gram
    seqList = sequence.split(' ')
    wbigram = bigram(seqList)

    # 文字bi-gram
    sbigram = bigram(sequence)

    return wbigram, sbigram
    

def bigram(sequence):
    rtnbigram = []
    for i in range(len(sequence)):
        # もし、最後の要素だったら抜ける
        if i == len(sequence) - 1:
            break

        rtnbigram.append([sequence[i:i+1], sequence[i+1:i+2]])
    
    return rtnbigram
    

def main():
    s = 'I am an NLPer'
    wordBiGram, strBiGram = ws_bigram_str(s)

    print(wordBiGram)
    print(strBiGram)


if __name__ == '__main__':
    main()

ほかの人の回答を見てみると、文字列を渡した時には文字bi-gram、リストを渡した時には単語bi-gramとなっていた。

たしかに、同時に文字bi-gramと単語bi-gramを作成し返す関数 とは書いてなかった...

あと、n-gramを作る関数って書いてあるため、引数でどの形式化を指定できるようにするべき。

ほかの人の回答を見たあとのソース

#!/bin/usr/env python

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

def ngram(sequence, n=2):
    rtnngram = []
    for i in range(len(sequence)-n+1):
        rtnngram.append(sequence[i:i+n])

    return rtnngram


def main():
    s = 'I am an NLPer'
    char_bi_gram = ngram(s, 2)

    splited = s.split(' ')
    word_bi_gram = ngram(splited, 2)

    print(char_bi_gram)
    # ['I ', ' a', 'am', 'm ', ' a', 'an', 'n ', ' N', 'NL', 'LP', 'Pe', 'er']
    print(word_bi_gram)
    # [['I', 'am'], ['am', 'an'], ['an', 'NLPer']]


if __name__ == '__main__':
    main()
  • len(sequence)-n+1で後ろから n 文字前までという感じにできる
  • strもlistもスライスが使えるため、sequence[i:i+n]というように書くことができる!!!

他の人の回答を見てお勉強させて頂く。

回答1

#!/usr/bin/python

def n_gram(sent, n):
    n_gram_list = []
    for i in range(len(sent)-n+1):
        n_gram_list.append(sent[i:i+n])
    return n_gram_list


if __name__ == "__main__":
    sent = "I am an NLPer"
    word_bi_gram = n_gram(sent.split(), 2)
    char_bi_gram = n_gram(sent, 2)

    print word_bi_gram
    print char_bi_gram

自分なりに理解してみる

n_gramへの引数で、n が 2 で、sent が list型 の場合

len(sent)-n+1は 配列の要素数-1 となる

これは、最後の要素より後ろは取得する必要が無いため、このようになっている。

sent[i:i+n]は今の位置からn個分取り出す処理

strの場合も流れは同じ!


言語処理100本ノック 2015