Rによるデータクリーニング実践をPython(Pandas)でやってみた

Pandasでは不要な処理も多いため別途作成しました imabari.hateblo.jp

参考

id.fnshr.info

Rによるデータクリーニング実践をPython(Pandas)でやってみた

!pip install japanize_matplotlib

スクレイピング

www.e-stat.go.jp

「男女別学校数 -後期課程」で検索、調査年月を降順で並べて1ページ目の50件取得

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"
}

r = requests.get(
    "https://www.e-stat.go.jp/stat-search/files?page=1&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')

data = []

# ExcelファイルのURLと調査年月日を取得
for div in soup.select("div.stat-resource_list-main"):
    li = div.select("li.stat-resource_list-detail-item")

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

データ処理

import pandas as pd
from tqdm import tqdm_notebook
import time

dfs = []

for i in tqdm_notebook(data):

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

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

    # 欠損値でない列が2個より多い行を抽出
    df1 = df0[df0.notnull().sum(axis=1) > 2].copy()

    # 空列を削除
    df1.dropna(how="all", axis=1, inplace=True)

    # 列名用に値を変更
    df1.iat[0, 0] = "設置者"
    df1.iat[1, 0] = "本校分校"

    # 転置
    df1t = df1.T
    df1t

    # 1行目を列名に設定
    df1t.rename(columns=df1t.iloc[0], inplace=True)

    # 1行目を削除
    df2 = df1t.iloc[1:, :].copy()

    # 空白文字を除去、欠損値を前から補完
    df2["設置者"] = df2["設置者"].str.replace(r"\s", "").fillna(method="ffill")

    # 横持ちから縦持ちへ変換
    df3 = pd.melt(df2, id_vars=["設置者", "本校分校"])

    # 列名変更
    df3.rename(columns={"variable": "男女", "value": "学校数"}, inplace=True)

    # 計の行を全削除、indexリセット
    df4 = df3[df3 != "計"].dropna(how="any").reset_index(drop=True)

    # 整数に型変更
    df4["学校数"] = df4["学校数"].astype(int)

    # 年を追加
    df4["年"] = i["year"]

    # 1からの連番に変更
    df4.index += 1

    dfs.append(df4)

    time.sleep(3)

# 全データを結合
df = pd.concat(dfs)

df

グラフ表示

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

pv = df.pivot_table(index="年", columns="男女", aggfunc="sum").droplevel(0, axis=1)

pv.plot(
    y=["男のみの学校", "女のみの学校"],
    marker="o",
    ms=5,
    grid=True,
    figsize=(10, 8),
    xticks=np.arange(int(pv.index.min()), int(pv.index.max()), 5),
)

f:id:imabari_ehime:20200107135511p:plain