どこにでもいる30代SEの学習ブログ

主にプログラミング関連の学習内容。読んだ本の感想や株式投資についても書いてます。

日本株の基礎指標(PERや配当利回り)をpythonでスクレイピングを使って取得する (2)

f:id:predora005:20201123102206j:plain
*1

前回の続きです。前回は「みんなの株式」から、単一銘柄のPERや配当利回りスクレイピングで取得しました。今回は複数銘柄の情報を統合してみます。

predora005.hatenablog.com

[1] DataFrameにまとめる

pandasのDataFrameに複数銘柄の情報をまとめます。pandasはデータ分析用のライブラリです。DataFrameはpandasの基本構造で表形式のデータです。

[1-1] pandasのインストール

pip3 install numpy  --user
pip3 install pandas --user

[1-2] DataFrameの作成

鉄道関係 5銘柄の情報を取得し、DataFrameにまとめます。get_basic_infoは前回の内容を関数化したものです。

jre_dict = get_basic_info(9020) # JR東日本
jrc_dict = get_basic_info(9022) # JR東海
jrw_dict = get_basic_info(9021) # JR西日本
tokyu_dict = get_basic_info(9005) # 東急
kintetsu_dict = get_basic_info(9041) # 近鉄

jre_sr = pd.Series(jre_dict.values(), index=jre_dict.keys(), name='JR東日本')
jrc_sr = pd.Series(jrc_dict.values(), index=jrc_dict.keys(), name='JR東海')
jrw_sr = pd.Series(jrw_dict.values(), index=jrw_dict.keys(), name='JR西日本')
tokyu_sr = pd.Series(tokyu_dict.values(), index=tokyu_dict.keys(), name='東急')
kintetsu_sr = pd.Series(kintetsu_dict.values(), index=kintetsu_dict.keys(), name='近鉄')

df = pd.DataFrame([jre_sr, jrw_sr, jrc_sr, tokyu_sr, kintetsu_sr])

結果、以下のような内容にまとめることができました。

始値 高値 安値 配当利回り ...
JR東日本 6,510.0円 6,580.0円 6,479.0円 2.53% ...
JR東海 14,280.0円 14,450.0円 14,280.0円 1.04% ...
JR西日本 5,000.0円 5,078.0円 4,959.0円 3.59% ...
東急 1,372.0円 1,379.0円 1,360.0円 1.67% ...
近鉄 4,745.0円 4,770.0円 4,720.0円 1.05% ...

[2] 単位を削る

'円'や'%'などの単位が付与された状態ですが、平均値を出す場合など計算する際には邪魔になります。DataFrameから単位を削っていきます。

[2-1] 正規表現を使う

正規表現を使って、不要なものを削っていきます。

以下は株価(始値, 高値)の例です。カンマと円が不要なので削っていきます。株価は銘柄ごとに異なっており、5桁のものもあれば3桁のものもあるため、どれにも対応できるようにしています。

import re

yen = '1,234.5円'

# 正規表現で'円'より前の文字列を抽出
yen_re = re.search(r"([+-]?\d{1,3}(,\d{3})*\.\d+)円", yen)
yen = yen_re.group(1)

# カンマを削除
yen = value.replace(',', '')

# 実数に変換
yen = float(yen)

print(yen)
# 1234.5

[2-2] すべての列に適用する

[2-1]と同様の処理を、すべての列に適用します。DataFrameのmapメソッドを使い、列ごとに変換処理を行っていきます。

[2-2-1] 変換用の関数を用意する

まずは、以下のような変換関数を用意します。円, 株といった単位ごとに関数を用意してもよいのですが、面倒なので全単位に対応できる関数を用意しました。

# 単位を削除する関数
def trim_unit(x):
    
    # 単位=円を削除
    yen_re = re.search(r"(\d{1,3}(,\d{3})*\.\d+)円", x)
    if yen_re:
        value = yen_re.group(1)
        value = value.replace(',', '')
        return np.float64(value)
    
    # 単位=%を削除
    perc_re = re.search(r"(\d+\.\d+)%", x)
    if perc_re:
        value = perc_re.group(1)
        return np.float64(value)
    
    # 単位=株を削除
    stock_re = re.search(r"(\d{1,3}(,\d{3})*)株", x)
    if stock_re:
        value = stock_re.group(1)
        value = value.replace(',', '')
        return np.int64(value)
    
    # 単位=倍を削除
    times_re = re.search(r"(\d+\.\d+)倍", x)
    if times_re:
        value = times_re.group(1)
        return np.float64(value)
    
    # 単位=百万円を削除
    million_yen_re = re.search(r"(\d{1,3}(,\d{3})*)百万円", x)
    if million_yen_re:
        value = million_yen_re.group(1)
        value = value.replace(',', '')
        value = np.int64(value) * 1000000
        return value
    
    # 単位=千株を削除
    thousand_stock_re = re.search(r"(\d{1,3}(,\d{3})*)千株", x)
    if thousand_stock_re:
        value = thousand_stock_re.group(1)
        value = value.replace(',', '')
        value = np.int64(value) * 1000
        return value
    
    return x

[2-2-2] map関数で各列に変換処理を行う

pandasのmap関数を使用して、上に挙げたtrim_unitを各列に対して適用します。

# 各列に対して、trim_unitを適用する
new_df = df.copy()
for col in df.columns:
    new_df[col] = new_df[col].map(lambda v : trim_unit(v))

[3] 各列の統計量を算出する

[3-1] 平均値と標準偏差の算出

単位を削り数値に変換できたので、各列の平均値と標準偏差を求めます。

mean = new_df.mean() # 平均値
std = new_df.std() # 標準偏差

求めた平均値と標準偏差をDataFrameにまとめると、以下の結果が得られました。

statistics = pd.DataFrame(
    {'平均値': new_df.mean(), '標準偏差': new_df.std()})
平均値 標準偏差
始値 6381.4 4798.0
高値 6451.4 4858.9
安値 6359.6 4806.1
配当利回り 1.976 1.088
単元株数 100 0
PER(調整後) 18.738 14.714
PSR 0.91 0.39
PBR 1.118 0.628
出来高 1.081580e+06 5.990959e+05
時価総額 1.629025e+12 1.001244e+12
発行済株数 3.181594e+08 1.887879e+08

[3-2] 統計量と各銘柄データを結合

求めた統計量を、各銘柄のデータと結合して比較してみます。

ここで比較に役に立たないと思われるデータは削ります。また、出来高時価総額は桁数が多いので、見やすい桁数になるように単位を変換します。

# 各銘柄のデータと統計量を結合する。
new_df2 = new_df.append(statistics.T)

# 出来高と時価総額の単位を変換する。
new_df2['出来高'] = new_df2['出来高'] / 1.0e+3
new_df2['時価総額'] = new_df2['時価総額'] / 1.0e+12
new_df2 = new_df2.rename(columns=
            {'出来高': '出来高(千株)', '時価総額': '時価総額(兆円)'})

# 不要な列を削除する。
new_df2 = new_df2.drop(columns=
            ['始値', '高値', '安値', '単元株数', '発行済株数', '購入金額'])

以下だけで読み取れる情報は未だ少ないですが、近鉄のみPER, PBRが大きいと分かります。

配当利回り PER(調整後) PSR PBR 出来高(千株) 時価総額(兆円) 株主優待
JR東日本 2.53 12.39 0.83 0.77 1965.8 2.458450 株主優待割引券、自社施設サービス券、人間ドック割引券
JR東海 1.04 7.07 1.60 0.76 701.9 2.957130 株主優待乗車証
JR西日本 3.59 10.85 0.64 0.79 1247.9 0.970065 鉄道優待、グループ優待
東急 1.67 19.61 0.73 1.05 1104.6 0.856696 株主優待乗車証、自社グループ優待券
近鉄 1.05 43.77 0.75 2.22 387.7 0.902784 株主優待乗車証、自社施設割引券
平均値 1.98 18.74 0.91 1.12 1081.6 1.629025 NaN
標準偏差 1.09 14.71 0.39 0.63 599.1 1.001244 NaN

終わりに

今回は複数銘柄の基本指標を取得し、比較するところまで行いました。次回は、決算情報の取得を行います。

predora005.hatenablog.com

*1:Lorenzo CafaroによるPixabayからの画像