届いたメッセージを自動で振り分ける
テキスト分類とは、文章を「迷惑」と「通常」のようなグループへ、自動で振り分けることです。単語を数えるだけで、かなりの仕事ができます。
レンタサイクル店に、宣伝のメッセージと、予約の連絡が混ざって届きます。過去のメッセージの単語を数えておけば、新しいメッセージを機械が振り分けられます。
このレッスンのゴール
メモ
単語の数を使って、文章を2つのグループに分類することができる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| 分類 | 文章をグループに振り分けること | |
| ラベル | 例につけた、正解のグループ名 | 迷惑、通常 |
| 学習データ | ラベルのついた、答えの分かっている例 | |
| 平滑化 | 回数に1を足して、確率が0になるのを避けること | |
| ナイーブベイズ | 語ごとの確率をかけて、グループを決める方法 | |
| 正解率 | 当たった数を、全部の数で割った値 |
学生が入力するセルは、このプレビューでは空白です。
学習データから、グループごとに語を数える
ラベルのついた例(学習データ)から、グループごとに、各語が何回出たかを数えます。迷惑なメッセージには「無料」が多く、通常のメッセージには「予約」が多い、というように。
数えた表が、そのまま分類のもとになります。
例: 4通のメッセージの語の回数
| 語 | 迷惑での回数 | 通常での回数 |
|---|---|---|
| 無料 | 2 | 0 |
| 当選 | 2 | 0 |
| クリック | 1 | 0 |
| 予約 | 0 | 2 |
| 変更 | 0 | 1 |
| お願い | 0 | 1 |
| 修理 | 0 | 1 |
| 語の総数 | 5 | 5 |
学生が入力するセルは、このプレビューでは空白です。
グループごとに語を数える
messages = [
["迷惑", ["無料", "当選", "無料"]],
["迷惑", ["当選", "クリック"]],
["通常", ["予約", "変更", "お願い"]],
["通常", ["修理", "予約"]],
]
label = "通常"
counts = {}
for item in messages:
if item[0] == label:
for word in item[1]:
if word in counts:
counts[word] = counts[word] + 1
else:
counts[word] = 1
print(counts)
# label を "迷惑" に変えて、もう一度実行してください。
語ごとの確率に1を足して出す
新しいメッセージの語ごとに、「その語がグループで出る確率」を出します。確率は、(その語の回数 + 1)÷(グループの語の総数 + 語彙の数)です。
1を足すのは、一度も出なかった語で確率が0になるのを避けるためで、平滑化と言います。この例の語彙は7語です。
確率を端末で出す
docker exec jupyter python3 -c "print((2 + 1) / (5 + 7), round(1 / 12, 3))"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
例: 語がグループで出る確率
| 語 | 迷惑での確率 | 通常での確率 |
|---|---|---|
| 無料 | 3 / 12 = 0.25 | 1 / 12 = 0.083 |
| 当選 | 3 / 12 = 0.25 | 1 / 12 = 0.083 |
| 予約 | 1 / 12 = 0.083 | 3 / 12 = 0.25 |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
一度も出なかった語の確率は、0でよいと考えがちです。0をかけると、ほかの語がどれだけ合っていても、全体が0になります。回数に1を足して、0を避けます。
確率をかけて、大きいほうを選ぶ
メッセージの語ごとの確率を、すべてかけます。かけた値が大きいグループが答えです。語が互いに関係ないと「素朴に」考えるので、ナイーブベイズと呼びます。
グループの割合も本来はかけますが、この例は2対2で同じなので、かけません。
例: 「無料 当選 予約」を分類する
| 語 | 迷惑の分子 | 通常の分子 |
|---|---|---|
| 無料 | 3 | 1 |
| 当選 | 3 | 1 |
| 予約 | 1 | 3 |
| かけた値 | 9 | 3 |
学生が入力するセルは、このプレビューでは空白です。
迷惑の点数を出す
# 迷惑のグループ: 語の総数は5、語彙は7語です。
counts = {"無料": 2, "当選": 2, "クリック": 1}
total = 5
vocab = 7
words = ["無料", "当選", "予約"]
score = 1.0
for word in words:
count = 0
if word in counts:
count = counts[word]
score = score * (count + 1) / (total + vocab)
print(round(score, 5))
# words を ["予約", "予約"] に変えて、もう一度実行してください。
正解率で、分類の良さを測る
作った分類を、ラベルが分かっている別のメッセージで試します。当たった数を全部の数で割った値が、正解率です。
4通のうち3通が当たれば、3 ÷ 4 で0.75です。学習に使った例では試さないでください。