見出し画像

言語処理100本ノック 解答例 第一章 (00-09)

自然言語処理の入門トレーニングとして最適だと思ったので,取り組みます!


00. 文字列の逆順

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

Pythonのスライス操作で逆順に並び替えています.

s = "stressed"
print(s[::-1])

出力

desserts


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

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

Pythonのスライス操作ではステップを指定できます.[start:stop:step]

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

出力

パトカー​


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

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

'zip'を使うことで複数のオブジェクトの要素を同時に取得できます.

s1 = "パトカー"
s2 = "タクシー"
for (a, b) in zip(s1, s2):
   print(a + b, end="")

出力

パタトクカシーー


03. 円周率

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

split()で文字列を分割し,配列を得ます.そして,ループで各要素の長さを出力します.

s = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
words = s.split()
for i in range(len(words)):
   print(len(words[i]),end="")

出力

3141692753589710


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

enumerate(words,1)を使うことで,要素とインデックスを取得できます.インデックスが,[1, 5, 6, 7, 8, 9, 15, 16, 19]のとき,先頭の1文字を取得します.

s = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
words = s.split()
number_list = [1, 5, 6, 7, 8, 9, 15, 16, 19]
ans={}
for i, word in enumerate(words,1):
   if i in  number_list:
       ans[word[0]] = i
   else:
       ans[word[0:2]] = i
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}


05. n-gram

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

単語bi-gramは,まず文字列をsplit()で単語ごとに分割します.一方,文字bi-gramは,replaceで文字列の空白を取り除きます.

ans.append(words[i:i+n]) → スライスで指定された数だけ取得します.今回はbiなので2.
for i in range(len(words) + 1 - n): → 配列要素を飛び越えないようにしています.例:10単語でbi-gram → 10 + 1 - 2 = 9

def n_gram(words, n):
   '''
   与えられたリストからn-gramを作成
   s:文字列
   n:単語数
   '''
   ans = []
   for i in range(len(words) + 1 - n):
       ans.append(words[i:i+n])
   return ans

s = "I am an NLPer"

#単語bi-gram
words = s.split()
print(n_gram(words,2))

#文字bi-gram
letters = s.replace(' ','')
print(n_gram(letters,2))

出力

[['I', 'am'], ['am', 'an'], ['an', 'NLPer']]
['Ia', 'am', 'ma', 'an', 'nN', 'NL', 'LP', 'Pe', 'er']


06. 集合

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

まず,05と同様にbi-gramを取得.

集合演算は,set型を使うとできます.

和集合 |  積集合 &  差集合 - 

s1 = "paraparaparadise"
s2 = "paragraph"

def n_gram(word, n):
   '''
   与えられたリストからn-gramを作成
   s:文字列
   n:単語数
   '''
   ans = []
   for i in range(len(word) + 1 - n):
       ans.append(word[i:i+n])
   return ans

X = n_gram(s1,2)
print('X', X)
Y = n_gram(s2,2)
print('Y', Y)

#和集合
s_union = set(X) | set(Y)
#s_union = set(X).union(set(Y))
print('和集合',s_union)

#積集合
s_intersection = set(X) & set(Y)
#s_intersection = set(X).intersection(set(Y))
print('積集合', s_intersection)

#差集合
s_difference = set(X) - set(Y)
#s_difference = set(X).difference(set(Y))
print('差集合', s_difference)

#'se'が含まれているか
print('"se"が含まれているか')
print('X', 'se' in X)
print('Y', 'se' in Y)

出力

X ['pa', 'ar', 'ra', 'ap', 'pa', 'ar', 'ra', 'ap', 'pa', 'ar', 'ra', 'ad', 'di', 'is', 'se']
Y ['pa', 'ar', 'ra', 'ag', 'gr', 'ra', 'ap', 'ph']
和集合 {'is', 'pa', 'ag', 'ra', 'ph', 'ar', 'se', 'gr', 'di', 'ap', 'ad'}
積集合 {'ra', 'ar', 'ap', 'pa'}
差集合 {'di', 'is', 'ad', 'se'}
"se"が含まれているか
X True
Y False


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

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

引数を受け取るときは,sysライブラリを使います.sys.argvで,引数として入力された物を空白区切りで配列として取得できます.

import sys

args = sys.argv                                             
print('{}時の{}は{}'.format(args[1], args[2], args[3]))

出力

12時の気温は22.4


08. 暗号文

与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.英小文字ならば(219 - 文字コード)の文字に置換
その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ.

islower() → 小文字判定
ord:文字→アスキーコード
chr:アスキーコード→文字

def cipher(sentence):
   '''文字列の暗号化、復号化
   引数:target -- 対象の文字列
   戻り値:変換した文字列
   '''
   result = ''
   for c in sentence:
       if c.islower():
           result += chr(219 - ord(c))
       else:
           result += c
   return result

sentence = input('文字列を入力-->')
encryption = cipher(sentence)
print('暗号化', encryption)

decryption = cipher(encryption)
print('複号化', decryption)

入力

文字列を入力-->Good morning. おはよう

出力

暗号化 Gllw nlimrmt. おはよう
複号化 Good morning. おはよう


09. Typoglycemia

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

mid = list(word[1:-1]) → 先頭と末尾を除いた文字列を取得
random.shuffle(mid) → シャッフル
result.append(word[0] + ''.join(mid) + word[-1]) → 元の先頭+シャッフルした中間の文字列+元の末尾

import random

input_text="I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
text = input_text.split()
result = []
for word in text:
   if len(word) > 4:
       mid = list(word[1:-1])
       random.shuffle(mid)
       result.append(word[0] + ''.join(mid) + word[-1])
   else:
       result.append(word)
print(' '.join(result))

出力

I cnul’dot bevliee that I culod aalctuly uedrastnnd what I was reinadg : the pneonamhel peowr of the hamun mind .


この記事が気に入ったらサポートをしてみませんか?