【言語処理100本ノック】課題No.00〜05

業務で自然言語処理(NLP)に取り組む予定なので、自然言語処理の練習として東北大学の乾・鈴木研究室さんの『言語処理100本ノック 2015』に取り組みたいと思います。

www.cl.ecei.tohoku.ac.jp

今回の記事では、第1章「00.文字列の逆順〜05.n-gram」に取り組みます。 間違いや改善点等ありましたら、ご指摘下さい。

また、解くために調べたサイトも記載しておきます。 (サイトの内容は、特にまとめておりません。)

00.文字列の逆順

課題

文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.

解答

スライスで解きました。

#00.文字列の逆順
target = 'stressed'
 
result = target[::-1] #逆順へ並べ替え
print(result)         #'desserts'

スライスの使い方

以下のサイトがとてもまとまっているので、参考にして下さい。

note.nkmk.me

01.「パタトクカシーー」

課題

「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

解答

「00.文字列の逆順」と同様に、スライスで解きました。

#01.パタトクカシーー    
target = 'パタトクカシーー'
 
result = target[0:8:2] #奇数番目の取り出し
print(result)          #'パトカー'

02.「パトカー」+「タクシー」=「パタトクカシーー」

課題

「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

解答

内包表記で解いてみました。

#02. パトカー+タクシー=>パタトクカシーー
target_a = 'パトカー'
target_b = 'タクシー'
 
#二つの文字列を交互に連結
result = ''.join([a+b for(a, b) in zip(target_a, target_b)])
print(result) #パタトクカシーー

内包表記

今まで、内包表記から避けていたので、まだ慣れていません。

以下のURLがとてもまとまっているので、参考にして下さい。 qiita.com

リストの文字列要素の連結(join)

要素が文字列のリスト一つの文字列に連結するために、joinを活用します。 ちなみに、joinを使わない場合、次のようになります。

#02. パトカー+タクシー=>パタトクカシーー
target_a = 'パトカー'
target_b = 'タクシー'
 
#二つの文字列をそれぞれ順番に結合(join使わず)
result = [a+b for(a, b) in zip(target_a, target_b)]
print(result) #['パタ', 'トク', 'カシ', 'ーー']

以下のサイトがとてもまとまっているので、参考にして下さい。 hibiki-press.tech

03.円周率

課題

"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

解答

まず、replace.,を置換(消去)してから、単語に分割し、それぞれの文字数のリストを作成しています。

target = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
 
target = target.replace(',', '').replace('.', '')
result = [len(iWord) for iWord in target.split(' ')]
print(result) #[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

文字列の置換(replace)

以下のURLがとてもまとまっているので、参考にして下さい。 note.nkmk.me

"Now I need a drink, ..."って何?

課題のタイトルにあるので、想像に難くないですが、円周率の15桁までの暗記法です。 ちなみに、英語だと、5桁、8桁の暗記方法があるみたいです。

日本の場合、『産医師異国に向かう』で9桁までの語呂合わせの暗記方法があります。(知らなかった。)

以下のサイトがとてもまとまっているので、参考にして下さい。 ja.wikiquote.org

04.元素記号

課題

"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

解答

「03.円周率」で使用した関数に加え、enumerateif文を利用し、解きました。

target = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
 
oneCharList = [ 1, 5, 6, 7, 8, 9, 15, 16, 19]
result  = {(index, jWord[0]) if (index+1) in oneCharList else (index, jWord[0:2]) for (index, jWord) in enumerate(target.split(' ')) }
print(result) #{(8, 'F'), (18, 'K'), (19, 'Ca'), (17, 'Ar'), (6, 'N'), (0, 'H'), (9, 'Ne'), (4, 'B'), (13, 'Si'), (11, 'Mi'), (14, 'P'), (16, 'Cl'), (10, 'Na'), (15, 'S'), (7, 'O'), (5, 'C'), (3, 'Be'), (1, 'He'), (12, 'Al'), (2, 'Li')}

""Hi He Lied Because Boron ..."って何?

「03.円周率」と同様、元素記号を表しているのだと思われますが、マグネシウム('Mg')が'Mi'となっています。また、円周率の場合とは異なり、元素記号は色々な語呂合わせがあり、明確な暗記文がないみたいです。

05.n-gram

課題

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

解答

n-gramが分からないと、全く解けない課題ですね。(私は知りませんでした。)

bi-gram(n=2)の場合を簡単に表すと、図のようにの順に、文字列を2個ずつ分解することです。

f:id:guarana001:20191014232447p:plain
単語n-gram

f:id:guarana001:20191014232607p:plain
文字n-gram

#与えられたシーケンスからn-gramを作る関数
def get_ngram(seq, num):
    result = [seq[index:index+num] for index in range(len(seq)+1-num)]
    return result
 
if __name__ == '__main__':
    #05.n-gram
    target = "I am an NLPer"
    num = 2
 
    #単語n-garm
    result_word  = get_ngram(target, num) 
    #[['I', 'am'], ['am', 'an'], ['an', 'NLPer']] 
 
    #文字n-garm 
    result_str   = get_ngram(target.split(' '), num)
    #['I ', ' a', 'am', 'm ', ' a', 'an', 'n ', ' N', 'NL', 'LP', 'Pe', 'er']

n-gramって何?

以下の二つのサイトがとてもまとまっているので、参考にして下さい。 qiita.com gihyo.jp