Path to でーたさいえんてぃすと

データサイエンスの勉強の過程を公開していきます。

NDBオープンデータ(二次医療圏別収縮期血圧)のクリーニング

第7回NDBオープンデータのデータクリーニングを行ったソースコードを載せます。
今回の元データは収縮期血圧 二次医療圏別性年齢階級別分布です。

元データは以下のようなエクセルファイルです。

図1 クリーニング前のデータ

データ解析しやすいように、血圧のクラスは列に設定しました。
下のコードの年齢と性別の部分を変えれば、自由にエクセルファイルに出力が可能です。

例として、40~44歳の男性の二次医療圏別性年齢階級収縮期血圧分布をデータクリーニングしてみます。

import numpy as np
import pandas as pd

# 収縮期血圧のデータ読み込み

df_sbp = pd.read_excel("SBP_2ndmed_7ndb.xlsx")

# titleを取得
df_sbp_title = df_sbp.columns[0]

# 検査データの単位を取得
bp_sbp_unit = df_sbp.iloc[0, 1]

df_sbp = pd.read_excel("SBP_2ndmed_7ndb.xlsx", skiprows =3)


# 列名の変更
df_sbp = df_sbp.drop(df_sbp.index[[0]])
df_sbp = df_sbp.rename(columns={"Unnamed: 0": "prefecture",
                              "Unnamed: 1": "2nd_med_area_code", 
                              "Unnamed: 2": "2nd_med_area",
                              "Unnamed: 3": "sbp_class"
                              })


# 都道府県などの欠損値を穴埋め
df_sbp = df_sbp.fillna(method="ffill")

# 二次医療圏判別不可を除外
df_sbp = df_sbp[df_sbp.loc[:, "prefecture"] != "二次医療圏判別不可"]


# 男性と女性のデータを区別

# 男性
rename_cols = ["40~44歳",     "45~49歳",    "50~54歳",    "55~59歳",    "60~64歳",    "65~69歳",    "70~74歳", '中計']
df_sbp = df_sbp.rename(columns={rename_col: f"{rename_col}_男性" for rename_col  in rename_cols})

# 女性
rename_cols_women = [f"{i}.1" for i in rename_cols]
df_sbp = df_sbp.rename(columns={rename_col_woman: rename_col_woman.replace(".1", "") for rename_col_woman  in rename_cols_women})
df_sbp = df_sbp.rename(columns={rename_col: f"{rename_col}_女性" for rename_col  in rename_cols})



# 今回は男性の40~44歳のデータを抽出
df_sbp = df_sbp.loc[:, ["prefecture","2nd_med_area_code", "2nd_med_area", "sbp_class", "40~44歳_男性"]]



# 180overだけprefectureなどの列を残し、他のdfは血圧の列だけにして、後でmergeで結合
# 2nd_med_area_codeで結合しないと、同じ名前の二次医療圏があってdfの行数がおかしくなる


# 180_over 
df_sbp_180_over = df_sbp[df_sbp.loc[:,  "sbp_class"] == "180以上"].rename(columns={"40~44歳_男性": "180以上"}).drop("sbp_class", axis=1)

# 160-180
df_sbp_160_180 = df_sbp[df_sbp.loc[:,  "sbp_class"] == "160以上180未満"].rename(columns={"40~44歳_男性": "160以上180未満"}).drop(["prefecture","2nd_med_area", "sbp_class"], axis=1)

# 140-160
df_sbp_140_160 = df_sbp[df_sbp.loc[:,  "sbp_class"] == "140以上160未満"].rename(columns={"40~44歳_男性": "140以上160未満"}).drop(["prefecture","2nd_med_area", "sbp_class"], axis=1)

# 130-140
df_sbp_130_140 = df_sbp[df_sbp.loc[:,  "sbp_class"] == "130以上140未満"].rename(columns={"40~44歳_男性": "130以上140未満"}).drop(["prefecture","2nd_med_area", "sbp_class"], axis=1)

# 120-130
df_sbp_120_130 = df_sbp[df_sbp.loc[:,  "sbp_class"] == "120以上130未満"].rename(columns={"40~44歳_男性": "120以上130未満"}).drop(["prefecture","2nd_med_area", "sbp_class"], axis=1)

# 120_less
df_sbp_120_less = df_sbp[df_sbp.loc[:,  "sbp_class"] == "120未満"].rename(columns={"40~44歳_男性": "120未満"}).drop(["prefecture","2nd_med_area", "sbp_class"], axis=1)



# dfの結合
df_sbp = pd.merge(df_sbp_180_over, df_sbp_160_180, on = "2nd_med_area_code")
df_sbp = pd.merge(df_sbp,df_sbp_140_160,  on = "2nd_med_area_code")
df_sbp = pd.merge(df_sbp,df_sbp_130_140,  on = "2nd_med_area_code")
df_sbp = pd.merge(df_sbp,df_sbp_120_130,  on = "2nd_med_area_code")
df_sbp = pd.merge(df_sbp,df_sbp_120_less,  on = "2nd_med_area_code")


# 列名の変更
df_sbp = df_sbp.rename(columns={"180以上": "180_over",
                              "160以上180未満": "160_180", 
                              "140以上160未満": "140_160",
                              "130以上140未満": "130_140",
                               "120以上130未満": "120_130",
                                "120未満": "120_less"
                              })


# エクセルファイルに出力
df_sbp.to_excel("SBP_2ndmed_7ndb_40_44_m.xlsx")


〜

以上のコードを行うと、以下のように元のエクセルファイルを整形することができます。 個人的にはこちらのほうが解析しやすいので、今後機械学習などの説明変数として利用する際に利用していきたいと思います。

図2 クリーニング後のデータ

参考サイト

第7回NDBオープンデータ https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/0000177221_00011.html