有価証券報告書内の表をデータとして活用できないか、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で扱えますが、
恐らく違いが出てくると思いますので完全自動化は難しそうです。
それでも、こういったプログラムは作っていきたいと考えてます。
有価証券報告書のデータをそのまま載せるわけにはいかないのでデータが
どう変わっていくか示せませんが、興味のある方は試してみてください。

