e-Statの男女別学校数から男のみ・女のみの学校をスクレイピング・グラフ作成

imabari.hateblo.jp

前回のRによるデータクリーニング実践――政府統計からのグラフ作成を例として を参考にしたのでクリーニング方法も今回は変更

せっかくなのでe-Statにあるデータ全部(1957年は課程ごとのため除外)をスクレイピングしてグラフ作成しました。

Excelデータ

年度ごとの違い

年度 分校 学校 共学 英語 合計 転置
1976~2019 × ×
1966~1975 × ×
1964~1965 ×
1963 × ×
1962 × 総数 ×
1959~1961 × × × 総数 ×
1958 × × × 総数
1957
  • 分校:分校の列があり、なし
  • 学校:男のみの学校・女のみの学校と「の学校が」つく・つかない
  • 共学:「共学」はあり、「男女ともにいる」はなし
  • 英語:英語のタイトルがあり、なし
  • 合計:計か総数
  • 転置:必要、なし

共学の違い

年度 共学
1976-2019 男女ともにいる学校
1963-1975 男女共学の学校
1962 男女共学学校
1959-1961 共学
1958 男女共学

プログラム

!pip install japanize_matplotlib

EXCELファイルのURLと年を抽出

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
}

data = []

for page in [1, 2]:

    r = requests.get(
        f"https://www.e-stat.go.jp/stat-search/files?page={page}&query=%E7%94%B7%E5%A5%B3%E5%88%A5%E5%AD%A6%E6%A0%A1%E6%95%B0%20-%E5%BE%8C%E6%9C%9F%E8%AA%B2%E7%A8%8B&sort=year_month%20desc&layout=dataset&toukei=00400001&metadata=1&data=1",
        headers=headers,
    )

    r.raise_for_status()

    soup = BeautifulSoup(r.content, "html5lib")

    for div in soup.select("div.stat-resource_list-main"):
        li = div.select("li.stat-resource_list-detail-item")

        year = int(li[2].contents[2].rstrip("年"))

        if year > 1957:

            url = urljoin(
                "https://www.e-stat.go.jp/",
                li[4].find("a", attrs={"data-file_type": "EXCEL"}).get("href"),
            )

            data.append({"year": year, "url": url})
        
        else:
            break

EXCELファイルのデータ抽出、CSVに保存

import pandas as pd
from tqdm import tqdm_notebook
import time

dfs = []

for i in tqdm_notebook(data):

    df1 = pd.read_excel(i["url"])

    df1.replace(["-", "―", "-"], 0, inplace=True)

    # クリーニング
    df2 = df1.loc[df1.notnull().sum(axis=1) > 2, df1.notnull().sum() > 2]

    year = i["year"]

    # 1962年~1965年は英語があるので除去
    if 1961 < year < 1966:
        df2.replace("[a-zA-Z-]", "", regex=True, inplace=True)

    # 空白文字を除去
    df2.replace(r"\s", "", regex=True, inplace=True)

    # 1959年~1963年は転置なし
    if 1958 < year < 1964:
        # 転置なし
        df3 = df2.fillna(method="ffill")
    else:
        # 転置あり
        df3 = df2.T.fillna(method="ffill")

    filename = f"{year}.csv"

    # CSVに保存
    df3.to_csv(filename, header=False, index=False)

    time.sleep(3)

    ## 年度ごとに取り込み方法変更
    if year > 1975:
        df4 = pd.read_csv(filename, header=0, index_col=[0, 1])
        s = df4.loc[("計", "計"), ["男のみの学校", "女のみの学校"]]
    elif year > 1962:
        df4 = pd.read_csv(filename, header=0, index_col=0)
        s = df4.loc["計", ["男のみの学校", "女のみの学校"]]
    elif year == 1962:
        df4 = pd.read_csv(filename, header=0, index_col=0)
        s = df4.loc["総数", ["男のみの学校", "女のみの学校"]]
    elif year > 1957:
        df4 = pd.read_csv(filename, header=0, index_col=0)
        s = df4.loc["総数", ["男のみ", "女のみ"]]
        s.index = ["男のみの学校", "女のみの学校"]
    else:
        break

    s.name = year

    dfs.append(s)

df = pd.concat(dfs, axis=1).T

df

グラフ

import matplotlib.pyplot as plt
import japanize_matplotlib
import numpy as np

df.plot(
    marker="o",
    ms=5,
    grid=True,
    figsize=(10, 8),
    xticks=np.arange(1955, 2020+1, 5),
    title="日本における男子のみ・女子のみの高校(通信制除く)の数"
)

f:id:imabari_ehime:20200110110537p:plain