CSVファイルから数の集計をする
以前人口ピラミッドのグラフを作成した
mecobalamin.hatenablog.com
同様なグラフを作成するに当たり、以下のようなリストから男女別と年代別に集計をしたい
居住地, 年代, 性別, 死亡確認 死亡例1例目, 非公表, 70代. 非公表, 非公表 死亡例2例目, 非公表, 50代, 男性, 2020年4月19日, 4月7日入院。酸素吸入開始。4月19日死亡確認。死因調査中 死亡例3例目, 那覇市, 80代, 男性, 2020年4月19日, 4月9日入院。4月12日ICUに転院。4月19日死亡確認。死因調査中 死亡例4例目, 中部保健所管内, 70代, 女性, 2020年4月22日, 4月22日死亡確認。死因調査中 死亡例5例目, 中部保健所管内, 70代, 男性, 2020年4月29日, 4月10日発熱。4月12日PCR検査にて陽性を確認、入院。4月29日死亡確認。死因調査中
集計後の出力は以下の通り
man | worman | undisclosed | |
90 + | 71.0 | 143.0 | NaN |
80 - 89 | 127.0 | 95.0 | 1.0 |
70 - 79 | 90.0 | 37.0 | NaN |
60- 69 | 43.0 | 19.0 | NaN |
50 - 59 | 15.0 | 6.0 | NaN |
40 - 49 | 6.0 | 3.0 | NaN |
30 - 39 | 3.0 | 1.0 | NaN |
20 - 29 | NaN | NaN | NaN |
10 - 19 | NaN | NaN | NaN |
0 - 9 | NaN | NaN | NaN |
undisclosed | 1.0 | NaN | 16.0 |
やることは
- CSVファイルを読み込んでデータフレームに変換
- 文字の変換
- 性別、年齢別に集計
1. CSVファイルを読み込んでデータフレームに変換
CSVを読み込むコードはよく使うので関数にしてある
ファイルのパスとファイル名を引数にした
ファイル名はリストになっている
CSVの読み込みはpandasのread_csvを使用し、1列目をインデックスにした
読み込んだCSVを空のデータフレームに結合して変数を返す
def Read_CSV_Files(Path_CSV, List_CSV): df = DataFrame() for i in List_CSV: try: df_tmp = pd.read_csv(Path_CSV + i, index_col = 0, encoding = 'shift_jis') except Exception as e: print('cannot open file: ', i) print(str(e)) sys.exit(1) else: print('we were able to open the file:', i) df = pd.concat([df, df_tmp]) return df
2. 文字の変換
読み込んだCSVの3列目の型を文字列からpandasのdatetime形式に変換する
日付が"非公表"の場合変換できずにエラーになるため、nanに変換して行ごと削除(dropna())する
df.iloc[:, 3] = df.iloc[:, 3].replace({'非公表': np.nan}).replace({'確認中': np.nan}).dropna() df.iloc[:, 3] = pd.to_datetime(df.iloc[:, 3], format = '%Y年%m月%d日')
3. 性別、年齢別に集計
実行環境ではグラフの出力に2バイト文字を使えないため漢字をアルファベットに変換している
まず性別だけを抜き出し、"Count_age()"で年齢ごとの数をカウントする
df_age = pd.DataFrame() for i in ['man', 'woman', 'undisclosed']: df_tmp = df df_tmp = df_tmp.replace({'男性': 'man', '女性': 'woman', '非公表': 'undisclosed'}) df_tmp = df_tmp[df_tmp['性別'].isin([i])] df_age = pd.concat([df_age, Count_age(df_tmp.iloc[:, 1])], axis = 1) df_age.columns = ['man', 'woman', 'undisclosed']
Count_age()はデータフレームを引数にして、インデックスの年代ごとに数をカウントする
def Count_age(df): df_index = {"90歳以上": "90 +", '80代': "80 - 89", '70代': "70 - 79", '60代': "60- 69", '50代': "50 - 59", '40代': "40 - 49", '30代': "30 - 39", '20代': "20 - 29", '10代': "10 - 19", "10歳未満": "0 - 9", "非公表": "undisclosed"} df = df.replace(df_index) df = df.dropna().value_counts() df = df.reindex(index = list(df_index.values())) return df
4. コードのまとめ
コードをまとめると次のようになる
import os, sys, datetime from pandas import Series, DataFrame import pandas as pd import numpy as np def Count_age(df): df_index = {"90歳以上": "90 +", '80代': "80 - 89", '70代': "70 - 79", '60代': "60- 69", '50代': "50 - 59", '40代': "40 - 49", '30代': "30 - 39", '20代': "20 - 29", '10代': "10 - 19", "10歳未満": "0 - 9", "非公表": "undisclosed"} df = df.replace(df_index) df = df.dropna().value_counts() df = df.reindex(index = list(df_index.values())) return df def Read_CSV_Files(Path_CSV, List_CSV): df = DataFrame() for i in List_CSV: try: df_tmp = pd.read_csv(Path_CSV + i, index_col = 0, encoding = 'shift_jis') except Exception as e: print('cannot open file: ', i) print(str(e)) sys.exit(1) else: print('we were able to open the file:', i) df = pd.concat([df, df_tmp]) return df if __name__ == '__main__': path = os.getcwd() path = os.chdir(os.path.dirname(os.path.abspath(__file__))) path = os.getcwd() List_DeathList = ['hogehoge.csv'] Path_CSV = path + '\\' + 'csv\\' df = Read_CSV_Files(Path_CSV, List_DeathList) df.iloc[:, 3] = df.iloc[:, 3].replace({'非公表': np.nan}).replace({'確認中': np.nan}).dropna() df.iloc[:, 3] = pd.to_datetime(df.iloc[:, 3], format = '%Y年%m月%d日') df_age = pd.DataFrame() for i in ['man', 'woman', 'undisclosed']: df_tmp = df df_tmp = df_tmp.replace({'男性': 'man', '女性': 'woman', '非公表': 'undisclosed'}) df_tmp = df_tmp[df_tmp['性別'].isin([i])] df_age = pd.concat([df_age, Count_age(df_tmp.iloc[:, 1])], axis = 1) df_age.columns = ['man', 'woman', 'undisclosed'] print(df_age)
いちいちコードを書いたけど何かしらもっと便利な方法が他にあるとは思う