ROE(自己資本利益率)と ROA(総資産利益率)は、企業の「稼ぐ力」を見るための代表的な指標です。本記事では両者の定義・違い・デュポン分解の入口を整理し、pandas で複数銘柄を一括計算する例を示します。
目次
- ROE とは
- ROA とは
- ROE と ROA の関係
- デュポン分解の入口
- 単一銘柄を計算する
- 複数銘柄を pandas で一括計算する
- デュポン分解を pandas で計算する
- ROE / ROA を読むときの注意
ROE とは
ROE(Return on Equity)は「株主資本(純資産)が、年間でどれだけ純利益を生み出したか」を表します。
たとえば純利益 100 億円、自己資本 1,000 億円なら、ROE = 10%。株主から預かった資本に対して、年間 10% のリターンを稼いだという意味です。
ROE が高いほど 株主資本を効率よく利益に変換できている と解釈できます。投資家視点から重要な指標とされる理由です。
ROA とは
ROA(Return on Assets)は「会社の総資産が、年間でどれだけ純利益を生み出したか」を表します。
総資産は自己資本だけでなく、借入金などの負債も含みます。ROA が高いほど、借入を含めた事業全体 の収益効率が高いことを意味します。
ROE と ROA の関係
両者の関係は次の式で書けます。
「総資産 / 自己資本」を 財務レバレッジ と呼びます。借入が多いほどレバレッジは大きく、ROE は ROA より大きくなります。同じ ROA でも、レバレッジが高い会社の ROE は 見かけ上高く なる構造です。
「ROE が高い銘柄を選ぶ」場合、財務レバレッジで稼いでいるのか、本業の収益力で稼いでいるのかを区別する必要があります。
デュポン分解の入口
ROE は次のように 3 つに分解できます。これを デュポン分解 と呼びます。
それぞれの項に名前があります。
- 第 1 項: 売上高純利益率(Net Profit Margin)
- 第 2 項: 総資産回転率(Asset Turnover)
- 第 3 項: 財務レバレッジ(Equity Multiplier)
ROE が同じでも、3 項の内訳が違う会社は 稼ぎ方 が違います。たとえば次のように対比できます。
| 業態 | 利益率 | 回転率 | レバレッジ |
|---|---|---|---|
| 高級ブランド | 高い | 低い | 中程度 |
| ディスカウントストア | 低い | 高い | 中程度 |
| 銀行 | 低い | 低い | 高い |
「同じ ROE 10%」でも、内訳が違えば事業の性質も違います。
単一銘柄を計算する
サンプル値で計算する例です。
def roe(net_income: float, equity: float) -> float | None: """ROE(%)を返す。equity が 0 / 負の場合は None。""" if equity is None or equity <= 0: return None return net_income / equity * 100
def roa(net_income: float, assets: float) -> float | None: if assets is None or assets <= 0: return None return net_income / assets * 100
print(round(roe(100, 1000), 2)) # 10.0print(round(roa(100, 5000), 2)) # 2.0ROE は数十%、ROA は数%が現実的な水準です。ROA が ROE を上回る場合は、無借金または資産構成に何か特殊な事情がある可能性があり、確認が必要です。
複数銘柄を pandas で一括計算する
財務データの DataFrame を入力に取る前提です。
import numpy as npimport pandas as pd
df = pd.DataFrame({ "Code": ["1301", "1302", "1303", "1304", "1305"], "CoName": ["サンプル商事001", "サンプル商事002", "サンプル商事003", "サンプル商事004", "サンプル商事005"], "NP": [4_900_000_000_000, 1_500_000_000_000, 970_000_000_000, 700_000_000_000, -200_000_000_000], "Eq": [27_000_000_000_000, 13_000_000_000_000, 7_500_000_000_000, 3_300_000_000_000, 6_000_000_000_000], "TA": [70_000_000_000_000, 380_000_000_000_000, 30_000_000_000_000, 4_500_000_000_000, 36_000_000_000_000],})
df["roe"] = np.where(df["Eq"] > 0, df["NP"] / df["Eq"] * 100, np.nan)df["roa"] = np.where(df["TA"] > 0, df["NP"] / df["TA"] * 100, np.nan)df = df.assign(roe=df["roe"].round(2), roa=df["roa"].round(2))
print(df[["Code", "CoName", "roe", "roa"]])赤字銘柄(サンプル商事005)は ROE / ROA が 負 になります。負を含めて表示するか、フィルタで除外するかは目的に応じて決めます。
なお、上記サンプル値は説明用の 架空の概算 です。実値は J-Quants API の財務データから取得します(#6-6「財務情報を取得する (/fins/summary)」)。
デュポン分解を pandas で計算する
3 項に分解した値を列として持っておくと、後の比較が楽になります。
df["Sales"] = [40_000_000_000_000, 9_000_000_000_000, 13_000_000_000_000, 2_500_000_000_000, 6_500_000_000_000] # 売上高
df["margin"] = df["NP"] / df["Sales"] * 100df["turnover"] = df["Sales"] / df["TA"]df["leverage"] = df["TA"] / df["Eq"]df["roe_check"] = df["margin"] * df["turnover"] * df["leverage"] / 100# roe_check が roe と概ね一致することを確認
cols = ["Code", "CoName", "margin", "turnover", "leverage", "roe", "roe_check"]print(df[cols].round(3))roe と roe_check の差が大きい場合、計算上の丸め誤差・データの粒度ずれが疑われます。
ROE / ROA を読むときの注意
ROE / ROA を実用するときに踏まえたいポイントです。
- 単年で評価しない: 特別損益で利益が大きくぶれる年がある。3〜5 年の平均で見る
- 業種で水準が違う: 銀行業はレバレッジが高く ROE が高めに見える
- 過剰なレバレッジは脆さ: 高 ROE が借入依存の場合、金利上昇 / 業績悪化で大きく崩れる
- 自社株買いで ROE が上がる: 純資産を減らすことでも ROE は上昇する。継続的な収益力とは別の話
「ROE 8% が日本のひとつの目安」と言われることがありますが、業種や事業ステージで適切な水準は変わります。
生成AI へのプロンプト例
3 期分のデュポン分解を時系列で並べたい場合の例です。
入力 DataFrame に次の列があります(財務項目は J-Quants API に準拠)。- Code (str)- fiscal_year (int): 2022, 2023, 2024- NP (float)- Sales (float)- TA (float)- Eq (float)
依頼:- Code × fiscal_year ごとに margin, turnover, leverage, roe, roa を計算- 戻り値は元の列に上記指標を追加した DataFrame- Eq <= 0 / TA <= 0 の場合は当該指標を NaN
要件: pandas 2.2 系。関数化し、docstring は日本語。まとめ
- ROE は株主資本に対する利益率、ROA は総資産に対する利益率
- ROE = ROA × 財務レバレッジ。レバレッジで見かけの ROE が上がる構造に注意
- デュポン分解で「利益率 / 回転率 / レバレッジ」に分けると稼ぎ方が見える
- 単年でなく複数年で見る。業種で水準が違うことも踏まえる