スポンサードリンク
最近、自然言語処理の勉強を始めたので、東北大学のある教授?が作成した100本ノックをやってみることにしました。
00. 文字列の逆順
「文字列”stressed”の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.」
|
#!/usr/bin/env python # -*- coding: utf-8 -*- str = "stressed" print(str[::-1]) |
特に難しいことはないです。strの引数を[::-1]とすることに注意。
実行結果:
01. 「パタトクカシーー」
『「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.』
|
#!/usr/bin/env python # -*- coding: utf-8 -*- str = "パタトクカシーー" slice = str[0::2] print(slice) |
配列の要素番号は0から始まることに注意です。strの最後の「2」は2つおきに(奇数なので)、[0,2,4,…]ということです。
実行結果:
02. 「パトカー」+「タクシー」=「パタトクカシーー」
『「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.』
|
#!/usr/bin/env python # -*- coding: utf-8 -*- str1 = list("パトカー") str2 = list("タクシー") s ="".join(a+b for (a, b) in zip("パトカー", "タクシー")) #list1,list2を同時にループ print(s) |
自分はzip関数というものを知らなかったので、だいぶ手こずりました笑。どうやら二つのリストの要素ごとに、同時にfor文で回せるようです。
これを知らなかったので、自分は二つのfor文を書き無駄にてこづっていました。
実行結果:
03. 円周率
『”Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.”という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.』
|
#!/usr/bin/env python # -*- coding: utf-8 -*- hoge = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics." huga = hoge.split(" ") print(huga) uga = [] for i in huga: uga.append(len(i)) print(uga) |
スペースキーでsplitしたいときは、split(” “)ですね。ついでにタブでsplitしたいときは、split(“\t”)です。
実行結果:
|
['Now', 'I', 'need', 'a', 'drink,', 'alcoholic', 'of', 'course,', 'after', 'the', 'heavy', 'lectures', 'involving', 'quantum', 'mechanics.'] [3, 1, 4, 1, 6, 9, 2, 7, 5, 3, 5, 8, 9, 7, 10] |
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文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.』
|
#!/usr/bin/env python # -*- coding: utf-8 -*- num_first_only = (0, 4, 5, 6, 7, 8, 14, 15, 18) hoge = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can." huga = hoge.split(" ") result = {} for (num, word) in enumerate(huga): if num in num_first_only: result[word[0:1]] = num else: result[word[0:2]] = num print(result) |
連想配列を作成する方法はいくつかありますが、今回は辞書型と言われているので、ループする際にインデックスつきで要素を得られるenumurate(ループする際にインデックスつきで要素を得ることができる)を用いれば良いです。
for 文の引数を指定するときに、単語のnumberと単語自身のnum,word と二つ指定しなければいけないことに注意。このforの後に二つの引数を使うタイプに慣れていないです笑
実行結果:
|
{'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} |
スポンサードリンク
05. n-gram
『与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,”I am an NLPer”という文から単語bi-gram,文字bi-gramを得よ.』
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
#!/usr/bin/env python # -*- coding: utf-8 -*- def ngram(nlp,hoge): box = [] for i in range(0,len(hoge)-nlp+1): box.append(hoge[i:nlp+i]) return box hoge = "I am an NLPer" words_hoge = hoge.split(" ") #単語バイグラム box = ngram(2,words_hoge) print(box) #文字バイグラム box = ngram(2,hoge) print(box) |
バイグラム以外のngramを一瞬で解析できます。ngram()の引数を変えるだけですね。
ついでにこの場合の文字バイグラムは空白(スペース)も一文字としてカウントしています。実行結果を見てもらえればわかると思います。
実行結果:
|
[['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に含まれるかどうかを調べよ.』
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
#!/usr/bin/env python # -*- coding: utf-8 -*- def ngram(nlp,hoge): box = [] for i in range(0,len(hoge)-nlp+1): box.append(hoge[i:nlp+i]) return box hoge1 = "paraparaparadise" hoge2 = "paragraph" box = ngram(2,hoge1) X = box box = ngram(2,hoge2) Y = box X_set = set(X) Y_set = set(Y) print(X) print(Y) print ("se" in X) # in: X に "se" が含まれていれば True, いなければ False print ("se" in Y) # ほとんど同上(X -> Y) sum_list = list(X_set | Y_set) print(sum_list) matched_list = list(X_set & Y_set) print(matched_list) dif_list = list(X_set - Y_set) print(dif_list) |
ngramの関数は前の問題で作成したものを用いています。
setコマンドは重複を許さない配列の要素を作成します。
さらに二つの配列の中身を比較する際、リスト型からセット型に変換すると、&,-,等の記号だけで集合演算ができます。知らなかった!笑
実行結果:
|
['pa', 'ar', 'ra', 'ap', 'pa', 'ar', 'ra', 'ap', 'pa', 'ar', 'ra', 'ad', 'di', 'is', 'se'] ['pa', 'ar', 'ra', 'ag', 'gr', 'ra', 'ap', 'ph'] True False ['di', 'ad', 'gr', 'ap', 'is', 'ra', 'ar', 'ph', 'se', 'pa', 'ag'] ['ar', 'pa', 'ap', 'ra'] ['se', 'ad', 'is', 'di'] |
スポンサードリンク
07. テンプレートによる文生成
『引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y=”気温”, z=22.4として,実行結果を確認せよ』
|
#!/usr/bin/env python # -*- coding: utf-8 -*- def origin(x,y,z): box = "{shun}時の{naka}は{ore}".format(shun = x, naka = y ,ore = z) return box box = origin(12,"気温",22.4) print(box) |
format関数を用いることで、変数の文字列の埋め込みが可能になります。format関数を用いずにやろうとすると、”気温”が数字ではなく文字列なのでエラーになります。
実行結果:
08. 暗号文
『与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.
- 英小文字ならば(219 – 文字コード)の文字に置換
- その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ.』
|
#!/usr/bin/env python # -*- coding: utf-8 -*- def cipher(string): return ''.join(chr(219-ord(c)) if 'a'<=c<='z' else c for c in string) if __name__=="__main__": sentence="Hello, world!" ciphertext=cipher(sentence) print(sentence) print(ciphertext) print(cipher(ciphertext)) |
最初は、暗号文?なんだそれって感じでしたので、時間がかかりました。
chr()コマンドで暗号文に変換します。ord(c)は暗号化前の文字列です。ifで英小文字の範囲内ならjoin(chr(219-ord(c)、else ならそのまま”c”ということです。
さらにifとfor を内包表記で書いています。この方がコードが複雑になってきたときの可読性が上がるので、この書き方にも慣れないといけませんね!
実行結果:
|
Hello, world! Hvool, dliow! Hello, world! |
09. Typoglycemia
『スペースで区切られた単語列に対して,各単語の先頭と末尾の文字は残し,それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ.ただし,長さが4以下の単語は並び替えないこととする.適当な英語の文(例えば”I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind .”)を与え,その実行結果を確認せよ.』
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys,random,itertools sentence="I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind." #文を単語に分解 words=[word.strip(".,") for word in sentence.split()] for idx,word in enumerate(words): ret="" L=len(word) #4文字以下はなにもしない if 4<L: #最初は確定 ret+=word[0] #並べ替えパターンを全てリストに perm=list(itertools.permutations(list(word[1:L-1]),L-2)) #乱数生成 rnd=random.randint(0,len(perm)-1) #並びのなかからランダムにピック ret+="".join(perm[rnd]) #最後も確定 ret+=word[L-1] words[idx]=ret print (' '.join(words)) |
いくつかコマンドについて説明します。
- itertools.permutations():iterable の要素からなる順列 (permutation) を連続的に返す。
- random.randint(a,b):
a <= N <= b
であるようなランダムな整数 N を返す。
難しいところは、単語を連想配列にして番号と記憶させるのと、文字の並び替えの組み合わせを順列で計算し、各組を乱数で番号付しているところでしょうか。
ここでも連想配列が登場しましたね。
実行結果:
|
I cnuol'dt bevilee that I cluod alautlcy urtsanendd what I was rdniaeg : the pnnahemeol pewor of the human mind |
以上で第1章は終わりです。続きはこちら>>>第二章前半。
スポンサードリンク