言語処理100本ノック 2015 第1章 05〜09

一つ前の記事に引き続き「言語処理100本ノック 2015」の「第1章: 準備運動」、05〜09。

05. n-gram

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

n-gramについてはWikipediaをご参照のこと。
今回もスライスを使って1行で記載してみました。

def func05(s, n):
    """
    >>> func05('ABCD', 2)
    ['AB', 'BC', 'CD', 'D']
    >>> func05(['ABC', 'DEF', 'GHI', 'JKL'], 2)
    [['ABC', 'DEF'], ['DEF', 'GHI'], ['GHI', 'JKL'], ['JKL']]
    """
    return [s[i:i + n] for i in range(len(s))]

これを

    s05 = 'I am an NLPer'
    print('05: 単語bi-gram: ' + str(func05(s05.split(), 2)))
    print('05: 文字bi-gram: ' + str(func05(s05, 2)))

のように呼び出すと

05: 単語bi-gram: [['I', 'am'], ['am', 'an'], ['an', 'NLPer'], ['NLPer']]
05: 文字bi-gram: ['I ', ' a', 'am', 'm ', ' a', 'an', 'n ', ' N', 'NL', 'LP', 'Pe', 'er', 'r']

という形で出力されます。
こう見るとpythonのスライスってかなり強力ですね。

06. 集合

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

1つ上の課題で作ったn-gram取得関数を使って、以下のような感じですね。

    s06_x = set(func05('paraparaparadise', 2))
    s06_y = set(func05('paragraph', 2))
    print('06: 和集合: ' + str(s06_x | s06_y))
    print('06: 積集合: ' + str(s06_x & s06_y))
    print('06: 差集合: ' + str(s06_x - s06_y))
    print("06: Xの中に'se'があるか: " + str('se' in s06_x))
    print("06: Yの中に'se'があるか: " + str('se' in s06_y))

集合演算は感覚通りの演算子で求められるわけですね。非常に便利。
出力はこんな感じになります。

06: 和集合: {'e', 'ad', 'ar', 'ph', 'is', 'gr', 'ap', 'pa', 'di', 'ra', 'ag', 'h', 'se'}
06: 積集合: {'ap', 'ar', 'pa', 'ra'}
06: 差集合: {'e', 'ad', 'se', 'is', 'di'}
06: Xの中に'se'があるか: True
06: Yの中に'se'があるか: False

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

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

これは簡単ですね。

def func07(x, y, z):
    """
    >>> func07(12, '気温', 22.4)
    '12時の気温は22.4'
    """
    return '{0}時の{1}は{2}'.format(x, y, z)

08. 暗号文

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

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

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

仕様の通り愚直に実装してみました。

def cipher(s):
    """
    >>> cipher('AaBbCc')
    'AzByCx'
    """
    return ''.join([chr(219 - ord(x)) if str.islower(x) else x for x in s])

「暗号化・復号化せよ」に対しては

    s08 = cipher('AaBbCc')
    print('08: 暗号: ' + s08)
    print('08: 復号: ' + cipher(s08))

とすると、

08: 暗号: AzByCx
08: 復号: AaBbCc

のような形で出力されます。

09. Typoglycemia

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

Typoglycemiaって知らない単語だったのですが「タイポグリセミア現象」で調べてみると、どうも「単語の最初と最後が正しければ、その間の文字の順番がどうであれ読めてしまう」ということらしいです。
実装に関しては以下の通り。

def func09_shuffle(s):
    if (len(s) <= 4):
        r = s
    else:
        m = list(s[1:-1])
        random.shuffle(m)
        r = s[0] + ''.join(m) + s[-1]

    return r


def func09(s):
    return ' '.join([func09_shuffle(x) for x in s.split()])

func09では入力された文字列を空白文字で分割、それぞれの単語をfunc09_shuffleに渡し、結果を空白区切りで接続する、という作りにしました。
func09_shuffleは文字列長が4以下ならそのまま、5文字以上なら先頭と最後以外をランダムにシャッフル、という作りです。ここでもスライス大活躍です。
ランダムなので結果は一定ではないですが"I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."を渡した結果は

I cndl'uot bivelee that I cluod alltcauy uetdnasrnd what I was renidag : the peohemannl power of the hmaun mind .

という形で、やっぱりなんとなく読めてしまうという…(笑)

スポンサーリンク

フォローする

スポンサーリンク