良すぎた点数
あるチームが、取り置いた行でモデルを試します。「10回中9回、当たります」と言われました。実際に使うと、10回中7回しか当たりません。
モデルに誤りはありませんでした。テストの行が、本当は新しくなかったのです。点数が良すぎるときは、まず、モデルがすでに何を見たかを疑います。
このレッスンのゴール
メモ
テスト用データをきれいに保ち、情報が漏れたことに気づける。
キーワード
| ことば | いみ |
|---|---|
| テスト用データ | 取り置いて、最後に1回だけ見る行 |
| 検証用データ | モデルや設定を選ぶために使う行 |
| データ漏れ | テストの情報や答えが、テストの前にモデルへ届くこと |
| 重複 | 2回以上出てくる行 |
| 基準 | ごく単純な当て方の点数。比べるために使う |
学生が入力するセルは、このプレビューでは空白です。
3つのデータ、3つの役目
前のレッスンでは、検証用データを取り置きました。いつ止めるか、どの設定にするかを決めるために、何度も見ました。
見るたびに、少しずつ新しさが減ります。そこで慎重なチームは、3つ目のテスト用データを取り置きます。使うのは最後の1回だけで、報告する点数に使います。
例: 1年を3つに分ける
| データ | 割合 | 日数 | 使い道 |
|---|---|---|---|
| 学習用データ | 60パーセント | 219 | 重みを決める |
| 検証用データ | 20パーセント | 73 | モデルと設定を選ぶ |
| テスト用データ | 20パーセント | 73 | 最後の、ただ1つの正直な点数 |
学生が入力するセルは、このプレビューでは空白です。
3つの大きさを計算する
docker exec jupyter python3 -c "print(int(365 * 0.6), int(365 * 0.2), 365 - int(365 * 0.6) - int(365 * 0.2))"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
データ漏れ: テストが新しくない
データ漏れとは、テストの前に、モデルがテストの情報を見てしまうことです。いちばん簡単なのは重複です。同じ行が、学習用とテスト用の両方にあります。
行を覚えるだけのモデルは、そうなると立派に見えます。覚えるだけのモデルで、確かめましょう。
覚えるだけのモデル
# 8日分: (気温, 雨) と、その日が忙しかったか静かだったか。
days = [
((3, 0), "静か"), ((8, 0), "忙しい"), ((12, 2), "静か"), ((15, 0), "忙しい"),
((18, 0), "忙しい"), ((9, 5), "静か"), ((21, 0), "忙しい"), ((6, 3), "静か"),
]
train = days[:6]
fresh = days[6:]
copies = days[:2] + days[6:]
def memoriser(day):
# 学習した日を、そのまま覚えます。知らない日は "静か" と答えます。
for known, label in train:
if known == day:
return label
return "静か"
def score(rows):
right = 0
for day, label in rows:
if memoriser(day) == label:
right = right + 1
return right / len(rows)
print("学習に使った日:", score(train))
print("新しい2日:", score(fresh))
print("コピー2日と新しい2日:", score(copies))
# どの点数を信じますか。新しい日を1つ変えて、もう一度 Run しましょう。
本物の表で、同じテスト
次は、ラボの自転車の貸出で同じことをします。最近傍のモデルは、いちばん近い既知の日のラベルで答えるので、丸暗記に近いモデルです。忙しい日は、貸出が300以上の日です。
まず、短いスクリプトをラボに書きます。honest、copies、answer のどれか1語を受け取ります。
スクリプトをラボに書く
docker exec jupyter sh -c "printf '%s\n' 'import sys' 'import pandas as pd' 'from sklearn.model_selection import train_test_split' 'from sklearn.neighbors import KNeighborsClassifier' '' 'hires = pd.read_csv(\"hires.csv\")' 'way = sys.argv[1]' 'if way == \"copies\":' ' hires = pd.concat([hires, hires], ignore_index=True)' 'columns = [\"temp_c\", \"rain_mm\"]' 'if way == \"answer\":' ' columns = columns + [\"hires\"]' 'label = hires[\"hires\"] >= 300' 'X_train, X_test, y_train, y_test = train_test_split(hires[columns], label, test_size=0.25, random_state=1)' 'model = KNeighborsClassifier(n_neighbors=1).fit(X_train, y_train)' 'print(way, \"学習した日:\", round(model.score(X_train, y_train), 3), \"取り置いた日:\", round(model.score(X_test, y_test), 3))' > steps/leak.py"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
正直に実行する
docker exec jupyter python3 steps/leak.py honestここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
毎日を2回書いてから、分ける
docker exec jupyter python3 steps/leak.py copiesここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
答えを教えてしまう列
もう1つのよくある漏れは、答えそのもの、または後からしか分からないことを持つ列です。返金を予測する表にある返金の印が、その例です。出来事のあとで足した合計も同じです。
ラボでは、hires がラベルの元の数です。それを入力に入れて、見てみましょう。
モデルに hires の列を渡す
docker exec jupyter python3 steps/leak.py answerここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
よくある間違い
注意
点数が高いと、よいモデルだと思う人が多いです。テストが簡単だっただけかもしれません。取り置いた行で満点なら、祝う前に、漏れを探します。どの点数も基準と比べます。たとえば、いつも「静か」と答える当て方です。
例: 3つの漏れと確かめ方
| 何が起きたか | なぜ漏れか | 確かめ方 |
|---|---|---|
| 毎日を2回書いてから分けた | テストの行に、学習用の双子がいる | テストの行のうち、学習用にもある行を数える |
| hires から作ったラベルを、hires の列で予測した | 入力に答えが入っている | 各列について、答えより前に分かるかを問う |
| 10個試して、最良のテストの点数を報告した | テストを選ぶために使った | 検証で選び、テストは1回だけにする |
学生が入力するセルは、このプレビューでは空白です。
さらに: 自分のノートブックで
ラボの hires.csv と、自分のモデルを使います。学習した日と取り置いた日の点数を書きます。
次に、漏れそうな列を1つ足して、もう一度実行します。点数はどれだけ動きますか。本当に予測が必要な日に、その列が手に入らない理由を、1文で書きます。