Python初心者必見!自然言語処理100本ノック2025 第1章「準備運動」(#00-#09)を解説

自然言語処理 100本ノック解説第一章 プログラミング


始める前に


今回から「自然言語処理100本ノック」の解説を章ごとに行っていきたいと思います。


できるだけ、Python初心者向けでも理解できるように解説していこうと思うので、


これからよろしくお願いします!


第1章: 準備運動 — 言語処理100本ノック 2025



第1章: 準備運動

00. パタトクカシーー


2つの文字列の前からインデックスを指定して、ansに格納していきます。


一応、頻出のrangeについて復習すると、range(start, stop, step)を基本として、


start以上stop未満を指定step数で連続した整数を作ります。


今回の場合は、len(x)が4であるため、range(4)となり、0,1,2,3の整数を作ります。


01. タクシー

if i % 2 ==0 など、いくつか方法がありますが、Pythonにおいてスライスが一番効率的です。


使い方は[start:stop:step]です。


rangeの引数と同じように使います。


1::2では、stopが省略されています。このように省略されていると、文字列の末尾(最後まで)が自動的に指定されます。


つまり、インデックスが1の「タ」から「ク」、「シ」、「ー」とスライスされます。


02. 文字列の逆順


01と同様にスライスの問題です。

startとstopが省略されています。つまり、これは最初から最後までの文字を指定しています。


そして、stepが-1となっていますが、これは逆の順番でスライスしていきます。

よって、d→e→s→s→e→r→t→sでdessertsとなります。


03. 円周率


解答① for文とリストを別々


解答② リストの中にfor文を入れる


文章から余分な,.を取り除き、単語ごとにリスト化します。その後、単語の長さを数えリストに格納します。

リスト内包表記


for文からリストの使い方は2つあると思います。


通常の使い方の①では、ansを[]でリストとして、宣言してからfor文の中でその値をappendで格納しています。

対して、②ではans=[len(word) for word in sentence.split()]のように、右側でfor文を使い、要素を取り出して、左側で値を返してみます。

このような方法は、リスト内包表記と呼ばれます。

使い方: [返したい値 for 要素 in リスト if 要素の条件]


replace()の使い方


文字列.replace(置き換え前, 置き換え後, 置き換える回数)

replace(“.”,””)とreplace(“,”,””)のように、コンマとカンマを””で置き換えることでその文字をなくすことができます。

split()の使い方


文字列.split(区切り文字, 最大分割数)

split()のようにデフォルトでは、空白文字で分割条件なくリスト化します。


(前)

‘Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.’

(後)

[‘Now’,’I’,’need’,’a’,’drink,’,’alcoholic’,’of’,’course,’,’after’,’the’,’heavy’,’lectures’,’involving’,’quantum’,’mechanics.’]


04. 元素記号

解答①自作関数を使用して、タプルリストから辞書型を作る

解答②自作関数を使用せず、そのまま辞書を作る

単語をそれぞれリスト化して、指定のインデックスに対しては先頭一文字、それ以外では先頭2文字と先頭からの番号を使って辞書を作成します。


解説①では、リスト内包表記を使用しているのに対して、解答②では、辞書内包表記を使っています。

どちらも内包表記を使用していて、大きな違いはありませんが、辞書型への変換に注意が必要です。

dict()の使い方


04の解答では、キーと値のペアから作っています。


例えば、

pairs = [("a", 1), ("b", 2), ("c", 3)]
d = dict(pairs)
print(d)

このコードでは、リストの中に(キー、値)が入っています。

このリストをdictの引数に入れることで辞書を作ることができます。

enumerateの使い方

for index, value in enumerate(list, start=0):

startはインデックスの開始位置となります。インデックスとその値をindex,valueに代入します。


enumerate(sentence,1)では、1を開始位置とするので、index=1 value=Hi ,index=2 value=He,index=3 value=Lied…のように続いていきます。


05. n-gram

それぞれ、単語と文字の前処理をして、リスト化したものをn_gramという関数に代入します。

特に、文字tri-gramのlist(sentence.replace(” “,””))はひとつの大きな単語にしてから、list()によりひとつずつの文字をリスト化します。

n_gramとは

n_gramとは、「n個の連続した要素を取り出す方法」です。

そして、文字n-gram単語n-gramの二つがあります。


実際に今回のケースに当てはめるとわかりやすいです。

文字tri-gramの場合

[“I”,”a”,”m”,”a”,”n”,”N”,”L”,”P”,”e”,”r”]という文字リストを作ります。


文字tri-gramとは、「3個の連続した文字を取り出す」ということなので、

“I”と”a”と”m”,  ”a”と”m”と”a”,  ”m”と”a”と”n”,  ”a”と”n”と”N”,  ”n”と”N”と”L”,  ”N”と”L”と”P”,  “L”と”P”と”e”,  ”P”と”e”と”r”

となります。


単語bi-gramの場合

[“I”, “am”, “an”, “NLPer”]という単語リストを作ります。

単語bi-gramとは、「2個の連続した単語を取り出す」ということなので、

“I”と”am”, “am”と”an”, “an”と”NLPer”

となります。

n_gram関数の作り方

n_gram関数の中にある、[“”.join(sentence[i:i+n]) for i in range(0,len(sentence)-n+1)]を分解すると、

“”.join(sentence[i:i+n]) とfor i in range(0,len(sentence)-n+1)の二つに分解できます。

“区切り文字”.join(リストやタプル)は、リストの要素を指定の区切り文字を使って合体させます。

つまり、””.join(sentence[i:i+n]) はn個のスライスした要素リストを区切りなしでくっつけます。


次に、for i in range(0,len(sentence)-n+1)]でも、len(sentence)-n+1)に注目してほしいです。


もし、すべてのリストを3個ずつずらして取得した場合、最後の2つは2つの要素と1つの要素のみしか取得できません。


これを対策するために、len(sentence)-n+1をすることですべてn個を取得できます。


len(sentence)-n+1より、len(sentence)-(nー1)の方がイメージしやすいと思います。

最後のn-1個はn未満になってしまうため、その分だけ引いているだけです。



06. 集合

05で書いたn_gramを使います。


文字列をlist()により、文字をリスト化しn_gram関数に渡して、文字bi-gramを作成します。


その後、set()により、リストを集合にして、和、積、差の集合を調べていきます。



和集合 (全部) A ∪ B → A | B

積集合 (共通) A ∩ B → A & B

差集合 (片方のみ)A - B  → A – B


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


変数の埋め込みが今回のポイントです。


埋め込みの方法として3つありますが、以下は参考程度にどうぞ。

① f文字列(f-string)

f'{x}時の{y}は{z}’のようにそのまま埋め込みます。

format() メソッドを使う方法

‘{}時の{}は{}’.format(x,y,z)のように後ろから変数を埋め込みます。

③ %(パーセント)演算子

‘%d時の%sは%d’%(x,y,z)のように、%sや%dを指定して、その型に合った変数を埋め込みます。


08. 暗号文

「英小文字ならば (219 – 文字コード) のASCIIコードに対応する文字に置換」とは、a~z の文字を逆順に置き換えます。((219-文字コード)の-はマイナスです))


aの文字コードは97、zの文字コードは122です。

この公式に当てはめると、

219-a=219-97=122となり、zの文字コード

219-z=210-122=97となり、aの文字コード

になります。


よって、文字コード変換はord(c)で取得できるため、

219-ord(c)の値を計算し、chr(c)で文字コードから文字への変換を行います。

文字列の文字イテレーションから文字列の再構築方法

今回は文字列をfor文を使用し、文字のリストを作成後、join()でくっつけました。


他の方法として、new_sentence=””を作った後に、new_sentence+=cのような方法があります。


しかし、これは長い文字列では効率が悪く遅くなります。

この理由は、文字列は不変であるため、一度作った文字列に追加や削除はできないから、新しい文字列としてメモリに新しく作られてしまうのです。



09. Typoglycemia

random.sampleを使用することで、中間のを入れ替えることができます。

random.sample(リスト,数)でリストから指定した数の要素を取得します。


そして、returnの箇所でword[0]とword[-1]は文字なので、リスト化しくっつけます。


余談ですが、私は先にrandom.shuffleを使用して以下のように実装しました

def random_word(word):
  if len(word) <=4:
    return word
  else:    
    word=list(word)
    new_word=word[:]#コピー
    random_list=[i for i in range(1,len(word)-1)]
    random.shuffle(random_list)
    for i ,v in enumerate(random_list,1):
      new_word[i]=word[v]
    return "".join(new_word)

この場合でも、問題なく行えましたが、若干わかりずらいコードになってしまいました。


まとめ


私は近頃JavaScriptやGo,C++をやって、Pythonを避けていました。しかし、今回の準備運動でかなりPythonの独特な感じを思い出すことができたので、うるおぼえな方にもおすすめします。


次回は、第2章: UNIXコマンドの解説に進んでいきます。

コメント

タイトルとURLをコピーしました