有価証券報告書内の表をデータとして活用できないか、Pythonで読み込んでみたいと思います。
今回使う有価証券報告書は某夢の国を運営している会社です。
この銘柄を選んだ理由は妻が行きたいと願いつつ、チケットが高額なのであまり
行けていないことから、優待でチケットを入手できれば、と思ったことがきっかけです。
では早速、読み込んでいきたいと思います。
まずはライブラリをimportします。
import pandas as pd import numpy as np import tabula
次にtabula-pyを使ってPDFファイルを読み込みます。
ページを指定して、概況、貸借対照表、損益計算書、キャッシュフローをデータにします。
dfs = tabula.read_pdf('test_pdf.pdf', lattice=True, pages=['2', '71-74', '77']) for df in dfs: display(df) # Jupyter notebookの環境で実行可能なコード #-------------------------------------------------- # 回次 第 59 期 第 60 期 第 61 期 第 62 期 第 63 期 Unnamed: 0 #0 決算年月 2019年3月 2020年3月 2021年3月 2022年3月 2023年3月 NaN #1 売上高 百万円 データ割愛 #2 経常利益又は経常損失\r(△) 百万円 # ⁞ # Unnamed: 0 Unnamed: 1 (単位:百万円 #0 NaN 前連結会計年度\r(2022年3月31日) 当連結会計年度\r(2023年3月31日) #1 資産の部 データ割愛 #2 流動資産 # ⁞ # Unnamed: 0 Unnamed: 1 (単位:百万円 #0 NaN 前連結会計年度\r(2022年3月31日) 当連結会計年度\r(2023年3月31日) #1 負債の部 データ割愛 #2 流動負債 # ⁞ #<以下省略>
type(dfs) #-------------------------------------------------- #list
type(dfs[0]) #-------------------------------------------------- #pandas.core.frame.DataFrame
dfsはist、その中にDataFrameとして格納されている状態であることが確認できます。
まずは企業の概況をデータにしますが、行名などがずれているので気持ちよくないから調整します。
gaikyo = pd.DataFrame(columns=['単位', dfs[0].columns[1], dfs[0].columns[2], dfs[0].columns[3], dfs[0].columns[4], dfs[0].columns[5]], index=[dfs[0].iloc[:, 0]]) gaikyo #-------------------------------------------------- # 単位 第 59 期 第 60 期 第 61 期 第 62 期 第 63 期 #回次 #決算年月 NaN NaN NaN NaN NaN NaN #売上高 NaN NaN NaN NaN NaN NaN #経常利益又は経常損失\r(△) NaN NaN NaN NaN NaN NaN # ⁞
dfs[0].columns[i]みたいな形で楽な記述ができればいいのですが、今の時点では割愛します。
割愛と言いますか、今はアイデアがないので後回しです。
あと、回次のところが不要ですね。
gaikyo.columns #-------------------------------------------------- #Index(['単位', '第 59 期', '第 60 期', '第 61 期', '第 62 期', '第 63 期'], dtype='object')
columnsにも入っていないようです。
ilocで全行をindexに入れると行名の元々の行名の回次がcolumnsでもないところに入ってしまいます。
回次が気持ち悪いから消していきます。
ついでに\rをreplaceします。
index_name = [] for i in range(0, len(dfs[0])): index_name.append(dfs[0].iloc[i, 0].replace('\r', '')) gaikyo = pd.DataFrame(columns=['単位', dfs[0].columns[1], dfs[0].columns[2], dfs[0].columns[3], dfs[0].columns[4], dfs[0].columns[5]], index=[index_name]) gaikyo #-------------------------------------------------- # 単位 第 59 期 第 60 期 第 61 期 第 62 期 第 63 期 #決算年月 NaN NaN NaN NaN NaN NaN #売上高 NaN NaN NaN NaN NaN NaN #経常利益又は経常損失(△) NaN NaN NaN NaN NaN NaN #親会社株主に帰属する… NaN NaN NaN NaN NaN NaN # ⁞ #現金及び現金同等物の期末残高 NaN NaN NaN NaN NaN NaN #従業員数[外、平均臨時雇用者数] NaN NaN NaN NaN NaN NaN
使うかどうかもわかりませんが、一番最後の従業員数、平均臨時従業員数も
列を分けれたら収まりがいいので実現させていこうと思います。
index_name = [] for i in range(0, len(dfs[0])-1): index_name.append(dfs[0].iloc[i, 0].replace('\r', '')) tmp_list = dfs[0].iloc[-1, 0].replace('\r', '').replace(']', '').split('[') index_name.extend(tmp_list) gaikyo = pd.DataFrame(columns=['単位', dfs[0].columns[1], dfs[0].columns[2], dfs[0].columns[3], dfs[0].columns[4], dfs[0].columns[5]], index=[index_name]) gaikyo #-------------------------------------------------- # 単位 第 59 期 第 60 期 第 61 期 第 62 期 第 63 期 #決算年月 NaN NaN NaN NaN NaN NaN #売上高 NaN NaN NaN NaN NaN NaN #経常利益又は経常損失(△) NaN NaN NaN NaN NaN NaN #親会社株主に帰属する… NaN NaN NaN NaN NaN NaN # ⁞ #従業員数 NaN NaN NaN NaN NaN NaN #外、平均臨時雇用者数 NaN NaN NaN NaN NaN NaN
決算月は単位がいらないから1列ずらして格納。
その他従業員以外のデータはそのまま格納していきます。
gaikyo.iloc[0, 1:] = dfs[0].iloc[0, 1:6] for i in range(1, len(dfs[0])-1): gaikyo.iloc[i, :] = dfs[0].iloc[i, 1:] gaikyo #-------------------------------------------------- # 単位 第 59 期 第 60 期 第 61 期 第 62 期 第 63 期 #決算年月 データ割愛 #売上高 #経常利益又は経常損失(△) #親会社株主に帰属する… # ⁞ #現金及び現金同等物の期末残高 #従業員数 NaN NaN NaN NaN NaN NaN #外、平均臨時雇用者数 NaN NaN NaN NaN NaN NaN
従業員数なども入れていきます。
for i in range(0, gaikyo.shape[1]): for j in range(-1, -3, -1): if i == 0: gaikyo.iloc[j, i] = dfs[0].iloc[-1, i+1] else: tmp_list = dfs[0].iloc[-1, i+1].replace('\r', '').replace(']', '').split('[') gaikyo.iloc[j, i] = tmp_list[j] gaikyo #-------------------------------------------------- # 単位 第 59 期 第 60 期 第 61 期 第 62 期 第 63 期 #決算年月 データ割愛 #売上高 #経常利益又は経常損失(△) #親会社株主に帰属する… # ⁞ #現金及び現金同等物の期末残高 #従業員数 #外、平均臨時雇用者数
概況の表はindexと要素は対応した形にできましたので、数字として計算できるように
文字列から数値に変換していきます。
その前にマイナスを表す△を-に置き換え、,を消します。
for i in range(0, gaikyo.shape[0]): for j in range(0, gaikyo.shape[1]): if type(gaikyo.iloc[i, j]) != float: gaikyo.iloc[i, j] = gaikyo.iloc[i, j].replace('△', '-') gaikyo.iloc[i, j] = gaikyo.iloc[i, j].replace(',', '') gaikyo #-------------------------------------------------- # 単位 第 59 期 第 60 期 第 61 期 第 62 期 第 63 期 #決算年月 データ割愛 #売上高 #経常利益又は経常損失(△) #親会社株主に帰属する… # ⁞ #現金及び現金同等物の期末残高 #従業員数 #外、平均臨時雇用者数
今、この状態ですと要素の型はstrです。
なので、型を変換します。
PERは利益がマイナスだとハイフンになっているので、データなしとしてnanを入れます。
for i in range(1, gaikyo.shape[0]): for j in range(1, gaikyo.shape[1]): if '.' in gaikyo.iloc[i, j]: gaikyo.iloc[i, j] = float(gaikyo.iloc[i, j]) elif gaikyo.iloc[i, j] == '-': gaikyo.iloc[i, j] = np.nan else: gaikyo.iloc[i, j] = int(gaikyo.iloc[i, j]) type(gaikyo.iloc[-1, -1]) #-------------------------------------------------- #int
一番最後の要素もintに変わっているので有価証券報告書の最初の方にある概況は
数値として扱えるように変換できました。
同じ書き方をしている表であればファイル名を変えるだけでPythonで扱えますが、
恐らく違いが出てくると思いますので完全自動化は難しそうです。
それでも、こういったプログラムは作っていきたいと考えてます。
有価証券報告書のデータをそのまま載せるわけにはいかないのでデータが
どう変わっていくか示せませんが、興味のある方は試してみてください。