Pandasでは不要な処理も多いため別途作成しました imabari.hateblo.jp
参考
Rによるデータクリーニング実践をPython(Pandas)でやってみた
!pip install japanize_matplotlib
スクレイピング
「男女別学校数 -後期課程」で検索、調査年月を降順で並べて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), )