Help us understand the problem. What is going on with this article?

【言語処理100本ノック 2020】第1章: 準備運動

はじめに

自然言語処理の問題集として有名な言語処理100本ノックの2020年版が公開されました。
この記事では、以下の第1章から第10章のうち、「第1章: 準備運動」を解いてみた結果をまとめています。

事前準備

解答にはGoogle Colaboratoryを利用しています。
Google Colaboratoryのセットアップ方法や基本的な使い方は、こちらの記事が詳しいです。
なお、以降の解答の実行結果を含むノートブックはgithubにて公開しています。

第1章: 準備運動

00. 文字列の逆順

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

スライスは[開始位置:終了位置:移動幅]を指定して文字列を抽出します。このとき、開始位置を省略すると先頭から、終了位置を省略すると末尾までの範囲となります。また、移動幅にマイナスを指定すると、終了位置から順番に抽出されます。

str = 'stressed'
ans = str[::-1]  # 「先頭」から「末尾」まで「逆順の移動幅1」で

print(ans)
出力
desserts

Pythonで文字列を抽出

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

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

str = 'パタトクカシーー'
ans = str[::2]  # 「先頭」から「末尾」まで「移動幅2」で

print(ans)
出力
パトカー

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

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

str1 = 'パトカー'
str2 = 'タクシー'
ans = ''.join([i + j for i, j in zip(str1, str2)])

print(ans)
出力
パタトクカシーー

Python, zip関数の使い方: 複数のリストの要素をまとめて取得
Pythonリスト内包表記の使い方
Pythonで文字列を連結・結合

03. 円周率

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

import re

str = 'Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.'
str = re.sub('[,\.]', '', str)  # ,と.を除去
splits = str.split()  # スペースで区切って単語ごとのリストを作成
ans = [len(i) for i in splits]

print(ans)
出力
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

Pythonで文字列を置換
Pythonで文字列を分割
Pythonのlen関数で様々な型のオブジェクトのサイズを取得

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

str = 'Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.'
splits = str.split()
one_ch = [1, 5, 6, 7, 8, 9, 15, 16, 19]  # 1文字を取り出す単語の番号リスト
ans = {}
for i, word in enumerate(splits):
  if i + 1 in one_ch:
    ans[word[:1]] = i + 1  # リストにあれば1文字を取得
  else:
    ans[word[:2]] = i + 1  # なければ2文字を取得

print(ans)
出力
{'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}

Pythonのfor文によるループ処理
Python, enumerateの使い方: リストの要素とインデックスを取得
Pythonのif文による条件分岐の書き方
Pythonで辞書を作成するdict()と波括弧、辞書内包表記

05. n-gram

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

ここでは、[lst[i:] for i in range(n)]で、1要素目始まり、2要素目始まり、…、n要素目始まりの要素列のリストを作成し、それらをzip関数に渡して前から順番に要素を抽出することで、連続するn要素からなる組を作っています。
なお、[lst[i:] for i in range(n)]の結果は1つのリストであるため、前に*をつけることでリストを展開し、それぞれの要素列に分けた上でzip関数に渡す必要があります。

def ngram(n, lst):
  # ex.
  # [str[i:] for i in range(2)] -> ['I am an NLPer', ' am an NLPer']
  # zip(*[str[i:] for i in range(2)]) -> zip('I am an NLPer', ' am an NLPer')
  return list(zip(*[lst[i:] for i in range(n)]))

str = 'I am an NLPer'
words_bi_gram = ngram(2, str.split())
chars_bi_gram = ngram(2, str)

print('単語bi-gram:', words_bi_gram)
print('文字bi-gram:', chars_bi_gram)
出力
単語bi-gram: [('am', 'an'), ('I', 'am'), ('an', 'NLPer')]
文字bi-gram: [('I', ' '), (' ', 'N'), ('e', 'r'), ('a', 'm'), (' ', 'a'), ('n', ' '), ('L', 'P'), ('m', ' '), ('P', 'e'), ('N', 'L'), ('a', 'n')]

Pythonで関数を定義・呼び出し

06. 集合

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

前問で作成した関数ngramを利用します。また、返り値をset型に変換することで、重複があれば削除され、集合として扱うことができるようになります。

str1 = 'paraparaparadise'
str2 = 'paragraph'
X = set(ngram(2, str1))
Y = set(ngram(2, str2))
union = X | Y
intersection = X & Y
difference = X - Y

print('X:', X)
print('Y:', Y)
print('和集合:', union)
print('積集合:', intersection)
print('差集合:', difference)
print('Xにseが含まれるか:', {('s', 'e')} <= X)
print('Yにseが含まれるか:', {('s', 'e')} <= Y)
出力
X: {('a', 'r'), ('a', 'p'), ('s', 'e'), ('p', 'a'), ('r', 'a'), ('i', 's'), ('d', 'i'), ('a', 'd')}
Y: {('p', 'h'), ('a', 'r'), ('a', 'p'), ('p', 'a'), ('g', 'r'), ('r', 'a'), ('a', 'g')}
和集合: {('p', 'h'), ('a', 'r'), ('a', 'p'), ('s', 'e'), ('p', 'a'), ('g', 'r'), ('r', 'a'), ('i', 's'), ('a', 'g'), ('d', 'i'), ('a', 'd')}
積集合: {('p', 'a'), ('r', 'a'), ('a', 'r'), ('a', 'p')}
差集合: {('d', 'i'), ('i', 's'), ('a', 'd'), ('s', 'e')}
Xにseが含まれるか: True
Yにseが含まれるか: False

Python, set型で集合演算

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

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

def generate_sentence(x, y, z):
  print(f'{x}時のとき{y}{z}')

generate_sentence(12, '気温', 22.4)
出力
12時のとき気温は22.4

Python, formatで書式変換

08. 暗号文

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

def cipher(str):
  rep = [chr(219 - ord(x)) if x.islower() else x for x in str]

  return ''.join(rep)

message = 'the quick brown fox jumps over the lazy dog'
message = cipher(message)
print('暗号化:', message)
message = cipher(message)
print('復号化:', message)
出力
暗号化: gsv jfrxp yildm ulc qfnkh levi gsv ozab wlt
復号化: the quick brown fox jumps over the lazy dog

PythonでUnicodeコードポイントと文字を相互変換
Pythonで大文字・小文字を操作する文字列メソッド一覧

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 shuffle(words):
  result = []
  for word in words.split():
    if len(word) > 4:  # 長さが4超であればシャッフル
      word = word[:1] + ''.join(random.sample(word[1:-1], len(word) - 2)) + word[-1:]
    result.append(word)

  return ' '.join(result)

words = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
ans = shuffle(words)

print(ans)
出力
I conuld't bivelee that I cloud actlaluy utnensardd what I was radineg : the pheanomnel peowr of the hmaun mind .

Pythonでリストの要素をシャッフル

おわりに

言語処理100本ノックは自然言語処理そのものだけでなく、基本的なデータ処理や汎用的な機械学習についてもしっかり学ぶことができるように作られています。
オンラインコースなどで機械学習を勉強中の方も、とても良いアウトプットの練習になると思いますので、ぜひ挑戦してみてください。

全100問の解答へ

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away