第1章 解答

8/3(火)の勉強会にて、自然言語処理100本ノックの第1章「準備運動」をやってみる。

https://nlp100.github.io/ja/ch01.html

00. 文字列の逆順

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

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

コメント:文字列[::-1]で逆になるの初めて知りました。

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

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

string = "パタトクカシーー"
ans = string[0::2]
print(ans)
パトカー

コメント:文字列[x::y] で(x+1)番からy個おきに取得できる。

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

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

s1 = "パトカー"
s2 = "タクシー"

ans = ""
for i,j in zip(s1,s2):
    ans += i+j
print(ans)

#短く
ans2 = ''.join([i+j for i,j in zip(s1,s2)])
print(ans)
パタトクカシーー
パタトクカシーー

コメント:zip()で複数のものに対してfor文を実行できる。

03. 円周率

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

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

#コンマとコロンを抜く
sentence = sentence.replace(',','')
sentence = sentence.replace('.','')

#単語の配列にする
word_list = sentence.split()

ans = list()
for word in word_list:
    ans.append(len(word))

print(ans)
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

コメント:replaceで文字の置換、splitで文字の分解

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

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

# コンマをとって単語の配列に
sentence = sentence.replace('.','')
word_list = sentence.split()

ans = dict()
for index,word in enumerate(word_list):
    will_take_first = [1, 5, 6, 7, 8, 9, 15, 16, 19]
    if index+1 in will_take_first:
        ans[word[0]] = index+1
    else:
        ans[word[0:2]] = index+1

print(ans)
{'H': 1, 'He': 2, 'Li': 3, 'Be': 4, 'B': 5, 'C': 6, 'N': 7, 'O': 8, 'F': 9, 'Ne': 10, 'Na': 11, 'Mi': 12, 'Al': 13, 'Si': 14, 'P': 15, 'S': 16, 'Cl': 17, 'Ar': 18, 'K': 19, 'Ca': 20}

コメント:for文でenumerate(配列)で、インデックスと配列の要素の両方が取得できる

05. n-gram

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

def n_gram(string,n):
    """文字列stringと自然数nを受け取り、単語n-gramと文字n-gramを返す"""
    #単語n_gramを作る
    word_n_gram = []
    sentence = string.replace(',','').replace('.','')
    word_list = sentence.split()
    for i in range(len(word_list)-n+1):
        word_n_gram.append(word_list[i:i+n])

    #文字n_gramを作る
    letter_n_gram = []
    for i in range(len(string)-n+1):
        letter_n_gram.append(string[i:i+n])
    return word_n_gram, letter_n_gram

word_n_gram,letter_n_gram = n_gram('I am an NLPer',2)
print("単語bi-gram→",word_n_gram)
print("文字bi-gram→",letter_n_gram)
単語bi-gram→ [['I', 'am'], ['am', 'an'], ['an', 'NLPer']]
文字bi-gram→ ['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に含まれるかどうかを調べよ.

# 05で作ったn_gram関数を使う。
_,X = n_gram('paraparaparadise',2)
_,Y = n_gram('paragraph',2)

X = set(X)
Y = set(Y)

print('Xは',X)
print('Yは',Y)

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

if "se" in X and "se" in Y:
    print("seはX,Yの両方に含まれます。")
elif "se" in X:
    print("seはXのみに含まれます。")
elif "se" in Y:
    print("seはYのみに含まれます。")
else:
    print("seはどちらにも含まれません。")
Xは {'di', 'ar', 'ad', 'ra', 'is', 'ap', 'se', 'pa'}
Yは {'ar', 'ph', 'ra', 'ap', 'ag', 'gr', 'pa'}
和集合は {'di', 'ar', 'ph', 'ad', 'ra', 'is', 'ap', 'ag', 'gr', 'se', 'pa'}
積集合は {'ap', 'ra', 'ar', 'pa'}
差集合は {'ad', 'di', 'se', 'is'}
seはXのみに含まれます。

コメント:和集合は「|」、積集合は「&」、差集合は「-」で求められる。

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

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

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

print(create_sentence(12,"気温",22.4))
12時の気温は22.4

コメント:なし

08. 暗号文

与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.

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

def cipher(string):
    ans = ""
    for letter in string:
        if letter.islower():
            ans += chr(219 - ord(letter))
        else:
            ans += letter
    return ans

example = "Men willingly believe what they wish."
encoded = cipher(example)
decoded = cipher(encoded)

print("暗号化されたもの→",encoded)
print("復号化されたもの→",decoded)
暗号化されたもの→ Mvm droormtob yvorvev dszg gsvb drhs.
復号化されたもの→ Men willingly believe what they wish.

コメント:英小文字かどうかの判定は文字.islower()でできる。 ord(文字)で文字コードが取得でき、chr(文字コード)で文字が取得できる。

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
def shuffle_string(string):   
    """文字列stringをランダムに並び替える関数""" 
    letter_list = list(string)
    random.shuffle(letter_list)
    return ''.join(letter_list)


def generate_typo(word):
    """ 単語wordを受け取り、長さが5以上であれば先頭と末尾以外をランダムにする関数 """
    if len(word) > 4:
        return word[0] + shuffle_string(word[1:-1]) + word[-1]
    else:
        return word

example = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
word_list = example.split()

ans = ""
for word in word_list:
    ans += generate_typo(word) + " "

print(ans)
I cnd'uolt blveiee that I could altulacy udtrenansd what I was rnaideg : the pnhneoamel peowr of the huamn mind . 

コメント:list(文字列)で文字ごとの配列が取得できる。

ちなみにタイポグリセミア(Typoglycemia)とは、文章中のいくつかの単語で、先頭と末尾以外の文字がシャッフルされても正しく読めてしまうこと。 打ち間違えの「Typo」と、低血糖症の「Hypoglycemia」をかけたもの

準備運動ということで簡単でした。続きもやり次第公開していきます。

T/T(東京医科歯科大学医療IT数学同好会)では、入会したい関東の医学生を募集しております。Twitterからお気軽にお声がけください!

Discussion

コメントにはログインが必要です。