はじめに
今更ですが、Pythonの勉強がてら言語処理100本ノック 2015をやってみました。最初は何も見ずにやってみて、その後、他の方の100本ノックの書き方を参考に、より良い(スマートな)書き方でやり直してみます。
より良い書き方の参考文献は最後にまとめて記載しています。
第1章: 準備運動
00. 文字列の逆順
文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.
input_str = 'stressed'
result = input_str[::-1]
print(result)
desserts
より良いコード
スライスのステップに負の値を設定すると末尾から見てくれる。これより大きく変わるのはなさそう。
01. 「パタトクカシーー」
「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.
input_str = 'パタトクカシーー'
result = ''
for index, s in enumerate(input_str):
if index % 2 == 0:
result += s
print(result)
パトカー
より良いコード
これもスライスでOK。
input_str = 'パタトクカシーー'
result = input_str[::2]
print(result)
02. 「パトカー」+「タクシー」=「パタトクカシーー」
「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.
p = 'パトカー'
t = 'タクシー'
result = ''
for i in range(len(p)):
result += p[i]
result += t[i]
print(result)
パタトクカシーー
より良いコード
['パタ', 'トク', 'カシ', 'ーー']
というリストを作ってjoin()
する。
p = 'パトカー'
t = 'タクシー'
result = ''.join([char1 + char2 for char1, char2 in zip(p, t)])
print(result)
03. 円周率
"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.
input_str = 'Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.'
result = []
input_str = input_str.replace(',', '').replace('.', '').split(' ')
for s in input_str:
result.append(len(s))
print(result)
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]
より良いコード
split()
の引数はデフォルトで' '
のため指定不要。
input_str = 'Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.'
result = []
input_str = input_str.replace(',', '').replace('.', '').split()
for s in input_str:
result.append(len(s))
print(result)
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文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.
input_str = 'Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.'
single_ary = [1, 5, 6, 7, 8, 9, 15, 16, 19]
result = {}
input_str = input_str.replace('.', '').split(' ')
for index, s in enumerate(input_str):
if index + 1 in single_ary:
result[s[0]] = index
else:
result[s[0] + s[1]] = index
print(result)
{'H': 0, 'He': 1, 'Li': 2, 'Be': 3, 'B': 4, 'C': 5, 'N': 6, 'O': 7, 'F': 8, 'Ne': 9, 'Na': 10, 'Mi': 11, 'Al': 12, 'Si': 13, 'P': 14, 'S': 15, 'Cl': 16, 'Ar': 17, 'K': 18, 'Ca': 19}
より良いコード
if文を三項演算子に。リストにaryって命名もよくなさそうなので修正。
input_str = 'Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.'
single_list = [1, 5, 6, 7, 8, 9, 15, 16, 19]
result = {}
input_str = input_str.split()
for index, s in enumerate(input_str):
l = 1 if index + 1 in single_list else 2
result[s[:l]] = index
print(result)
05. n-gram
与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,"I am an NLPer"という文から単語bi-gram,文字bi-gramを得よ.
input_str = 'I am an NLPer'
def create_word_n_gram(input_str, num):
str_list = input_str.split(' ')
results = []
for i in range(len(str_list) - num + 1):
ngram = ''
for j in range(num):
ngram += str_list[j + i]
results.append(ngram)
return results
def create_char_n_gram(input_str, num):
str_no_space = input_str.replace(' ', '')
results = []
for i in range(len(str_no_space) - num + 1):
ngram = ''
for j in range(num):
ngram += str_no_space[j + i]
results.append(ngram)
return results
print(create_word_n_gram(input_str, 2))
print(create_char_n_gram(input_str, 2))
['Iam', 'aman', 'anNLPer']
['Ia', 'am', 'ma', 'an', 'nN', 'NL', 'LP', 'Pe', 'er']
より良いコード
文字n-gramはスペースも含む。ずっと勘違いしていた。。。
単語n-gramも出力形式がいけていないので修正。
input_str = 'I am an NLPer'
def create_word_n_gram(input_str, num):
str_list = input_str.split(' ')
results = []
for i in range(len(str_list) - num + 1):
results.append(str_list[i:i + num])
return results
def create_char_n_gram(input_str, num):
results = []
for i in range(len(input_str) - num + 1):
results.append(input_str[i:i + num])
return results
print(create_word_n_gram(input_str, 2))
print(create_char_n_gram(input_str, 2))
[['I', 'am'], ['am', 'an'], ['an', 'NLPer']]
['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に含まれるかどうかを調べよ.
input_str_x = 'paraparaparadise'
input_str_y = 'paragraph'
word = 'se'
def create_char_n_gram(input_str, num):
str_no_space = input_str.replace(' ', '')
results = []
for i in range(len(str_no_space) - num + 1):
ngram = ''
for j in range(num):
ngram += str_no_space[j + i]
results.append(ngram)
return results
def calculate_union(list_x, list_y):
list_union = list(set(list_x + list_y))
return list_union
def calculate_intersection(list_x, list_y):
list_sum = list_x + list_y
list_intersection = [elem for elem in set(list_sum) if list_sum.count(elem) > 1]
return list_intersection
def calculate_difference(list_x, list_y):
list_intersection = calculate_intersection(list_x, list_y)
list_sum = list_x + list_intersection
list_difference = [elem for elem in set(list_sum) if list_sum.count(elem) == 1]
return list_difference
def check_including_word(word_list, word):
if word in word_list:
return True
else:
return False
x = create_char_n_gram(input_str_x, 2)
y = create_char_n_gram(input_str_y, 2)
print(calculate_union(x, y))
print(calculate_intersection(x, y))
print(calculate_difference(x, y))
print(check_including_word(x, word))
print(check_including_word(y, word))
['ar', 'ag', 'gr', 'is', 'ph', 'se', 'pa', 'di', 'ap', 'ad', 'ra']
['ar', 'pa', 'ap', 'ra']
['is', 'se', 'di', 'ad']
True
False
より良いコード
setにしてしまえば集合演算が可能。関数なんていらなかった・・・
チェック関数もかなり冗長。こっちは書いている最中に気付くべき。
input_str_x = 'paraparaparadise'
input_str_y = 'paragraph'
word = 'se'
def create_char_n_gram(input_str, num):
results = []
for i in range(len(input_str) - num + 1):
results.append(input_str[i:i + num])
return results
x = set(create_char_n_gram(input_str_x, 2))
y = set(create_char_n_gram(input_str_y, 2))
print(x | y)
print(x - y)
print(x & y)
print(word in x)
print(word in 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 str(x) + '時の' + y + 'は' + str(z)
print(create_str(x, y, z))
12時の気温は22.4
より良いコード
文字列の足し方はいろいろあると思うが、これより大きく変わるのはなさそう。
08. 暗号文
与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.
英小文字ならば(219 - 文字コード)の文字に置換
その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ.
input_str = 'Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.'
def cipher(input_str):
result = list(map(lambda e: chr(219 - ord(e)) if e.islower() else e, input_str))
return ''.join(result)
print(cipher(input_str))
print(cipher(cipher(input_str)))
Nld I mvvw z wirmp, zoxlslorx lu xlfihv, zugvi gsv svzeb ovxgfivh rmeloermt jfzmgfn nvxszmrxh.
Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.
より良いコード
これより大きく変わるのはなさそう。
正しくは「復号化」ではなく「復号」。と思ったけど、今は「復号化」も普通に使われているらしい・・・
※一瞬、同じ操作で暗号化と復号を両方やるのは不可能だと思ってしまったが、219 - x = y
なら、219 - y = x
になるのは当然だった。219は他の数字でもよい。
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
input_str = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
def create_typoglycemia(input_str):
input_str_list = input_str.split(' ')
result = []
for word in input_str_list:
length = len(word)
if length > 4:
first_char = word[0]
last_char = word[length - 1]
random_str = ''.join(random.sample(list(word[1:length - 1]), length - 2))
result.append(word[0] + random_str + word[length - 1])
else:
result.append(word)
return ' '.join(result)
print(create_typoglycemia(input_str))
I cunldo't biveele that I culod aclatluy urdseanntd what I was rdineag : the pehaneomnl pewor of the huamn mind .
より良いコード
定義したくせに一度しか使っていない変数や、定義したくせに全く使っていない変数を削除。
import random
input_str = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
def create_typoglycemia(input_str):
result = []
for word in input_str.split(' '):
length = len(word)
if length > 4:
random_str = ''.join(random.sample(word[1:length - 1], length - 2))
result.append(word[0] + random_str + word[length - 1])
else:
result.append(word)
return ' '.join(result)
print(create_typoglycemia(input_str))
おわりに
参考とさせていただいた、Qiitaに上がっている言語処理100本ノック2015(Python)の記事をまとめておきます。