06. 経営分析の基本モデル
テーマ: CVP分析(損益分岐点・安全余裕率・営業レバレッジ)
学習点: dataclass, プロパティ, 逆算(目標利益からの必要数量)
依存: 標準ライブラリのみ / 難易度: 基礎
実行方法
uv run 06_cvp_breakeven.py
スクリプト冒頭の PEP 723 メタデータ(# /// script)により、必要なライブラリは
uv が自動的に仮想環境へ導入します。事前の pip install は不要です。
解説
何をするプログラムか
CVP 分析(Cost-Volume-Profit analysis)は、原価・販売数量・利益の関係を単純な線形モデルで捉える、管理会計の最も基本的な道具です。このスクリプトは、単価 2,500 円・単位変動費 1,400 円・固定費 880 万円という製品を例に、損益分岐点(利益がゼロになる販売数量と売上高)、販売数量ごとの営業利益・安全余裕率・営業レバレッジ(DOL)、そして目標利益 500 万円を達成するために必要な数量を計算します。
最後に感度分析として、固定費・変動費・単価をそれぞれ 10% 動かしたときに損益分岐点がどれだけ動くかを比較し、どのパラメータが利益構造に最も効くかを確認します。
コードの読みどころ
@dataclassを付けたCVPクラスは、price・variable_cost・fixed_costの 3 つのフィールドを宣言するだけで__init__が自動生成されます。感度分析ではCVP(m.price, m.variable_cost, m.fixed_cost * 1.1)のように条件を変えたインスタンスを 1 行で作れるのがその恩恵です。@propertyを付けたcontribution(限界利益)やbreakeven_qty(損益分岐点数量)は、m.breakeven_qtyと属性のように参照できる「計算される値」です。フィールドに保存せず毎回計算するため、前提を変えた別インスタンスでも常に整合した値が得られます。breakeven_qtyは限界利益が非正のときraise ValueError(...)で異常を知らせます。分母がゼロや負のまま計算を続けない防御的な書き方です。qty_for_profit()は損益分岐点の式を「利益 = 目標値」に置き換えて数量について解いた(F + target) / (p - v)を返します。公式の逆算がそのまま 1 行のコードになる例です。dol()は営業利益がちょうどゼロ(損益分岐点上)のときfloat("inf")を返します。実行結果の表で数量 8,000 個の行にinfが出るのはこのためです。
理論的背景
損益分岐点数量は Q* = F / (p − v) で与えられます。分母の (p − v) は 1 個売るごとに固定費回収と利益に貢献する金額で、限界利益(貢献利益)と呼ばれます。安全余裕率は現在の売上が損益分岐点売上をどれだけ上回っているかの割合です。営業レバレッジ度 DOL = 限界利益 ÷ 営業利益 は「売上が 1% 変化したとき営業利益が何 % 変化するか」という弾力性で、固定費の大きい事業ほど大きくなり、好況にも不況にも利益が敏感になることを示します。
実行結果の見方
表を見ると、損益分岐点の 8,000 個を境に営業利益が負から正へ転じ、DOL は分岐点直後の 10,000 個で 5.00 と大きく、15,000 個では 2.14 へと低下します。分岐点に近いほど利益が売上変動に敏感である、という DOL の性質が数値で確認できます。感度分析では、固定費 ±10% が損益分岐点を ±10.0% と比例的に動かすのに対し、単価 +10% は −18.5% と最も大きく効いています。値上げ(または値引き回避)が利益構造に与える影響の大きさを示す結果です。
ソースコード
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""06: 経営分析の基本モデル -----------------------------------------------
テーマ: CVP分析(損益分岐点・安全余裕率・営業レバレッジ)
学習点: dataclass, プロパティ, 逆算(目標利益からの必要数量)
根拠: 損益分岐点数量 Q* = F / (p - v)。 (p-v) は限界利益(貢献利益)。
営業レバレッジ DOL = 限界利益 / 営業利益 は、売上1%変化に対する
営業利益の変化率(%)を表す弾力性である。
"""
from dataclasses import dataclass
@dataclass
class CVP:
price: float # 販売単価 p
variable_cost: float # 単位変動費 v
fixed_cost: float # 固定費 F
@property
def contribution(self) -> float:
"""単位当たり限界利益 p - v"""
return self.price - self.variable_cost
@property
def cm_ratio(self) -> float:
"""限界利益率 (p-v)/p"""
return self.contribution / self.price
@property
def breakeven_qty(self) -> float:
if self.contribution <= 0:
raise ValueError("限界利益が非正のため損益分岐点が存在しません")
return self.fixed_cost / self.contribution
@property
def breakeven_sales(self) -> float:
return self.breakeven_qty * self.price
def profit(self, qty: float) -> float:
return self.contribution * qty - self.fixed_cost
def qty_for_profit(self, target: float) -> float:
"""目標営業利益を達成する必要販売数量"""
return (self.fixed_cost + target) / self.contribution
def dol(self, qty: float) -> float:
"""営業レバレッジ度(qty 時点)"""
op = self.profit(qty)
if op == 0:
return float("inf")
return self.contribution * qty / op
def main() -> None:
m = CVP(price=2500, variable_cost=1400, fixed_cost=8_800_000)
print(f"単価 {m.price:,}円 / 単位変動費 {m.variable_cost:,}円 / "
f"固定費 {m.fixed_cost:,}円")
print(f"限界利益 {m.contribution:,.0f}円/個 限界利益率 {m.cm_ratio:.1%}")
print(f"損益分岐点 {m.breakeven_qty:,.0f}個 = 売上 {m.breakeven_sales:,.0f}円\n")
print(f"{'販売数量':>9}{'売上高':>13}{'営業利益':>13}{'安全余裕率':>11}{'DOL':>8}")
for q in [6000, 8000, 10000, 12000, 15000]:
sales = q * m.price
margin = (sales - m.breakeven_sales) / sales # 安全余裕率
print(f"{q:>9,}{sales:>13,.0f}{m.profit(q):>13,.0f}"
f"{margin:>11.1%}{m.dol(q):>8.2f}")
print(f"\n目標利益 500万円に必要な数量: {m.qty_for_profit(5_000_000):,.0f}個")
print("\n[感度分析] 固定費 ±10% / 変動費 ±10% が損益分岐点に与える影響")
base = m.breakeven_qty
for label, obj in [
("固定費 +10%", CVP(m.price, m.variable_cost, m.fixed_cost * 1.1)),
("固定費 -10%", CVP(m.price, m.variable_cost, m.fixed_cost * 0.9)),
("変動費 +10%", CVP(m.price, m.variable_cost * 1.1, m.fixed_cost)),
("単価 +10%", CVP(m.price * 1.1, m.variable_cost, m.fixed_cost)),
]:
q = obj.breakeven_qty
print(f" {label}: {q:>9,.0f}個 ({q / base - 1:+.1%})")
print(" ※ 単価変更は限界利益率を通じて最も大きく効く。")
if __name__ == "__main__":
main()
実行結果
単価 2,500円 / 単位変動費 1,400円 / 固定費 8,800,000円
限界利益 1,100円/個 限界利益率 44.0%
損益分岐点 8,000個 = 売上 20,000,000円
販売数量 売上高 営業利益 安全余裕率 DOL
6,000 15,000,000 -2,200,000 -33.3% -3.00
8,000 20,000,000 0 0.0% inf
10,000 25,000,000 2,200,000 20.0% 5.00
12,000 30,000,000 4,400,000 33.3% 3.00
15,000 37,500,000 7,700,000 46.7% 2.14
目標利益 500万円に必要な数量: 12,545個
[感度分析] 固定費 ±10% / 変動費 ±10% が損益分岐点に与える影響
固定費 +10%: 8,800個 (+10.0%)
固定費 -10%: 7,200個 (-10.0%)
変動費 +10%: 9,167個 (+14.6%)
単価 +10%: 6,519個 (-18.5%)
※ 単価変更は限界利益率を通じて最も大きく効く。