WordPress.com で次のようなサイトをデザイン
始めてみよう

言語処理100本ノックをやってみた 第1章②

はじめに 言語処理の問題集として有名な、言語処理100本ノックを解いた回答をまとめてます。今回は前回の続きになります…

はじめに

言語処理の問題集として有名な、言語処理100本ノックを解いた回答をまとめてます。
今回は前回の続きになります。

第1章:準備運動

05. n-gram

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

phrase2 = "I am an NLPer"


def n_gram(phrase, n, word=True):
    outcome_list = []
    if word == True:
        phrase_list = phrase.split()
        for i in range(len(phrase_list) - n + 1):
            outcome_list.append(phrase_list[i:i+n])
        return outcome_list
    else: #incluede or exclude space?
        phrase = phrase.replace(" ", "")
        for i in range(len(phrase) - n + 1):
            outcome_list.append(phrase[i:i+n])
        return outcome_list

    
print(n_gram(phrase2, 2, word=True))  
print(n_gram(phrase2, 2, word=False))  
>[['I', 'am'], ['am', 'an'], ['an', 'NLPer']]
>['Ia', 'am', 'ma', 'an', 'nN', 'NL', 'LP', 'Pe', 'er']

N-gramに関する問題です。
N-gramについては以下の記事を参照してください。

自然言語解析:「N-gram」について

このN-gramは英語を想定して作成しています。文字単位か単語単位かを指定して、それぞれについて、空のリストに分割された文字列を追加しています。

06. 集合

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

x = "paraparaparadise"
y = "paragraph"

X = n_gram(x, 2, word=False)
Y = n_gram(y, 2, word=False)


def set_func(z):
    lst = set()
    for i in range(len(z)):
        lst.add(z[i])
    return lst


X = set_func(X)
Y = set_func(Y)

X_or_Y = X | Y
X_and_Y = X & Y
X_but_Y = X - Y

print (X_or_Y, X_and_Y, X_but_Y)

print("se is in X? :", "se" in X)
print("se is in Y? :", "se" in Y)
>{'pa', 'di', 'se', 'ap', 'ad', 'ar', 'is', 'ag', 'ph', 'ra', 'gr'} {'ar', 'pa', 'ap', 'ra'} {'ad', 'is', 'di', 'se'}
>se is in X? : True
>se is in Y? : False

ポイント

set( ), { }
setオブジェクト
・集合を表現するオブジェクト
・集合の演算に用いることができる

setオブジェクトの用例
add( ):オブジェクトに要素を追加
|, union( ):和集合、A∪B
&, intersection( ):積集合、A∩B
-, difference( ):差集合、A∩‾B(Bの上に棒線)

前の問題で作成したN-gramを利用しています。
あとは、それぞれの単語のbigramをsetオブジェクトにして、和集合・積集合・差集合をとっています。

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

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

x1 = 12
y1 = "気温"
z1 = 22.4


def template(x, y, z):
    return "{}時の{}は{}".format(x, y, z)


print(template(x1, y1, z1))
>12時の気温は22.4

ポイント

"{ }".format( )
format( )関数
・文字列に変数を埋め込める関数

これは実にシンプルです。format( )関数を用いてます。

08. 暗号文

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

def cipher(word, encryption=True):
    coded = ""
    decoded = ""
    alpha = "abcdefghijklmnopqrstuvwxyz"
    if encryption == True:
        for x in word:
            if x in alpha:
                coded += (chr(219 - ord(x)))
            else:
                coded += x
        return coded
    else:
        for x in word:
            if x in alpha:
                decoded += chr(219 - ord(x))
            else:
                decoded += x
        return decoded
                
    
print(cipher("abdあ"))
print(cipher("zywあ", encryption=False))
>zywあ
>abdあ

ポイント

ord( )
chr( )
ord( )関数
・入力された文字のアスキーコードをreturnする関数

chr( )関数
・入力されたアスキーコードに対応する文字をreturnする関数

暗号化する場合は、encryption=True、複合化する場合は、encryption=Falseに設定するようにしています。

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


phrase2 = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."


def shuffle_func(phrase):
    lst = phrase.split()
    shffl_lst = []
    for word in lst:
        if len(word) <=4:
            shffl_lst.append(word)
        else:
            cap_lst = []
            for i in range(1, len(word) - 1):
                cap_lst.append(word[i])
            random.shuffle(cap_lst)
            cap_shuffled = ""
            for x in cap_lst:
                cap_shuffled += x
            word2 = word[0] + cap_shuffled + word[len(word) - 1]
            shffl_lst.append(word2)
    shuffled = shffl_lst[1]
    for i in range(1, len(shffl_lst)):
        shuffled = shuffled + " " + shffl_lst[i]
    return shuffled
  
    
print(shuffle_func(phrase2))
>c'duolnt c'duolnt beleive that I colud atullcay udrnatsned what I was rdeniag : the pahnenoeml pweor of the hmaun mind .

ポイント

random
randomモジュール
・標準ライブラリに備えられているモジュール
・ランダムな数値の生成に使用する

random.shuffle( ):入力されたリストの中身の順番をランダムに入れ替えてreturnする関数
random.random( ):0以上1未満の浮動小数点数をreturnする関数

まず、与えられた単語列を単語で分割してリストに入れます。
その後、単語の長さが5以上の場合は上記のrandom.shuffle( )関数を用いて文字列を並び替えています。

以上、第1章の問題の回答でした。次回の投稿では第2章について扱おうかと思います。

言語処理100本ノックをやってみた 第1章①

はじめに 言語処理の問題集として有名な、言語処理100本ノックを実施していこうと思います。基本的に1章の内容を1投稿または2投稿程度でまとめていこうかと思います。 第1章…

はじめに

言語処理の問題集として有名な、言語処理100本ノックを実施していこうと思います。
基本的に1章の内容を1投稿または2投稿程度でまとめていこうかと思います。

第1章:準備運動

00. 文字列の逆順

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

word1 = "stressed"


def reverse_func(word):
    word_list = []
    for i in range(len(word1)):
        word_list.append(word[i])
    reverse_word = ""
    for i in range(len(word1)):
        reverse_word += word_list.pop()
    return reverse_word


print(reverse_func(word1))
>desserts

何となく関数の形で回答を作成しました。
空のリストに文字を順番に足した後に、リストの最後から順に取り出して逆順の文字列を生成しています。

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

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

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


def odd_num_word_func(word):
    odd_num_word = ""
    for i in range(0, len(word), 2):
        odd_num_word += word[i]
    return odd_num_word


print(odd_num_word_func(word2))
>パトカー

ポイント

range(start, stop, step)
start : インデックスの参照したい最初の値
stop : インデックスの参照したい最後の値+1
step : インデックスを何個おきに参照するか(デフォルトは1)

新しい空の文字列を作成して、forループを用いて文字を追加して生成しています。

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

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

word3 = "パトカー"
word4 = "タクシー"

def combine_word_func(word1, word2):
    combined_word = ""
    for i in range(len(word1)):
        combined_word = combined_word + word1[i] + word2[i]
    return combined_word


print(combine_word_func(word3, word4))
>パタトクカシーー

新しい空の文字列を作成して、forループを回して、各単語から文字を一文字ずつ読み込んで生成しています。
※文字列の長さが異なると機能しません

03. 円周率

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

sentence1 = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."

def word_length_func(sentence):
    sentence = sentence.replace(",", "")
    sentence = sentence.replace(".", "")    
    sentence_list = sentence.split()
    cap_num_list = []
    for word in sentence_list:
        cap_num_list.append(len(word))
    return cap_num_list
    
    
print(word_length_func(sentence1))
>[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

まず文章中の不要なカンマとピリオドを取り除いています。
その後、文章をスペースで分割してリスト化。
最後にリスト中の単語をforループで呼び出して、長さを空のリストに追加しています。

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

phrase1 = "Hi He Lied Because Boron Could Not Oxideze Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

def element_func(phrase):
    phrase = phrase.replace(".", "")
    phrase_list = phrase.split()
    num = [1, 5, 6, 7, 8, 9, 15, 16, 19]
    element_dic = {}
    for i in range(len(phrase_list)):
        if i + 1 in num:
            element_dic[phrase_list[i][:1]] = i + 1
        else:
            element_dic[phrase_list[i][:2]] = i + 1
    return element_dic


print(element_func(phrase1))
>{'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}

まず文章中の不要なピリオドを取り除いています。
その後、文章をスペースで分割してリスト化。
最後にリスト中の単語をforループで呼び出して、何番目の単語によって取得する文字数を変えて空のリストに追加しています。

05以降の問題は次回の投稿に掲載します。