pandasのpivot_tableで比較的簡単に処理できます。本記事では、データ処理の例として、愛知県の次のリンク先https://www.pref.aichi.jp/site/covid19-aichi/の中程にある新型コロナの「愛知県内の発生事例」のPDFファイル「8月まで [PDFファイル/357KB]」を使用しました。このPDFファイルは下図のような表が99ページに渡って複数あります。

本コードの実施例を以降に示します。本コードを実行すると、上記pdfファイルを読み取って、下図のようにcsvファイルを作成します。これを行うためのPythonライブラリは「PyPDF2 」と「camelot」を使用しています。

そして、下図のように感染者数が多い市町村順に横棒グラフ化します。これにより、視覚的に比較確認できます。

次に、下図のようにクロス集計を行ってcsvファイルにします。これを行うには、「pandas」のpivot_tableを使用すると簡単に作成できます。

最後に、配列(リスト)で指定した複数の市町村を下図のように時系列でグラフ化します。これにより、感染者数の変化を可視化できて比較できます。

■本プログラム
import warnings
from pathlib import Path
from tqdm import tqdm
from PyPDF2 import PdfFileReader
from PyPDF2 import PdfFileWriter
import pandas as pd
import camelot
import os
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import japanize_matplotlib
import datetime
now = datetime.datetime.now()
now = now.strftime("%y%m%d")
import time
def my_split_pdf_func(input_pdf):
file_name_list = []
with open(input_pdf, 'rb') as f1:
input = PdfFileReader(f1)
pgnum = input.getNumPages()
for i in range(pgnum):
file_name = str(i+1) + "page.pdf"
output = PdfFileWriter()
output.addPage(input.getPage(i))
outputfile = open(file_name, 'wb')
output.write(outputfile)
outputfile.close()
file_name_list.append(file_name)
print(file_name_list)
return file_name_list
def create_ranking_csv_img_func(DF, X_column, Y_column):
df = DF.dropna(subset=[X_column])
df = df.dropna(axis=1)
df = df.groupby([X_column]).size()
df = df.reset_index(name=Y_column)
df = df.sort_values(by=Y_column, ascending=True)
print(df)
df_x = df[X_column]
df_y = df[Y_column]
y_np = np.array(df_y)
plt.figure(figsize=(8,10))
plt.barh(range(len(df_x)), df_y, tick_label=df_x, align="center", color="magenta", height=0.8)
df_x_r = df_x.reset_index(drop=True)
with open(save_name + '_ranking.csv', 'a') as f:
for i, j in enumerate(y_np):
plt.text(j, (i+0.5), str(int(j)), ha='left', va='top')
mystr_list = [df_x_r[i], str(int(j)), '\n']
mystr = ','.join(mystr_list)
f.write(mystr)
plt.xlabel('count', fontsize=10)
if range_X:
plt.xlim([range_X[0], range_X[1]])
plt.grid(which="major", axis="x", color="black", alpha=0.8, linestyle="-", linewidth=1)
plt.tight_layout()
plt.savefig(save_name + '_ranking.png')
plt.close()
def create_time_series_plotgraph_func(DF, TIME, LEGEND, COUNT, Y_list):
print(DF)
print(TIME)
DF[TIME] = DF.apply(lambda a: f"{str(2020)}-{a[TIME]}", axis=1)
DF[TIME] = DF[TIME].str.replace('月', '-')
DF[TIME] = DF[TIME].str.strip('日')
DF[TIME] = pd.to_datetime(DF[TIME])
print(DF)
df = pd.pivot_table(DF,
index = TIME, # 発表日
columns = LEGEND, # 住居地
values = COUNT, # count
aggfunc='sum')
print(df)
df_sorted = df.sort_index()
cross_data_file_name = save_name + '_' + TIME + '_' + LEGEND + '_cross.csv'
df_sorted.to_csv(cross_data_file_name,
header = True,
index = True,
encoding = 'cp932',
sep = ',')
df = pd.read_csv(cross_data_file_name,
encoding='cp932')
fig = plt.figure(figsize=(15,6))
plt.style.use('bmh')
ax = fig.add_subplot(1,1,1)
for i, Y in enumerate(Y_list):
print(Y)
try:
df.plot(x=TIME,
y=Y,
kind='line',
ax=ax,
color=cm(i))
ax = plt.gca()
x_ticklabels = ax.get_xticklabels()
plt.setp(x_ticklabels, rotation=45, fontsize=14)
tick_spacing = 15
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
except KeyError:
pass
y_ticklabels = ax.get_yticklabels()
plt.setp(y_ticklabels, rotation=0, fontsize=16)
ax.set_xlabel(None)
ax.set_ylabel(COUNT, fontsize=16)
ax.grid(True)
plt.legend(bbox_to_anchor=(1.01, 1), loc='upper left', borderaxespad=0, fontsize=16)
plt.rcParams['font.size'] = 18
plt.subplots_adjust(right=0.7)
plt.tight_layout()
fig.savefig(cross_data_file_name + '.png')
plt.close()
def main():
page_pdf_path_list = my_split_pdf_func(pdf_path)
for page_pdf_path in tqdm(page_pdf_path_list):
table = camelot.read_pdf(page_pdf_path,
pages='1-end',
split_text=True,
strip_text='\n',
encoding='cp932')
try:
df = table[0].df
print(df)
except IndexError:
print('read error of pdf2df -> pass')
with open(now + '_' + file_name + '.csv',
mode="a", newline='', encoding="cp932", errors="ignore") as f:
df.to_csv(f,
index = False,
header = False,
mode = 'a',
encoding='utf-8')
os.remove(page_pdf_path)
df_csv = pd.read_csv(now + '_' + file_name + '.csv', header=0, index_col=0, encoding='cp932')
create_ranking_csv_img_func(df_csv, target_column, 'count')
df_new = df_csv.assign(count=1)
create_time_series_plotgraph_func(df_new, x_time, target_column, 'count', y_list)
if __name__ == '__main__':
pdf_path = '345284_愛知県8月まで.pdf'
file_name = Path(pdf_path).stem
save_name = now + "_" + file_name
target_column = '住居地'
range_X = ()
x_time = '発表日'
y_list = [
'名古屋市',
'豊田市',
'一宮市',
'岡崎市',
'刈谷市',
'日進市',
]
cm_name = 'gist_rainbow'
cm = plt.get_cmap(cm_name, len(y_list))
warnings.resetwarnings()
warnings.simplefilter('ignore', UserWarning)
start = time.time()
main()
print('run time: ', time.time() - start)
print('finished')
●関連記事
hk29.hatenablog.jp
hk29.hatenablog.jp
以上
<広告>
リンク