乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

大学入試

今回はBERTを用いて
大学入試の英語の問題を解いてみました。

解説動画はこちら


さて、まずはBERTですが
これはBidirectional Encoder Representations from Transformers の略で
自然言語処理(NLP : Natural Language Processing)タスクを
こなすことの出来るモデルです。

翻訳、文書分類、質問応答などの
様々な問題を解かせることができます。

Google Colabで実際に動かすことができるので
試したい方はコードを参考にしてみて下さい。

今回は大学入試の過去問題を
解いてみることとします。

選択肢で単語を選ぶ系の問題を解かせて
選択肢を選ばせてみることにしました。

参考として2020年のセンター試験の問題を
解いてみましょう。

まず最初にすることは
ライブラリのインストールです。

transformersというものを使います。

transformers

こちらにライブラリの詳細があります。
詳しい使い方はこちらにありますので
英語ですが見たい方はどうぞ。

インストールコマンドで
Google colab上にインストールできます。
!pip install transformers

次にモデルの読み込みです。
穴埋め問題を解く「fill-mask」というのを
指定します。

from transformers import pipeline

model = pipeline("fill-mask")

ここで一問解いてみることにしましょう。

c

問題の英文と選択肢を設定すると
選択肢の当てはまる確率を出してくれます。

probrem = 'Due to the rain, our performance in the game was {} from perfect'
choices = ['apart','different','far','free']
text = probrem.format(model.tokenizer.mask_token)
targets = [" " + c for c in choices]
result = model(text, targets=targets)
possibility = [(r["token_str"].strip()  , round(r["score"],4)) for r in result]
print(possibility)
[('far', 0.9982), ('apart', 0.0), ('different', 0.0), ('free', 0.0)]

結果はこんな感じで出てきます。
4つの選択肢の当てはまる確率の高い順で
出てくるので、一番数値の大きいのを選べば
良いことになります。

この場合の正解は3番の「far」でした。

自分は英語の偏差値20くらいなので
ファーーーって感じですよね。

正解しているようなので
次は問題をまとめて解いてみます。

問題は辞書型で沢山しこんでおきます。
正解も加えておき、合っているかを
確認してみることとします。

probrems={
  8:['Due to the rain, our performance in the game was {} from perfect.',['apart','different','far','free'],'far'],
  9:['Emergency doors can be found at {} ends of this hallway.',['both','each','either','neither'],'both'],
 10:['My plans for studying abroad depend on {} I can get a scholarship.',['that','what','whether','which'],'whether'],
 11:['Noriko can speak Swahiki and {} can Marco.',['also','as','so','that'],'so'],
 12:['To say you will go jogging every day is one thing, but to do it is {}.',['another','one another','the other','the others'],'another']
}

さて解いてみましょう。
import pandas as pd

tmp = []
for k,v in probrems.items():
  text = v[0].format(model.tokenizer.mask_token)
  targets = [" " + c for c in v[1]]
  result = model(text, targets=targets)
  possibility = [(r["token_str"].strip()  , round(r["score"],4)) for r in result]
  print(possibility)
  answer = possibility[0][0]
  tmp.append(v+[answer])
  
df = pd.DataFrame(tmp,columns=['問題','選択肢','解答','選んだ答え'])
df['正解'] = df['解答']==df['選んだ答え']

df


問題
選択肢解答選んだ答え正解
0Due to the rain, our performance in the game w...[apart, different, far, free]farfarTrue
1Emergency doors can be found at {} ends of thi...[both, each, either, neither]bothbothTrue
2My plans for studying abroad depend on {} I ca...[that, what, whether, which]whetherwhetherTrue
3Noriko can speak Swahiki and {} can Marco.[also, as, so, that]sothatFalse
4To say you will go jogging every day is one th...[another, one another, the other, the others]anotheranotherTrue

実際にBERT君が選択した問題と解答を比較してみました。
4問目は間違えていてそれ以外は合っています。

4問目は確率が同じ選択肢が3つあり
その中から並びが最初のものを選んだので間違いでしたが
同じ確率の選択肢としては選んだものは合っていました。

ここら辺は人が見て選ぶ必要が有るかもですね。

選択肢を与えない場合は空欄に当てはまる単語を
セレクトしてくれるみたいなので
場合によって使い分けすると良いかもしれません。

さて
BERTを用いると英文問題などは
比較的解けるかなと思います。

一番の難点は
実際の入試の際にこのBERTを使うのが
困難な点ですねーーーーーー

モバイルグラスや、コンタクトに仕込んで
英文と選択肢を自動認識、入力させて
解答を自動で出すような仕組みを作らないと
入試の時には使えないですね。

テクノロジーの進化を待ちましょうかwww

BERTを用いると他にも自然言語処理に関わる
色々な問題を解くことができます。

気になった方は試してみて下さい。
それでは。

今回は受験シーズンにつき
大学の入試問題をプログラムで解いてみました。

解説動画はこちら

 
一橋大学さんの2021年の数学の入試問題です。

問題は

1000以下の素数は250個以下であることを示せ

さて
私は偏差値20位しかないので
普通に解いたら解くことはできません。

プログラムの力を使って
強引に解いていきましょう。

まずは1000以下の素数を列挙したれば
個数がわかります。

素数を列挙してみましょう。

素数を判定するプログラムを書いても良いですが
面倒くさいのでライブラリを用います。

Python言語ではsympyという数学計算ライブラリがあり
それを用いると計算はめっちゃ楽です。

isprimeという素数かどうかを判定する
メソッドがあるのでそれを用いましょう。

素数だと判定された数を
リストに格納して個数を数えます。
from sympy import isprime

prime=[]
for i in range(1,1001):
    if isprime(i):
        prime.append(i)
print(len(prime))
168

ということで
250個以下であるということは
わかりましたね。


でもこれだと素数を列挙して
答案用紙に書くのは大変そうですね。

別の解き方も考えてみましょう。

​素数の倍数を挙げ
それが750個以上出れば
素数は250個以下であることが
示ると思います。

それでは素数の小さい方から
その倍数の個数を数えていきましょう。

2が一番小さいですね。
2の倍数で考えると2は素数なので候補ではなく
4から1000まで数えることになります。

こんな感じで2の倍数のリストを
作ることができます。
bai_2 = [i for i in range(4,1001,2)]
len(bai_2)
499

2の倍数の時点で499個ですね
次は3の倍数です。
bai_3 = [i for i in range(6,1001,3)]
len(bai_3)
332

5の倍数もいきましょう。
bai_5 = [i for i in range(10,1001,5)]
len(bai_5)
199

この時点でリストの個数は
len(bai_2 + bai_3 + bai_5)
1030

ということで、リストの個数は
1000個を超えましたが
このリストは重複が含まれています。

プログラム言語では重複を排除する方法として
セットというデータ型を使うことができます。

pythonでは set() でリストをセットに変換できます。
sets = set(bai_2 + bai_3 + bai_5)
print(len(sets))
731


重複を排除したら731個になってしまいました。

7の倍数も追加してみましょう。
bai_7 = [i for i in range(14,1001,7)]
print(len(bai_7))

sets = set(bai_2 + bai_3 + bai_5 + bai_7)
print(len(sets))
141
768

7の倍数を追加すると素数でないものの数が
750を超えました。

ということで素数が250個以下になることが
わかるかと思います。

あとは解答用紙にどう書くかですかね
そこは知りません!!!!!

ということで今回は
数学の問題をプログラムで解いてみました。

プログラムの勉強にはちょうど良い題材ですね。
それでは。

このページのトップヘ