e-statの平成30年1~12月犯罪統計をPandasでデータラングリング

exploratory.io

import pandas as pd

df1 = pd.read_excel(
    "https://www.e-stat.go.jp/stat-search/file-download?statInfId=000031797656&fileKind=0",
    sheet_name=1,
    header=None,
)

df1.head(10)

df2 = df1.loc[df1.notnull().sum(axis=1) > 2, df1.notnull().sum() > 2].copy()

df2.to_csv("data.tsv", sep="\t")

# タイトル
df2.iloc[0:2, 0] = "大分類"
df2.iloc[0:2, 1] = "中分類"
df2.iloc[0:2, 2] = "小分類"

df2.iat[3, 0] = "刑法犯総数"

# 大分類のあるところの中分類に「計」を入力
df2.iloc[3:, 1][df2.iloc[3:, 0].notnull()] = "計"

# 大分類の欠損値の前補完
df2.iloc[3:, 0].fillna(method="ffill", inplace=True)

# 中分類の欠損値の前補完
df2.iloc[3:, 1].fillna(method="ffill", inplace=True)

# 小分類の欠損値の前補完
df2.iloc[3:, 2].fillna("-", inplace=True)

df2

# 不要な行を削除
df2.drop([6], inplace=True)

# 不要な列を削除
df2.drop([12, 13, 16, 17, 20, 23, 24, 27, 28], axis=1, inplace=True)

# うち)を除去
df2.iloc[:, 1] = df2.iloc[:, 1].str.replace("うち)", "")
df2.iloc[:, 2] = df2.iloc[:, 2].str.replace("うち)", "")

# 検挙人員を補足
df2.iloc[0] = df2.iloc[0].str.replace("うち)", "検挙人員_")

df2.iloc[0].fillna(method="ffill", inplace=True)

df2.iloc[1] = df2.iloc[1].replace({"平成30年": "2018年", "平成29年": "2017年"})

df2.T.to_csv("data.csv", index=None, header=None)

df3 = pd.read_csv("data.csv", index_col=[0, 1], header=[0, 1, 2], na_values="-")

# 検挙率を削除あとで再計算
df3.drop("検挙率", level=0, inplace=True)

# うちの不足のデータを作成
df3.loc[:, ("粗暴犯", "傷害", "その他")] = (
    df3.loc[:, ("粗暴犯", "傷害", "-")] - df3.loc[:, ("粗暴犯", "傷害", "傷害致死")]
)

df3.loc[:, ("知能犯", "偽造", "その他")] = (
    df3.loc[:, ("知能犯", "偽造", "-")]
    - df3.loc[:, ("知能犯", "偽造", "通貨偽造")]
    - df3.loc[:, ("知能犯", "偽造", "文書偽造")]
    - df3.loc[:, ("知能犯", "偽造", "支払用カード偽造")]
    - df3.loc[:, ("知能犯", "偽造", "有価証券偽造")]
)

df3.loc[:, ("知能犯", "汚職", "その他")] = (
    df3.loc[:, ("知能犯", "汚職", "-")] - df3.loc[:, ("知能犯", "汚職", "賄賂")]
)

df3.loc[:, ("風俗犯", "わいせつ", "その他")] = (
    df3.loc[:, ("風俗犯", "わいせつ", "-")]
    - df3.loc[:, ("風俗犯", "わいせつ", "強制わいせつ")]
    - df3.loc[:, ("風俗犯", "わいせつ", "公然わいせつ")]
)

df3.loc[:, ("その他の刑法犯", "その他", "-")] = (
    df3.loc[:, ("その他の刑法犯", "計", "-")]
    - df3.loc[:, ("その他の刑法犯", "占有離脱物横領", "-")]
    - df3.loc[:, ("その他の刑法犯", "公務執行妨害", "-")]
    - df3.loc[:, ("その他の刑法犯", "住居侵入", "-")]
    - df3.loc[:, ("その他の刑法犯", "逮捕監禁", "-")]
    - df3.loc[:, ("その他の刑法犯", "略取誘拐・人身売買", "-")]
    - df3.loc[:, ("その他の刑法犯", "盗品", "-")]
    - df3.loc[:, ("その他の刑法犯", "器物損壊等", "-")]
)

df4 = (
    df3.T.reset_index()
    .set_index(["大分類", "中分類", "小分類"])
    .sort_index()
    .fillna(0)
    .astype(int)
)

# 検挙率再計算
df5 = df4["検挙件数"] / df4["認知件数"] * 100
df5.columns = pd.MultiIndex.from_product([["検挙率"], df5.columns])

# 検挙人員の成人集計
df6 = df4["検挙人員"] - df4["検挙人員_少年"]
df6.columns = pd.MultiIndex.from_product([["検挙人員_成人"], df6.columns])

# 結合
df7 = pd.concat([df4, df5, df6], axis=1).sort_index(axis=1)

df7.fillna(0, inplace=True)

df7

# 計の列の抽出
df7.loc[pd.IndexSlice[:, "計", :], :]

e-Statの趣味・娯楽の種類別行動者率をデータラングリング

www.e-stat.go.jp

exploratory.io

import pandas as pd

df1 = pd.read_excel(
    "https://www.e-stat.go.jp/stat-search/file-download?statInfId=000031577984&fileKind=0",
    header=None,
)

df1.to_csv("data.tsv", sep="\t")

# 行カウント確認
df1.notnull().sum(axis=0)

# 列カウント確認
df1.notnull().sum(axis=1)

df1

# テキスト埋め
df1.iat[7, 7] = "男女"
df1.iat[7, 10] = "年齢"
df1.iat[7, 12] = df1.iat[6, 12]
df1.iat[7, 13] = df1.iat[6, 13]

df1.iat[10, 10] = "計"
df1.iat[24, 10] = "計"
df1.iat[38, 10] = "計"

# 表のみ抽出
df2 = df1.iloc[7:-4, 7:-2].copy()

# 英字と番号の行を削除
df2.drop([8, 9], inplace=True)

# 総数・男・女 列テキスト結合
df2[7] = df2[7].fillna("") + df2[8].fillna("") + df2[9].fillna("")

# 空白のところをNanに置換
df2[7].mask(df2[7] == "", inplace=True)

# 前行の値をコピー
df2[7].fillna(method="ffill", inplace=True)

# タイトルの空白文字を除去
df2.iloc[0, :] = df2.iloc[0, :].str.replace(r"\s", "")

# 不要な列を削除
df2.drop([8, 9, 11, 30, 31, 32, 33, 34, 35, 36], axis=1, inplace=True)

df2.head(10)

df2.to_csv("data.csv", header=False, index=False)
import matplotlib.pyplot as plt
import seaborn as sns

import japanize_matplotlib

df = pd.read_csv("data.csv", index_col=[0,1], header=0)

# 計の行削除
df.drop("計", level=1, inplace=True)

df.drop(["サンプルサイズ", "15歳以上推定人口(千人)", "総数"], axis=1, inplace=True)

df_man = df.loc["男", :].copy()

df_man.plot(figsize=(10, 8))
# 凡例を枠外
plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left", borderaxespad=0, fontsize=10)

df_woman = df.loc["女", :].copy()

df_woman.plot(figsize=(10, 8))
# 凡例を枠外
plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left", borderaxespad=0, fontsize=10)

df_all = df.loc["総数", :].copy()

df_all.plot(figsize=(10, 8))
# 凡例を枠外
plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left", borderaxespad=0, fontsize=10)


plt.figure(figsize=(5, 10)) 
sns.heatmap(df_man.T, cmap="bwr")
plt.savefig('man.png')

plt.figure(figsize=(5, 10)) 
sns.heatmap(df_woman.T, cmap="bwr")
plt.savefig('woman.png')

plt.figure(figsize=(5, 10)) 
sns.heatmap(df_all.T, cmap="bwr")
plt.savefig('all.png')

f:id:imabari_ehime:20200117150101p:plain

f:id:imabari_ehime:20200117150113p:plain

全体

f:id:imabari_ehime:20200117150125p:plain

クラスタリング

やりかたがわからない

Pandasでデータラングリングでよく使うもの

github.com

import pandas as pd

df1 = pd.read_excel("URL", sheet_name=0, header=None)

# Excelないとき
df1.to_csv("data.tsv", sep="\t")

# 行カウント確認
df1.notnull().sum(axis=0)

# 列カウント確認
df1.notnull().sum(axis=1)

# テキスト埋め
df1.iloc[行, 列] = "テキスト"

# テキスト絞り込み
df2 = df1.loc[df1.notnull().sum(axis=1) > 2, df1.notnull().sum() > 2].copy()

# 下方向
df2.fillna(method="ffill", inplace=True)

# 右方向
df2.fillna(method="ffill", axis=1, inplace=True)

# 行削除
df2.drop("行名", inplace=True)

# 列削除
df2.drop("列名", axis=1, inplace=True)

Pandasでe-Statの年齢・男女別人口推移データ

EDA Salon 第6回 - 日本の統計データ(e-Stat)のデータラングリング大会

EDA Salon 第6回 - 日本の統計データ(e-Stat)のデータラングリング大会 年齢・男女別人口推移データ(難易度:普通)

www.e-stat.go.jp

exploratory.io

exploratory.io

相違

Pandasで解いてみたのですが統計の合計が合わない

f:id:imabari_ehime:20200115133451p:plain

drive.google.com

  • data.csv 抽出したデータ
  • data1.csv 抽出したデータから再集計

Pandas

import pandas as pd

df = pd.read_excel("https://www.e-stat.go.jp/stat-search/file-download?statInfId=000013168604&fileKind=0", header=None, skiprows=6)

df.head(20)

# 英語の行削除
df.drop(df.index[4], inplace=True)

# 英語の列削除
df.drop(df.columns[1], axis=1, inplace=True)

# 年の「1)」を除去
df.iloc[0,:].replace("1\)", "", regex=True, inplace=True)

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

# 年の平成を除去
df.iloc[0,:].replace(r"平成(\d{2})年", "", regex=True, inplace=True)

# 年の欠損値を前の値で補完
df.iloc[0,:].fillna(method="ffill", inplace=True)

# 年齢の数字以外を除去
df.iloc[:,0].replace(r"歳(以上)?$", "", regex=True, inplace=True)

# タイトル補完
df.iloc[0, 0] = "年"
df.iloc[2, 0] = "性別"

# データ以外を行・列除去
df1 = df.loc[df.notnull().sum(axis=1) > 2, df.notnull().sum() > 2].copy()

# 欠損値を0で補間
df1.fillna(0, inplace=True)

# CSVに保存
df1.T.to_csv("data.csv", encoding="utf_8_sig", index=False, header=False)

df1

総数

df2 = pd.read_csv("data.csv", index_col=[0,1], header=0)
df2.head(10)

df2["総数"] - df2.loc[:, "0":"100"].sum(axis=1)
男女計
2000 0 -3 -4
2001 -1 1 -1
2002 2 -2 1
2003 -3 2 -2
2004 -2 2 -2
2005 2 4 2
2006 2 0 4
2007 3 2 -2
2008 -1 1 -2
2009 -2 -1 1
2010 8 4 0
2011 0 2 1
2012 1 1 3
2013 3 -2 0
2014 1 -1 5
2015 0 1 1

男女の計

df3 = pd.read_csv("data.csv", index_col=None, header=0)
df3.head(10)

df3.drop("総数", axis=1, inplace=True)
df3.head()

df4 = df3.melt(id_vars=["年", "性別"], var_name="年齢", value_name="人数")
df4.head(10)

pv4 = df4.pivot_table(index="年", columns="性別", values="人数", aggfunc="sum")

pv4["差"] = pv4["男女計"] -  pv4["男"] -  pv4["女"]
男女計
2000 62111 64818 126930 1
2001 62245 65046 127292 1
2002 62250 65185 127434 -1
2003 62307 65313 127621 1
2004 62297 65390 127689 2
2005 62347 65415 127766 4
2006 62328 65440 127766 -2
2007 62307 65459 127773 7
2008 62252 65440 127694 2
2009 62132 65381 127509 -4
2010 62320 65726 128057 11
2011 62184 65613 127798 1
2012 62028 65485 127512 -1
2013 61906 65390 127298 2
2014 61800 65283 127078 -5
2015 61842 65252 127094 0

年・年齢

df4["年齢"] = df4["年齢"].astype(int)
pv5 = df4.pivot_table(index=["年", "年齢"], columns="性別", values="人数", aggfunc="sum")

pv5["集計"] = pv5["男"] + pv5["女"]
pv5["差"] = pv5["男女計"] -  pv5["集計"]

Pythonでe-Statから男女別学校数を検索、統計表情報取得、統計データ取得

import io
import time
import pandas as pd
import requests

key = ""

# 統計表情報取得
def get_list_csv(word):

    params = {
        "appId" : key,
        "lang": "J" ,
    }
    params["searchWord"] = word

    r = requests.get(
        "https://api.e-stat.go.jp/rest/3.0/app/getSimpleStatsList", params=params
    )

    return r.content

# 統計データ取得
def get_data_csv(id):

    params = {
        "appId": key,
        "lang": "J",
        "metaGetFlg": "Y",
        "cntGetFlg": "N",
        "sectionHeaderFlg": "1",
    }

    params["statsDataId"] = id

    r = requests.get(
        "https://api.e-stat.go.jp/rest/3.0/app/getSimpleStatsData", params=params
    )

    return r.content

# 検索
res = get_list_csv("男女別学校数 NOT 後期課程")

# 統計表情報をCSV変換
df0 = pd.read_csv(io.BytesIO(r.content), skiprows=8, dtype=object)

# 統計表IDリスト作成
stats = df0["TABLE_INF"].to_list()

dfs = []

# 統計表ID
for stat in stats:

    res = get_data_csv(stat)

    # 統計データをCSV変換
    df1 = pd.read_csv(io.BytesIO(r.content), skiprows=28)

    dfs.append(df1)

    time.sleep(1)

# 列が違うためエラー
df = pd.concat(dfs)

Pythonでe-StatのAPIデータを取得、グラフ作成

事前準備

www.e-stat.go.jp

dekiru.net

API

https://www.e-stat.go.jp/api/sites/default/files/uploads/2019/07/API-specVer3.0.pdf

https://www.e-stat.go.jp/api/sample/testform3-0/

  • APIの登録しアプリケーションID(appId)を取得する
  • APIのアイコンのものだけ使える
  • statsDataIdが必要

JSON

このサービスは、政府統計総合窓口(e-Stat)のAPI機能を使用していますが、サービスの内容は国によって保証されたものではありません。

import pandas as pd
import requests
from pandas.io.json import json_normalize

params = {
    "appId": "",
    "lang": "J",
    "statsDataId": "0003191360",
    "metaGetFlg": "Y",
    "cntGetFlg": "N",
    "sectionHeaderFlg": "1",
}

r = requests.get(
    "https://api.e-stat.go.jp/rest/3.0/app/json/getStatsData", params=params
)

# URL確認
r.url

# JSON
data = r.json()

# 内容確認
data

# normalize
df = json_normalize(data["GET_STATS_DATA"]["STATISTICAL_DATA"]["DATA_INF"]["VALUE"])

df

CSV

  • JSONからCSVに変換するだけでもかなりの手間がかかるので表形式のデータの場合JSONで取得するよりもCSVで取得する
import io

import pandas as pd
import requests

import japanize_matplotlib
import matplotlib.pyplot as plt

params = {
    "appId": "",
    "lang": "J",
    "statsDataId": "0003191360",
    "metaGetFlg": "Y",
    "cntGetFlg": "N",
    "sectionHeaderFlg": "1",
}

r = requests.get(
    "https://api.e-stat.go.jp/rest/3.0/app/getSimpleStatsData", params=params
)

# URL確認
r.url

# CSV内容確認
print(r.text)

# CSVファイル読込
df = pd.read_csv(io.BytesIO(r.content), skiprows=26)

# データ確認
df.head(20)

# 欠損値確認
df.isna().any(axis=0)

# データ型確認
df.dtypes

# 列名確認
df.columns

# 年度ごとに集計
pv = df.pivot_table(
    index=["認知・検挙件数・検挙人員", "重要犯罪・重要窃盗犯"],
    columns="時間軸(年次)",
    values="value",
    aggfunc="sum",
).astype(int)

# CSVに保存
pv.to_csv("data.csv")

# グラフ
pv.loc[[("認知件数", "重要犯罪"),("検挙件数", "重要犯罪")],:].T.plot(ylim=0, figsize=(8, 6))

# 凡例を枠外
plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left", borderaxespad=0, fontsize=10)

# グラフ表示
plt.show()

f:id:imabari_ehime:20200114100428p:plain

わからない

  • CSVだと上部にあるステータスが読み取れない