クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

質問に答えるアプリを試す

このレッスンのあとで: 質問に答えるアプリを、少数の質問と、答えに含まれるべき事実で試せる。

60分のレッスンコマンド6件JupyterLab データサイエンスラボ:pandas、Matplotlib、scikit-learn をブラウザーで

質問に答える店のアプリ

自転車の貸出店が、アプリを作ります。客が質問を打つと、アプリは店の答えの中からいちばん合う段落を探し、言語モデル(文章を作るプログラム)に渡して、返事の文章にしてもらいます。

アプリが違う段落を見つけると、モデルは、とても丁寧に、違う答えを書きます。このレッスンでは、探す部分を試します。ふつうのコードなので、モデルを呼ばずに採点できます。

このレッスンのゴール

メモ

質問に答えるアプリを、少数の質問と、答えに含まれるべき事実で試せる。

キーワード

ことばいみれい
検索質問に答えるのに役立つ文章を見つけること
期待する事実よい答えに必ず含まれるはずの短い言葉1200円
当たり率正しい文章が見つかった質問の割合
ありふれた2文字どの文章にもよく出て、手がかりにならない2文字の組
はずれ文章は見つかったが、期待する事実がない
答えなし何も合わなかったので、アプリが分からないと言う

学生が入力するセルは、このプレビューでは空白です。

2つの段階。試しやすいのは片方だけ

質問に答えるアプリの多くは、2段階です。まず検索で、質問に合う段落を選びます。次に、言語モデルが、その段落から返事を書きます。

モデルの返事は、実行のたびに変わるので、採点しにくいです。検索は毎回同じ結果なので、採点しやすいです。検索が間違えば、そのあとに正しいものはありません。

2文字ずつ区切って、共通を数える

日本語は、単語の間に空白がありません。そこで、文章を2文字ずつ区切ります。「お店は9時」なら、「お店」「店は」「は9」「9時」です。

質問の2文字の組のうち、段落にもあるものを数えます。数がいちばん多い段落が勝ちです。コードを Run して、数を読みましょう。

1つの質問の、共通する2文字を数える

コード: python
def pairs(text):
    for mark in "、。?! ":
        text = text.replace(mark, "")
    found = []
    for n in range(len(text) - 1):
        found.append(text[n:n + 2])
    return found

docs = [
    "お店は9時に開いて、18時に閉まります。月曜日から土曜日までです。",
    "自転車は1日1200円で、1時間は500円です。",
    "自転車は、町の3つの駐輪場のどこでも返せます。",
    "自転車がこわれたら、フレームの番号に電話してください。すぐ直します。",
    "ヘルメットは無料です。受付で声をかけてください。",
]
question = "1日いくらで借りられますか?"
for text in docs:
    shared = []
    for pair in pairs(question):
        if pair in pairs(text):
            shared.append(pair)
    print(len(shared), shared, "<-", text[:10])
# 質問を "会員になれますか?" に変えて、もう一度 Run しましょう。

テストの集まり: 質問と事実

アプリを採点するには、小さなテストの集まりが要ります。客が聞きそうな質問を並べ、それぞれに、正しい段落にある期待する事実を付けます。

見つかった段落に事実があれば当たりです。段落は見つかったのに事実がなければはずれです。何も合わなければ答えなしです。

店の5つの答えを書く

コマンド
docker exec jupyter sh -c "printf '%s\n' 'd1|お店は9時に開いて、18時に閉まります。月曜日から土曜日までです。' 'd2|自転車は1日1200円で、1時間は500円です。' 'd3|自転車は、町の3つの駐輪場のどこでも返せます。' 'd4|自転車がこわれたら、フレームの番号に電話してください。すぐ直します。' 'd5|ヘルメットは無料です。受付で声をかけてください。' > faq.txt"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

6つのテスト質問を書く

コマンド
docker exec jupyter sh -c "printf '%s\n' 'お店は何時に開きますか?|9時' '1日いくらで借りられますか?|1200円' '自転車はどこで返せますか?|3つの駐輪場' '自転車がこわれたらどうしますか?|番号に電話' '帽子は借りられますか?|無料' '会員になれますか?|無料' > questions.txt"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

採点のスクリプトを書く

コマンド
docker exec jupyter sh -c "printf '%s\n' 'import sys' '' '' 'def pairs(text):' '    for mark in \"、。?! \":' '        text = text.replace(mark, \"\")' '    found = []' '    for n in range(len(text) - 1):' '        found.append(text[n:n + 2])' '    return found' '' '' 'docs = []' 'for line in open(\"faq.txt\", encoding=\"utf-8\"):' '    docs.append(line.strip().split(\"|\")[1])' 'skip = []' 'if sys.argv[1] == \"skip\":' '    seen = {}' '    for text in docs:' '        done = []' '        for pair in pairs(text):' '            if pair not in done:' '                done.append(pair)' '                if pair in seen:' '                    seen[pair] = seen[pair] + 1' '                else:' '                    seen[pair] = 1' '    for pair in seen:' '        if seen[pair] >= 2:' '            skip.append(pair)' '    print(\"無視する2文字:\", len(skip), \"個\")' > steps/ask.py"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

採点のスクリプトの続きを書く

コマンド
docker exec jupyter sh -c "printf '%s\n' 'hit = 0' 'wrong = 0' 'none = 0' 'for line in open(\"questions.txt\", encoding=\"utf-8\"):' '    parts = line.strip().split(\"|\")' '    question = parts[0]' '    fact = parts[1]' '    asked = []' '    for pair in pairs(question):' '        if pair not in skip:' '            asked.append(pair)' '    best = \"\"' '    best_shared = 0' '    for text in docs:' '        shared = 0' '        for pair in asked:' '            if pair in pairs(text):' '                shared = shared + 1' '        if shared > best_shared:' '            best = text' '            best_shared = shared' '    if best == \"\":' '        none = none + 1' '        print(\"なし:\", question)' '    elif fact in best:' '        hit = hit + 1' '        print(\"当たり:\", question)' '    else:' '        wrong = wrong + 1' '        print(\"はずれ:\", question)' 'print(\"当たり\", hit, \"はずれ\", wrong, \"なし\", none, \"率\", round(hit / (hit + wrong + none), 2))' >> steps/ask.py"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

単純な一致を採点する

コマンド
docker exec jupyter python3 steps/ask.py plain

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

1つ直して、もう一度採点する

「ます」「です」のような、どの文章にも出る2文字のせいで、質問が違う段落へ行きました。2つ以上の文章に出る2文字をありふれた2文字として除き、もう一度採点します。

直すのは、一度に1つだけです。3つ同時に変えたら、どれが効いたか分かりません。

ありふれた2文字を除いて、採点する

コマンド
docker exec jupyter python3 steps/ask.py skip

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

よくある間違い

注意

当たり率が 0.5 から 0.67 に上がったので、アプリがよくなったと思う人が多いです。ほかの数も見ます。3つのはずれは、1つが当たりに、2つが答えなしになりました。これはよいことですが、2つの質問はまだ何も見つけません。これほど小さなテストは、どこを見るかを教えます。アプリの良さまでは、教えません。

例: 2回の実行を並べる

実行当たりはずれ答えなし当たり率
何も除かない3300.5
ありふれた2文字を除く4020.67

学生が入力するセルは、このプレビューでは空白です。

さらに: 自分の質問を足す

テストのファイルに、事実付きの質問を4つ足します。店の5つの答えでは答えられない質問も1つ入れます。

2回の実行を、もう一度採点します。店の文章に答えがない質問の、正しい結果は何でしょう。アプリはそうなりますか。

このラボとソースについて: JupyterLab データサイエンスラボ:pandas、Matplotlib、scikit-learn をブラウザーで

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。