アイソモカ

知の遊牧民の開発記録

開発記録 200304 Wed (100本ノック #073, Scikit-Learn インストールだけ / お魚の本 2章 カウントベース下準備)

言語処理100本ノック #073

# 73. 学習

72で抽出した素性を用いて,ロジスティック回帰モデルを学習せよ.

準備:scikit-learn をインストール

参考 👉 Installing scikit-learn — scikit-learn 0.22.1 documentation

$ pip install -U scikit-learn
    ...
Successfully installed joblib-0.14.1 scikit-learn-0.22.2

どうやって使うのかなと調べていたら、どうやらベクトルを食わせないといけないっぽい???(他の人の書いた答えの丸写しはしたくないなあと思って、他の人の書いた答えは見ていない)

たしか、お魚の本にベクトルの作り方が載っていたような気がするので、見てみよう。

お魚の本 (ゼロから作る Deep Learning自然言語処理編)

2.3 カウントベースの手法 (2.3.1 コーパスの下準備):正規表現が分からない

p.64 によれば、 re.split(r'(\W+)?', text) というように正規表現を使えば、単語単位の分割がスッキリできるはずが……

words = re.split(r'(\W+)?', text)
↓
['', None, 'y', None, 'o', None, 'u', ' ', '', None, 's', None, 'a', None, 'y', ' ', '', None, 'g', None, 'o', None, 'o', None, 'd', None, 'b', None, 'y', None, 'e', ' ', '', None, 'a', None, 'n', None, 'd', ' ', '', None, 'i', ' ', '', None, 's', None, 'a', None, 'y', ' ', '', None, 'h', None, 'e', None, 'l', None, 'l', None, 'o', '.', '', None, '']

なんか1文字ごとのぶつ切りにされてしまい、うまくいかない。 re — 正規表現操作 — Python 3.8.2 ドキュメント によると

\w Unicode 単語文字にマッチします。これはあらゆる言語で単語の一部になりうるほとんどの文字、数字、およびアンダースコアを含みます。

\W 単語文字ではない任意の文字にマッチします。これは \w の反対です。

とのことで、\w を使ったら良いのか?

words = re.split(r'(\w+)?', text)
# ↓
#['', 'you', '', None, ' ', 'say', '', None, ' ', 'goodbye', '', None, ' ', 'and', '', None, ' ', 'i', '', None, ' ', 'say', '', None, ' ', 'hello', '', None, '.', None, '']

さらに、

(…) 丸括弧で囲まれた正規表現にマッチするとともに、グループの開始と終了を表します。 + 直前の正規表現を 1 回以上繰り返したものにマッチさせる結果の正規表現にします。例えば ab+ は ‘a’ に 1 つ以上の ‘b’ が続いたものにマッチし、単なる ‘a’ にはマッチしません。 ? 直前の正規表現を 0 回か 1 回繰り返したものにマッチさせる結果の正規表現にします。例えば ab? は ‘a’ あるいは ‘ab’ にマッチします。

なんかよく分からない。 re.split(r'(\W+)?', text) は、「『単語文字ではない文字を1回以上繰り返したグループを0回か1回繰り返す』を区切り文字とする」???

? を抜いて、re.split(r'(\W+)', text) は、「『単語文字ではない文字を1回以上繰り返したグループ』を区切り文字とする」なら、

words = re.split(r’(\W+)’, text)
# ↓
#[‘you’, ‘ ‘, ‘say’, ‘ ‘, ‘goodbye’, ‘ ‘, ‘and’, ‘ ‘, ‘i’, ‘ ‘, ‘say’, ‘ ‘, ‘hello’, ‘.’, ‘’]

となり、無 '' と 空白 ' ' を除けば目当てのものが手に入りそう。ちなみに、逆の \w を使って、re.split(r'(\w+)', text) は、「『単語を1回以上繰り返したグループ』を区切り文字とする」なら、

words = re.split(*r*’(\w+)’, text)
# ↓
#[‘’, ‘you’, ‘ ‘, ‘say’, ‘ ‘, ‘goodbye’, ‘ ‘, ‘and’, ‘ ‘, ‘i’, ‘ ‘, ‘say’, ‘ ‘, ‘hello’, ‘.’]

'' が切られる位置が違うけど、だいたい同じ結果になる。

なんかもう困ったので、このリストから無 '' と 空白 ' ' を除くでいいか。

words = [w for w in re.split(r'(\w+)', text) if w not in ['', ' ']]
# ↓
#['you', 'say', 'goodbye', 'and', 'i', 'say', 'hello', '.']

とりあえず目当てのものは手に入った。

それから、

corpus = np.array([word_to_id[w] for w in words])

このリストの内包表記ってやつ、便利だなあ!(早速、リストから無 '' と 空白 ' ' を除くのに使った)