1日22時間寝たい

技術頑張ってる最中です

自然言語処理100本ノック2020やってみる【chap1】

はじめに

言語処理100本ノックをやらねばな〜〜と5年考えていたら2020年版が出てしまい、いい加減ちゃんとトライしようと思った次第。

ページは以下です。

nlp100.github.io

マイルールはこう。

  • とりあえず最後までやる
    • 全然わからないところは飛ばす
    • 飛ばしたところは分かった時点で後から追記
  • 問題そのものをググらない
    • Pythonの関数とかはググるけどコピペで動くものをそのまま持ってきたりしない
    • なので書いてあるコードは全くベストな書き方ではないはず
  • できれば!上期中に!終えたい!
    • 怪しい

第1章: 準備運動

コード

00. 文字列の逆順

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

_str = "stressed"
print(_str[::-1])
desserts

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

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

_str = "パタトクカシーー"
print(_str[0:-1:2])

## ぐぐったらこっちでいいらしい
print(_str[::2])
パトカー

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

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

pato = "パトカー"
taxi = "タクシー"

print("".join([i + j for i, j in zip(pato, taxi)]))
パタトクカシーー

03. 円周率

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

sentences = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."

result = [len(i) for i in sentences.replace(",", "").replace(".", "").split(" ")]
print(result)
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

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文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

sentences = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

word_list = sentences.replace(",", "").replace(".", "").split(" ")
bool_list = [True if i+1 in [1, 5, 6, 7, 8, 9, 15, 16, 19] else False for i in range(len(word_list))]

result = {}

for i, j in zip(word_list, bool_list):
    if j:
        k = i[:1]
        result[k] = i
    else:
        k = i[:2]
        result[k] = i

print(result)

# 求められてる答えになってる?
{'H': 'Hi', 'He': 'He', 'Li': 'Lied', 'Be': 'Because', 'B': 'Boron', 'C': 'Could', 'N': 'Not', 'O': 'Oxidize', 'F': 'Fluorine', 'Ne': 'New', 'Na': 'Nations', 'Mi': 'Might', 'Al': 'Also', 'Si': 'Sign', 'P': 'Peace', 'S': 'Security', 'Cl': 'Clause', 'Ar': 'Arthur', 'K': 'King', 'Ca': 'Can'}

05. n-gram

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

sentences = "I am an NLPer"
n = 2
#sentences = ["I", "am", "an", "NLPer"]

result = []

def ngram(sentences, n):
    for i in range(len(sentences)):
        if i < len(sentences) - (n - 1):
            result.append(sentences[i:i + n])

    return result

print(", ".join(ngram(sentences, n)))

# リストが来たらアウト……
I ,  a, am, m ,  a, an, n ,  N, NL, LP, Pe, er

06. 集合

paraparaparadise”と”paragraph”に含まれる文字bi-gramの集合を,それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ.さらに,’se’というbi-gramがXおよびYに含まれるか どうかを調べよ.

sentences1 = "paraparaparadise"
sentences2 = "paragraph"

n = 2
result = []

def ngram(sentences, n):
    for i in range(len(sentences)):
        if i < len(sentences) - (n - 1):
            result.append(sentences[i:i + n])
    return result

X = set(ngram(sentences1, n))
Y = set(ngram(sentences2, n))

print("X", X)
print("Y", Y)
print("和集合", X | Y)
print("積集合", X & Y)
print("差集合", Y - X)

for i, j in zip([X, Y], ["X", "Y"]):
    print("’se’というbi-gramが", j, "に含まれるかどうか?")
    if "se" in i:
        print("◯")
    else:
        print("✕")
X {'ar', 'di', 'se', 'ap', 'ad', 'pa', 'is', 'ra'}
Y {'ar', 'ag', 'di', 'se', 'ap', 'ad', 'ph', 'pa', 'gr', 'is', 'ra'}
和集合 {'ar', 'ag', 'di', 'ap', 'pa', 'ad', 'ph', 'ra', 'gr', 'is', 'se'}
積集合 {'ar', 'di', 'ap', 'ad', 'pa', 'ra', 'is', 'se'}
差集合 {'ph', 'ag', 'gr'}
’se’というbi-gramが X に含まれるかどうか?
◯
’se’というbi-gramが Y に含まれるかどうか?
◯

07. テンプレートによる文生成

引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y=”気温”, z=22.4として,実行結果を確認せよ.

x = 12
y = "気温"
z = 22.4

def create_str(x, y, z):
    return "{}時の{}は{}".format(x, y, z)

print(create_str(x, y, z))
12時の気温は22.4

08. 暗号文

与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.※文字列はWikiの『バステト』の説明文

英小文字ならば(219 - 文字コード)の文字に置換 その他の文字はそのまま出力 この関数を用い,英語のメッセージを暗号化・復号化せよ.

def cipher(sentence):
    result = []
    for i in sentence:
        if i.islower():
            result.append(str(219 - ord(i)))
        else:
            result.append(i)
    return result

sentence = "Bastet, the form of the name that is most commonly adopted by Egyptologists today because of its use in later dynasties, is a modern convention offering one possible reconstruction."
print("".join(cipher(sentence)))
B122104103118103, 103115118 117108105110 108117 103115118 109122110118 103115122103 114104 110108104103 12010811011010810911198 122119108107103118119 12198 E11698107103108111108116114104103104 10310811912298 121118120122102104118 108117 114103104 102104118 114109 111122103118105 11998109122104103114118104, 114104 122 110108119118105109 120108109101118109103114108109 108117117118105114109116 108109118 107108104104114121111118 105118120108109104103105102120103114108109.

09. Typoglycemia

スペースで区切られた単語列に対して,各単語の先頭と末尾の文字は残し,それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ.ただし,長さが4以下の単語は並び替えないこととする.適当な英語の文(例えば”I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind .”)を与え,その実行結果を確認せよ.

import random

sentences = "I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind ."

def typoglycemia(sentences):
    result = []
    words = sentences.split(" ")
    for word in words:
        if len(word) <= 4:
            result.append(word)
        else:
            result.append("".join([word[:1], "".join(random.sample(word[1:-1], len(word[1:-1]))), word[-1:]]))
    return result

print(" ".join(typoglycemia(sentences)))
I clund’ot bielvee that I cluod alcaltuy udnersantd what I was randeig : the paneemnohl pwoer of the human mind .