全国学力テストの都道府県別平均正答率(2019年版)

2019年7月31日に,平成31年度全国学力テスト(正確には「全国学力・学習状況調査」)の結果が国研のこのページで公開された。例によって都道府県別平均正答率(%)は丸めて整数にしてある。そこで,都道府県ごとの正答数の度数分布のExcelファイルから精密な正答率を求めてCSV形式にした。

まず,報告書・調査結果資料からリンクされているファイル群を全部ダウンロードする(これはPythonではなくUNIXのコマンドである)。実際に全部を使うわけではないので,もっと絞ることも可能であるが,とりあえず:

wget --timestamping --recursive --no-parent --wait=1 \
     https://www.nier.go.jp/19chousakekkahoukoku/index.html

必要なファイル名のリストを得るには pathlib と正規表現ライブラリ re を使う:

import pathlib, re

path = pathlib.Path("www.nier.go.jp/19chousakekkahoukoku/factsheet/19prefecture-City")
names = sorted([p for p in path.glob("**/*.xlsx") if re.search(r"/\d\dp_19r\.xlsx$", str(p))])

まず小学校についてExcelファイルを読んで平均正答率を計算する:

from openpyxl import load_workbook
import numpy as np

def f(n):
    wb = load_workbook(n, read_only=True)
    ws = wb.worksheets[0]['AE8:AE22']
    n = len(ws)
    x = np.array([ws[i][0].value for i in range(n)])
    koku = (x @ np.arange(n)[::-1]) / np.sum(x) * (100 / (n-1))
    ws = wb.worksheets[1]['AE8:AE22']
    n = len(ws)
    x = np.array([ws[i][0].value for i in range(n)])
    san = (x @ np.arange(n)[::-1]) / np.sum(x) * (100 / (n-1))
    return [koku, san]

sho = np.array([f(n) for n in names])

同様に中学校も:

names = sorted([p for p in path.glob("**/*.xlsx") if re.search(r"/\d\dm_19r\.xlsx$", str(p))])

def f(n):
    wb = load_workbook(n, read_only=True)
    ws = wb.worksheets[0]['AE8:AE18']
    n = len(ws)
    x = np.array([ws[i][0].value for i in range(n)])
    koku = (x @ np.arange(n)[::-1]) / np.sum(x) * (100 / (n-1))
    ws = wb.worksheets[1]['AE8:AE24']
    n = len(ws)
    x = np.array([ws[i][0].value for i in range(n)])
    suu = (x @ np.arange(n)[::-1]) / np.sum(x) * (100 / (n-1))
    ws = wb.worksheets[2]['AE8:AE29']
    n = len(ws)
    x = np.array([ws[i][0].value for i in range(n)])
    ei = (x @ np.arange(n)[::-1]) / np.sum(x) * (100 / (n-1))
    return [koku, suu, ei]

chu = np.array([f(n) for n in names])

水平方向に結合する:

shochu = np.hstack((sho, chu))

CSV形式で保存(Excelや「メモ帳」で文字化けしないようにBOM付きUTF-8,行末CRLF):

import pandas as pd

pd.DataFrame(shochu).to_csv("atest2019.csv", index=False,
                            encoding="utf_8_sig", line_terminator="\r\n",
                            header=["小国","小算","中国","中数","中英"])

結果は atest2019.csv として置いておく。

都道府県名は特に付けていない。必要なら次のリストを使う:

kenmei = ["北海道", "青森県", "岩手県", "宮城県", "秋田県", "山形県",
  "福島県", "茨城県", "栃木県", "群馬県", "埼玉県", "千葉県", "東京都",
  "神奈川県", "新潟県", "富山県", "石川県", "福井県", "山梨県", "長野県",
  "岐阜県", "静岡県", "愛知県", "三重県", "滋賀県", "京都府", "大阪府",
  "兵庫県", "奈良県", "和歌山県", "鳥取県", "島根県", "岡山県", "広島県",
  "山口県", "徳島県", "香川県", "愛媛県", "高知県", "福岡県", "佐賀県",
  "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県"]

ついでに,各科目の正答数分布(全国,国・公・私立)をリストの形で挙げておく。それぞれ正答数0問,1問,2問,…の生徒(児童)数を並べたものである:

mkokugo = [6341, 15894, 25438, 36646, 50880, 69370, 95185, 127786,
           166953, 203279, 179498]

msuugaku = [8047, 19454, 31928, 40278, 46123, 50376, 53171, 56251,
            59513, 64337, 70933, 79772, 89387, 96414, 95775, 78450,
            37160]

meigo = [823, 1247, 3937, 9029, 16811, 27252, 38040, 48720, 59644,
         70950, 79952, 87227, 89056, 88087, 84676, 77895, 67556,
         54606, 38438, 22741, 9326, 1237]

pkokugo = [12397, 17864, 25613, 33122, 41213, 50515, 61704, 74986,
           90369, 106214, 119035, 128841, 125067, 102322, 51240]
         
psansuu = [2483, 6363, 16106, 27530, 38028, 48859, 61497, 74694,
           91659, 108309, 125896, 139305, 137438, 109090, 53222]

ついでに主成分分析をしてみる:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import pandas as pd

kenmei = ["北海道", "青森", "岩手", "宮城", "秋田", "山形", "福島", "茨城",
          "栃木", "群馬", "埼玉", "千葉", "東京", "神奈川", "新潟", "富山",
          "石川", "福井", "山梨", "長野", "岐阜", "静岡", "愛知", "三重",
          "滋賀", "京都", "大阪", "兵庫", "奈良", "和歌山", "鳥取", "島根",
          "岡山", "広島", "山口", "徳島", "香川", "愛媛", "高知", "福岡",
          "佐賀", "長崎", "熊本", "大分", "宮崎", "鹿児島", "沖縄"]

df = pd.read_csv("https://okumuralab.org/~okumura/python/data/atest2019.csv")

pca = PCA(n_components=2)
y = pca.fit_transform(df)

plt.clf()
plt.xlim(min(y[:,0]), max(y[:,0]))
plt.ylim(min(y[:,1])-0.2, max(y[:,1])+0.2)
for i in range(47):
    plt.text(y[i,0], y[i,1], kenmei[i],
             horizontalalignment='center', verticalalignment='center')
plt.axis('scaled')

plt.savefig('atest2019pca1.png', bbox_inches="tight")
全国学力テストの都道府県別正答率(2019年版)主成分分析

各主成分の分散の割合は pca.explained_variance_ratio_ で調べられる。第一主成分61.8%,第二主成分26.6%である。回転後の座標軸は次の通り:

r = pca.components_

plt.clf()
plt.xlim(-1, 1)
plt.ylim(-1, 1)
for i in range(5):
    plt.arrow(0, 0, r[0,i], r[1,i], head_width=0.05,
              head_length=0.05, length_includes_head=True, color='black')
    plt.text(r[0,i], r[1,i], df.columns[i])
plt.axis('scaled')

plt.savefig('atest2019pca2.png', bbox_inches="tight")
全国学力テストの都道府県別正答率(2019年版)主成分分析

Last modified: