Python
自然言語処理
言語処理100本ノック

言語処理100本ノック 第1章: 準備運動 やってみた

はじめに

Pythonをはじめて3ヵ月くらいたったが写経以外のこともしようと思い立ち,普段音響関連の研究をしているのもあって言語処理100本ノックに挑戦.
1日1つやれれば...と思っていたが,忙しかったのもあって結局第1章に二週間程度.

No. 00

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

word = "stressed"
invword = ""

for k in range(len(word)):
    invword = invword + str(word[len(word)-(k+1)])

print(invword)

空の文字列を用意して,そこに元の文字列後ろからとって足していく... ださい
調べてみるともっとかっこいいのがあった.

print(word[::-1])

slice というのを使っているらしいのですが, 文字列[ “始め” : “終り” : “何個区切りか”] で成り立っている自分は認識.
今回の場合,“始め”と“終わり”が省略して既定の文字列の最初と最後になって,-1 区切りで後ろから1つずつといった感じか?

No. 01

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

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

No. 00 の原理と変わらない.

No. 02

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

word1 = "パトカー"
word2 = "タクシー"

word = ""
for k in range(len(word1)):
    word = word + word1[k] + word2[k]

print(word)

今回はこれでいいけど word1 と word2 の文字数違ったらどうすんだってのが気になる...
(ご存知の方教えてください)

No. 03

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

word = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
word_list = word.split(" ")
count = [len(word_temp.strip(",.")) for word_temp in word_list]
print(count)

正直さっぱりだったので,自分で書く前に調べた.
split(" ") でスペースのところで文字列を分け,strip(",.") でカンマやピリオドを抜いている.

こういうのサクッと書けたらいいですよね.

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

word = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
word_list = word.split(' ')
one_list = [1, 5, 6, 7, 8, 9, 15, 16, 19]
dict = {}

for k in range(len(word_list)):

    if k+1 in one_list:
        str = (word_list[k])[0:1]
        dict[str] = k+1

    else:
        str = (word_list[k])[0:2]
        dict[str] = k+1


print(dict)

Pythonの辞書型がわかればあとはシンプル.
辞書型の初期化は {} .

No. 05

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

word = "I am an NLPer"
N = 2;

## 単語 bi-gram
word_list = word.split(' ')
result_word = []

for k in range(len(word_list)-N+1):
    result_word.append(word_list[k:k+2])

print(result_word)


## 文字 bi-gram
result_letter = []

for k in range(len(word)-N+1):
    result_letter.append(word[k:k+2])

print(result_letter)

まず,自分は n-gram ってなんぞ?ってところからだったが,文字や単語をn個ずつに分けるらしいと...
(詳しい方教えてください!)
個人的には比較的無駄を減らせたと思う.

No. 07

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

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

print(str(x) + "時の" + y + "は" + str(z)) 

本当に求められている記述はこれなのだろうか?
と思っていたら Template ってのがあった...

No. 08

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

英小文字ならば(219 - 文字コード)の文字に置換
その他の文字はそのまま出力

この関数を用い,英語のメッセージを暗号化・復号化せよ.

def cipher(target):
    result = ''
    """
    文字列.upper()
    文字列.lower()
    文字を文字コードにord
    文字コードを文字にchr
    """
    for k in range(len(target)):

        if ord(target[k])>96:
            result +=  chr(219 - ord(target[k]))

        else:
            result += target[k]

    return result


cipher("I like the Python")  # 暗号化
'I orpv gsv Pbgslm'

cipher(cipher("I like the Python"))  # 復号化
'I like the Python'

調べながら書いたので内容に関してはコメントの通り.
ちなみに, Python って the いる?

No. 09

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

import random

sentence = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
words = sentence.split(" ")
result = []

for word in words:

    if len(word)>4 :
        word_center = word[1:-1]
        word_center = random.sample(word_center ,len(word_center))
        word_center = ''.join(word_center)
        result.append(word[0] + word_center + word[len(word)-1])

    else:
        result.append(word)


' '.join(result)

ランダムに入れ替えるのには random.shuffle を使うらしいが,エラーが出てめんどうだったので配列から任意の個数を抜き出す random.sample を使用.
今扱っている変数が何型か意識しないと結構ややこしい(当たり前か).

終わりに

この記事を書いている途中に No. 06 を飛ばしていることに気付いた...
1章終わった記念に記事でも書くかと思っていたのにとても悲しいので,他の方のコードを眺めてごまかすことにしよう(素人の言語処理100本ノック:06).

ここまでやってみて普段 Matlab を使った信号処理をやっている身からすると

  • 文字列ってややこしい
  • Pythonって扱うときの型を結構気にしなきゃいけない
  • 当然だが,知らないだけで飛び道具的なものがたくさんある

ということを実感した.現在は Jupyter Notebook でちょこちょこ実装しているが変数の型とか意識するなら spyder とかの方がいいような気もする.
とりあえず,引き続き第2章に取り組もうと思う.

最後に,引用をつけていないが多くの記事を参考にさせていただきました.
諸先輩方ありがとうございます.


まだまだ,Python はじめたばかりなので間違いや無駄等ご教授いただけると幸いです.