Quibako Note

Questions unveiled invite brilliant and keen observation

自然言語処理100本ノック2020(Rev 2)の記録 Chapter 1

自然言語処理100本ノック2020(Rev 2)の記録(Python 3.11)

Chapter 1 準備運動

00. 文字列の逆順

文字列”stressed”の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.
string = "stressed"
print(string[::-1])
desserts

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

「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.
string = "パタトクカシーー"
print(string[::2])
パトカー

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

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

print(''.join(
  map(lambda x, y: x+y, str1, str2)
))
パタトクカシーー

03. 円周率

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

メモ

当初splitで分けようとしたが、スペースの他に”,.”も区切り文字扱いにしないと円周率にならない。 末尾にも”.”があって空白文字→0がリスト末尾に入ってしまうので、単語を正規表現で検索(re.findall)して字数カウントする方式にした。

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

print([
  len(m)
  for m in re.findall(r'[\w]+', string)
])
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

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文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.
string = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

# decompose string into word list
words = [ m for m in re.findall(r'[\w]+', string) ]

print({
  word[:1] if Z in [1, 5, 6, 7, 8, 9, 15, 16, 19] else word[:2] : Z
  for Z, word in enumerate(words, start=1)
})
{'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}

05. n-gram

与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,”I am an NLPer”という文から単語bi-gram,文字bi-gramを得よ.
def ngram(n, seq):
  for i in range(len(seq)-n+1):
    yield seq[i:i+n]


string = "I am an NLPer"
bg_word = list(ngram(2, re.findall(r'[\w]+', string)))
bg_char = list(ngram(2, string))

print(f"word bi-gram: {bg_word}")
print(f"character bi-gram: {bg_char}")
word bi-gram: [['I', 'am'], ['am', 'an'], ['an', 'NLPer']]
character bi-gram: ['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に含まれるかどうかを調べよ.
str1 = "paraparaparadise"
str2 = "paragraph"

X = set(ngram(2, str1))
Y = set(ngram(2, str2))

print(f"X : {X}")
print(f"Y : {Y}")
print(f"X|Y :{X.union(Y)}")
print(f"X&Y :{X.intersection(Y)}")
print(f"X-Y :{X.difference(Y)}")

print(f"bi-gram 'se' is in X : {'se' in X}")
print(f"bi-gram 'se' is in Y : {'se' in Y}")
X : {'ar', 'is', 'ad', 'ap', 'di', 'se', 'ra', 'pa'}
Y : {'ar', 'ap', 'ag', 'ph', 'ra', 'gr', 'pa'}
X|Y :{'ar', 'is', 'ad', 'ap', 'ag', 'di', 'ph', 'se', 'ra', 'gr', 'pa'}
X&Y :{'ap', 'ar', 'ra', 'pa'}
X-Y :{'ad', 'di', 'is', 'se'}
bi-gram 'se' is in X : True
bi-gram 'se' is in Y : False

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

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


print(tempgen(12, "気温", 22.4))
12時の気温は22.4

08. 暗号文

与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.
  • 英小文字ならば(219 - 文字コード)の文字に置換
  • その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ.
def cipher(s):
  sm = re.compile('[a-z]')
  return ''.join([
    chr(219-ord(l)) if sm.match(l) else l
    for l in s
  ])


string = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
print(cipher(string))
Nld I mvvw z wirmp, zoxlslorx lu xlfihv, zugvi gsv svzeb ovxgfivh rmeloermt jfzmgfn nvxszmrxh.

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

def typoglycemia(string):
  shuffle_inner = lambda w : w[:1] + \
                             ''.join(random.sample(w[1:-1], len(w[1:-1]))) + \
                             w[-1:]

  return ' '.join([
    shuffle_inner(word) if len(word) > 4 else word
    for word in string.split()
  ])


string = "I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
print(typoglycemia(string))
I cl’odnut bliveee that I cloud atlulacy udstnneard what I was raiendg : the pehnemnoal pewor of the haumn mind .