🎓 レベル:標準 | 重要度:B(標準)
📎 関連:価格最適化(利益最大化) | 前提:需要曲線と価格弾力性
要点(BLUF)
- 価格最適化(利益最大化) の答えは「単一の静的な最適価格」でした。これは需要曲線の下に残る三角形(消費者余剰・取りこぼし需要)を捨てています。価格差別——セグメント別・時間別に価格を変える——でこれを拾うと利益が増えます。例(2セグメント、限界費用 )では、セグメント別最適の合計利益 3,275 が単一価格の 約3,008 を 約267 上回ります。ただし裁定(転売)防止とセグメント識別が前提です。
- バンドル(まとめ売り)の鍵は、支払意思額(WTP)の異質性をならすこと。WTP が負相関なら、バンドルは個別販売より利益が増えます(Adams–Yellen 1976 の古典)。例(2消費者×2財、限界費用0)では、純バンドルの売上 20 が個別販売の 16 に勝ちます。WTP が正相関だと、この優位は消えます。
- 心理価格(端数価格=¥1,980 の left-digit 効果、アンカリング、文脈依存)は行動経済学的な値付けで、数理モデルは弱い。効果は思い込みでなく実験(A/Bテスト)で測るのが基本です(→ 第7章)。これら3つはいずれも 03-02 の静的単一価格モデルの拡張・補完です。
1. 価格差別・動的価格:単一価格は需要を取りこぼす
価格最適化(利益最大化) では、ひとつの市場にひとつの最適価格 を求めました。しかし顧客の支払意思額(WTP)はばらばらです。単一価格では、 より高く払ってもよかった顧客から取りこぼし(消費者余剰の放置)、 では高すぎて買わなかった顧客も取りこぼし(販売機会の放置)ています。需要曲線の下・限界費用の上に残るこの面積を取りにいくのが**価格差別(price discrimination)**です。慣習的に3つの級に分けます。
- 第1級(完全価格差別):各単位をその顧客の WTP ちょうどで売る。消費者余剰をすべて企業が取る理論的上限。現実には WTP を個別に知るのが難しい。
- 第2級:数量やバージョンで価格を変え、顧客に自己選択させる。数量割引、松竹梅のメニュー(→ 第4章の選択モデルとつながる)。
- 第3級:識別できるセグメントごとに別価格をつける。学割・シニア割・地域別、そして時間別の動的価格(曜日・時間帯・需給)もこの仲間です。
flowchart TD
S["単一の静的価格 P*"] --> L["需要曲線の下の三角形(消費者余剰・取りこぼし需要)を捨てる"]
L --> D{"どう差をつける?"}
D -->|"顧客ごとにWTPで"| D1["第1級:各単位をWTPで(理論的な上限)"]
D -->|"数量・バージョンで自己選択"| D2["第2級:数量割引・松竹梅メニュー"]
D -->|"識別できるセグメント・時間で"| D3["第3級:学割・地域別・時間別(動的価格)"]
数値例(第3級)。限界費用は両セグメント共通で 。2つのセグメントが線形需要を持つとします。
各セグメントは独立した市場なので、価格最適化(利益最大化) の線形需要の閉形式 をそのまま当てはめられます。
利益はそれぞれ 、、合計 3,275。いっぽう、両セグメントにひとつの価格しかつけられない場合(裁定が防げず、識別もできない場合)、合算需要は で 。利益 を最大化すると 、利益 です。差し引き 約267 が価格差別の取り分になります。
import numpy as np
from scipy.optimize import minimize_scalar
c = 10.0 # 限界費用(両セグメント共通)
# 2セグメントの線形需要
def Q1(P): return np.maximum(100 - P, 0) # 高WTP・非弾力的
def Q2(P): return np.maximum(120 - 2 * P, 0) # 低WTP・弾力的
def profit_seg(P, Q): return (P - c) * Q(P)
# (A) セグメント別に最適価格を求める(第3級価格差別)
r1 = minimize_scalar(lambda P: -profit_seg(P, Q1), bounds=(c, 100), method="bounded")
r2 = minimize_scalar(lambda P: -profit_seg(P, Q2), bounds=(c, 60), method="bounded")
P1, P2 = r1.x, r2.x
pi1, pi2 = profit_seg(P1, Q1), profit_seg(P2, Q2)
pi_discrim = pi1 + pi2
# (B) 単一価格:両セグメント合算需要 Q=Q1+Q2 に1つの価格をつける
def Q_total(P): return Q1(P) + Q2(P)
def profit_single(P): return (P - c) * Q_total(P)
rs = minimize_scalar(lambda P: -profit_single(P), bounds=(c, 100), method="bounded")
P_single = rs.x
pi_single = profit_single(P_single)
print("=== 価格差別 vs 単一価格(c=10)===")
print("セグメント別最適:")
print(f" S1(Q=100-P) : P1* = {P1:.1f}, Q1 = {Q1(P1):.0f}, pi1 = {pi1:,.0f}")
print(f" S2(Q=120-2P): P2* = {P2:.1f}, Q2 = {Q2(P2):.0f}, pi2 = {pi2:,.0f}")
print(f" 価格差別の合計利益 = {pi_discrim:,.0f}")
print("単一価格(合算需要 Q=220-3P):")
print(f" P* = {P_single:.2f}, Q = {Q_total(P_single):.0f}, pi = {pi_single:,.2f}")
print(f"価格差別の利得 = {pi_discrim - pi_single:+,.2f}")
print("→ セグメント別に値付けする方が利益が大きい(取りこぼし需要を拾える)。")
出力:
=== 価格差別 vs 単一価格(c=10)===
セグメント別最適:
S1(Q=100-P) : P1* = 55.0, Q1 = 45, pi1 = 2,025
S2(Q=120-2P): P2* = 35.0, Q2 = 50, pi2 = 1,250
価格差別の合計利益 = 3,275
単一価格(合算需要 Q=220-3P):
P* = 41.67, Q = 95, pi = 3,008.33
価格差別の利得 = +266.67
→ セグメント別に値付けする方が利益が大きい(取りこぼし需要を拾える)。
出力の意味:非弾力的な S1 には高め(55)、弾力的な S2 には安め(35)と別々の価格をつけると、合計利益は 3,275。これは単一価格(最適 )の 3,008.33 を 266.67(約267)上回ります。直感は明快です——単一価格 41.7 は、S1 にとっては安すぎて余剰を取りこぼし、S2 にとってはやや高い。セグメントを分けると、各市場で 03-02 のラーナー最適をそれぞれ達成できるので、取りこぼしが減ります。弾力性の違い(S1 は鈍く、S2 は敏感)が大きいほど、価格差別の取り分は大きくなります。これは 03-02 の単一最適価格を、市場を分割して各部分に適用し直したものに他なりません。
利益の差を図で確かめます。左に2セグメントの需要曲線と各最適価格、右に「単一価格の利益曲線」と「価格差別の合計利益(水平線)」を重ねます。
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
c = 10.0
# セグメント別最適(線形需要の閉形式 P*=(a+bc)/(2b))
P1s = (100 + 1 * c) / (2 * 1) # = 55
P2s = (120 + 2 * c) / (2 * 2) # = 35
pi_discrim = (P1s - c) * (100 - P1s) + (P2s - c) * (120 - 2 * P2s) # = 3275
P_single = 250 / 6 # 単一価格の最適(約41.67)
fig, ax = plt.subplots(1, 2, figsize=(11, 4.2))
# 左:2セグメントの需要曲線(縦軸=価格)と各最適価格
Pq = np.linspace(10, 100, 400)
ax[0].plot(np.maximum(100 - Pq, 0), Pq, color="C0", lw=2, label="S1: Q=100-P(非弾力的)")
ax[0].plot(np.maximum(120 - 2 * Pq, 0), Pq, color="C1", lw=2, label="S2: Q=120-2P(弾力的)")
ax[0].axhline(P1s, color="C0", ls=":", lw=1.2)
ax[0].axhline(P2s, color="C1", ls=":", lw=1.2)
ax[0].set_title("セグメント別の需要と最適価格(P1*=55, P2*=35)")
ax[0].set_xlabel("需要量 Q")
ax[0].set_ylabel("価格 P")
ax[0].legend(loc="upper right", fontsize=9)
# 右:単一価格の利益曲線 vs 価格差別ベンチマーク(水平線)
P = np.linspace(10, 70, 400)
def Q_total(P): return np.maximum(100 - P, 0) + np.maximum(120 - 2 * P, 0)
profit_single = (P - c) * Q_total(P)
ax[1].plot(P, profit_single, color="C3", lw=2, label="単一価格の利益")
ax[1].axhline(pi_discrim, color="C2", ls="--", lw=1.5, label=f"価格差別の合計 {pi_discrim:.0f}")
ax[1].axvline(P_single, color="C3", ls=":", lw=1.2)
ax[1].set_ylim(0, 3600)
ax[1].set_title("単一価格の利益 < 価格差別")
ax[1].set_xlabel("単一価格 P")
ax[1].set_ylabel("利益")
ax[1].legend(loc="lower center", fontsize=9)
fig.tight_layout()
plt.show()
右パネルで、単一価格の利益カーブは で頂点(3,008)に達しますが、それでも価格差別の合計(3,275、緑の破線)には届きません。この上下の隙間が、単一価格が捨てている取りこぼしです。
2. バンドル:WTPの異質性をならす
バンドル(bundling)は複数の財をまとめて売る戦略です。なぜ効くのか——鍵は支払意思額(WTP)のばらつきを平均してならすことにあります。Adams–Yellen(1976)の古典的な結果は、消費者間で2財の WTP が負相関のとき、バンドルは個別販売より利益が増えるというものです。バンドル WTP は2財の WTP の和なので、その分散は
共分散 が負なら、和の分散は縮みます。WTP がそろう(ばらつきが小さい)ほど、ひとつのバンドル価格を多くの顧客が受け入れるので、取りこぼしが減るわけです。
数値例。限界費用0、2消費者×2財(A, B)。WTP を表で与えます。
| 財A | 財B | |
|---|---|---|
| 消費者1 | 8 | 2 |
| 消費者2 | 2 | 8 |
消費者1は A を高く・B を低く、消費者2はその逆——WTP が完全な負相関です。個別販売だと、財Aは「価格8で1人(売上8)」か「価格2で2人(売上4)」の二択で、最適は 8。財Bも同様に 8。個別合計=16。いっぽう純バンドルでは、各消費者のバンドル WTP は 、 とそろうので、価格10で2人とも購入=売上20。バンドルが個別を上回ります。
import numpy as np
# 2消費者 × 2財 の支払意思額(WTP)行列。限界費用は 0。
# 行=消費者, 列=財(A,B)
WTP_neg = np.array([[8.0, 2.0], # 消費者1:A を高く、B を低く評価
[2.0, 8.0]]) # 消費者2:その逆(WTP が負相関)
def best_individual(WTP):
"""財ごとに、各消費者のWTPを候補価格として総当たりし、売上を最大化"""
total, detail = 0.0, []
for j in range(WTP.shape[1]):
col = WTP[:, j]
best_p, best_rev = 0.0, 0.0
for p in np.unique(col): # 候補価格は各消費者のWTP
rev = p * np.sum(col >= p) # その価格で買う人数 × 価格
if rev > best_rev:
best_p, best_rev = p, rev
detail.append((best_p, best_rev))
total += best_rev
return total, detail
def best_bundle(WTP):
"""バンドルWTP=財WTPの和。バンドル価格を総当たりして売上最大化"""
bundle = WTP.sum(axis=1)
best_p, best_rev = 0.0, 0.0
for p in np.unique(bundle):
rev = p * np.sum(bundle >= p)
if rev > best_rev:
best_p, best_rev = p, rev
return best_p, best_rev, bundle
ind_total, ind_detail = best_individual(WTP_neg)
bp, brev, bundle = best_bundle(WTP_neg)
corr = np.corrcoef(WTP_neg[:, 0], WTP_neg[:, 1])[0, 1]
print("=== バンドル vs 個別販売(限界費用0, WTPが負相関)===")
print(f"財AとBのWTPの相関 = {corr:+.1f}(負相関)")
print("個別販売:")
print(f" 財A:最適価格 {ind_detail[0][0]:.0f} → 売上 {ind_detail[0][1]:.0f}")
print(f" 財B:最適価格 {ind_detail[1][0]:.0f} → 売上 {ind_detail[1][1]:.0f}")
print(f" 個別販売の合計売上 = {ind_total:.0f}")
print("純バンドル:")
print(f" バンドルWTP = {bundle}(各消費者 8+2, 2+8)")
print(f" 最適バンドル価格 {bp:.0f} → 売上 {brev:.0f}")
print(f"バンドルの利得 = {brev - ind_total:+.0f}")
# 対照:WTPが正相関なら、バンドルの優位は消える
WTP_pos = np.array([[8.0, 8.0],
[2.0, 2.0]])
ind_total_p, _ = best_individual(WTP_pos)
bp_p, brev_p, bundle_p = best_bundle(WTP_pos)
corr_p = np.corrcoef(WTP_pos[:, 0], WTP_pos[:, 1])[0, 1]
print("--- 対照:WTPが正相関なら ---")
print(f"相関 = {corr_p:+.1f}(正相関), 個別合計売上 = {ind_total_p:.0f}, "
f"バンドル売上 = {brev_p:.0f}(バンドルWTP={bundle_p})")
print(f"バンドルの利得 = {brev_p - ind_total_p:+.0f} → 正相関ではバンドルの優位が消える")
出力:
=== バンドル vs 個別販売(限界費用0, WTPが負相関)===
財AとBのWTPの相関 = -1.0(負相関)
個別販売:
財A:最適価格 8 → 売上 8
財B:最適価格 8 → 売上 8
個別販売の合計売上 = 16
純バンドル:
バンドルWTP = [10. 10.](各消費者 8+2, 2+8)
最適バンドル価格 10 → 売上 20
バンドルの利得 = +4
--- 対照:WTPが正相関なら ---
相関 = +1.0(正相関), 個別合計売上 = 16, バンドル売上 = 16(バンドルWTP=[16. 4.])
バンドルの利得 = +0 → 正相関ではバンドルの優位が消える
出力の意味:負相関のケースでは、バンドル売上 20 が個別合計 16 を +4 上回りました。理由は WTP のならし——個別だと財Aの WTP は {8, 2} とばらつき、価格を8にすれば1人しか買わず、2にすれば余剰を取りこぼします。バンドルにすると WTP は {10, 10} にそろい、価格10で全員から余剰をぴったり回収できます。対照の正相関のケース(消費者1が両財とも高評価、消費者2が両方とも低評価)では、バンドル WTP が {16, 4} とかえって広がり、バンドル売上は16で個別と同じ(利得 +0)。バンドルが効くのは WTP が負相関のときで、いつでも得とは限らないことが数字で確認できます。なお実務では純バンドルと単品の両方を併売する**混合バンドル(mixed bundling)**が使われ、高評価の単品客も取りこぼさないようにします。
3. 心理価格:数理は弱く、実験で測る
3つ目は心理価格(psychological pricing)——行動経済学的な値付けです。代表例が端数価格:¥2,000 を ¥1,980 にすると、20円の値引き以上に売れることがあります。先頭の桁が「2」から「1」に変わると安く感じるleft-digit 効果です。ほかにも、最初に見せた高い価格が基準になるアンカリング、比較対象を置くと選ばれやすくなるおとり効果、同じ価格でも文脈で評価が変わる文脈依存など。
ここで率直に言うべきは、これらの数理モデルは §1・§2 ほど強くないということです。効果の大きさは商品・客層・提示文脈に強く依存し、理論からは決まりません。だから心理価格は実験(A/Bテスト)で測るのが基本になります(→ 第7章)。下のデモは、left-digit 効果を「しきい値で需要が不連続にジャンプする」ものとして単純化し、ジャンプ幅が分かって初めて値付けの良し悪しが言えることを示します。
import numpy as np
# なめらかな(合理的)需要 base(P)=a-bP。限界費用0。
a, b = 1000.0, 0.3
def base(P): return a - b * P
# left-digit 効果:千の位が下がる(P<2000)と知覚価格が大きく下がり需要が跳ねる
JUMP = 60.0
def demand_psych(P):
return base(P) + (JUMP if P < 2000 else 0.0)
for P in (1980.0, 2000.0):
qs, qp = base(P), demand_psych(P)
print(f"P={P:.0f}: なめらか需要 Q={qs:.0f}(売上{P*qs:,.0f}) / "
f"心理込み Q={qp:.0f}(売上{P*qp:,.0f})")
ds = 1980 * base(1980) - 2000 * base(2000) # なめらかモデルでの売上差
dp = 1980 * demand_psych(1980) - 2000 * demand_psych(2000) # left-digit モデルでの売上差
print("1980 が 2000 に勝つ売上差:")
print(f" なめらかモデル = {ds:+,.0f}(ごくわずか)")
print(f" left-digit モデル = {dp:+,.0f}(ジャンプで大きく逆転)")
print("→ ジャンプ幅は理論では決まらない。A/Bテストで測るしかない(第7章)。")
出力:
P=1980: なめらか需要 Q=406(売上803,880) / 心理込み Q=466(売上922,680)
P=2000: なめらか需要 Q=400(売上800,000) / 心理込み Q=400(売上800,000)
1980 が 2000 に勝つ売上差:
なめらかモデル = +3,880(ごくわずか)
left-digit モデル = +122,680(ジャンプで大きく逆転)
→ ジャンプ幅は理論では決まらない。A/Bテストで測るしかない(第7章)。
出力の意味:なめらかな需要曲線だけで考えると、¥1,980 は ¥2,000 を売上で +3,880 しか上回らない(20円値引きの効果はわずか)。しかし left-digit のジャンプ(ここでは需要 +60)が本当に存在すれば、¥1,980 は +122,680 で圧勝します。問題は、この +60 というジャンプ幅は理論からは出てこないこと。実際にあるのか、どれだけ大きいのかは、価格を振った A/Bテストでしか確かめられません。心理価格は「効くはず」という思い込みでなく、実測して初めて使える——次の図でその不連続を見ます。
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
a, b, JUMP = 1000.0, 0.3, 60.0
P = np.linspace(1900, 2100, 401)
base = a - b * P
psych = base + np.where(P < 2000, JUMP, 0.0)
fig, ax = plt.subplots(figsize=(7.5, 4.4))
ax.plot(P, base, color="C0", lw=1.8, ls="--", label="なめらかな需要 a-bP")
left = P < 2000
ax.plot(P[left], psych[left], color="C3", lw=2.4, label="left-digit 込みの需要")
ax.plot(P[~left], psych[~left], color="C3", lw=2.4)
ax.axvline(2000, color="gray", ls=":", lw=1.2)
ax.annotate("2000円のしきい値で\n需要がジャンプ",
xy=(1999, base[np.argmin(np.abs(P - 1999))] + JUMP),
xytext=(1930, 470), arrowprops=dict(arrowstyle="->", color="C3"))
ax.set_title("left-digit 効果:しきい値で需要が不連続にジャンプ")
ax.set_xlabel("価格 P(円)")
ax.set_ylabel("需要量 Q")
ax.legend(loc="upper right")
fig.tight_layout()
plt.show()
赤い需要曲線は ¥2,000 の手前で上にジャンプします。この不連続こそ心理価格の正体で、なめらかな需要曲線(青破線)の延長では捉えられません。ジャンプの有無と大きさを決めるのは数式でなくデータ——だから第7章の実験につながります。
まとめ:価格差別・バンドル・心理価格はいずれも、03-02 の「静的な単一最適価格」の拡張・補完です。価格差別とバンドルは需要の数理から利得が導けますが、その前提(弾力性・WTP 分布・負相関)が正しいかは推定に依存します。心理価格にいたっては理論が弱く、効果は実験頼みです。したがってどの戦略も、最終的には価格テスト=A/Bテスト(第7章)で検証するのが筋になります。さらに、需要が分からないまま価格を動かしながら学習・最適化する問題は、多腕バンディット(第8章/機械学習テキスト)の出番です。
⚠️ よくある誤解
- 価格差別には「裁定(転売)防止」と「セグメント識別」が要る:安いセグメントが買って高いセグメントに転売できると(裁定)、価格差別は崩れ、単一価格に逆戻りします。また、誰がどのセグメントかを識別できなければ別価格をつけられません。第3級では会員区分・時間・地域など識別可能な軸が、第2級では顧客に自己選択させる仕組み(バージョン・数量)が前提です。
- バンドルは常に得ではない:効くのは WTP が負相関のとき。本文の対照例のとおり、正相関だとバンドル WTP がかえって広がり、優位は消えます(16=16)。「とりあえずまとめれば儲かる」は誤り。WTP の相関構造を見てから判断します。
- 心理価格の効果は文脈依存——思い込みで使わない:¥1,980 が常に効くとは限りません。商品・客層・提示の仕方で効果は変わり、理論からは大きさが出ません。「効くはず」で決め打ちせず、A/Bテストで実測してから採用するのが基本です(→ 第7章)。
- 動的価格には公平性・法令・ブランド毀損のリスクがある(要最新確認):時間別・需給別の動的価格や、個人データに基づく個別価格(いわゆる surveillance pricing)は、消費者の不公平感やブランド毀損を招きやすく、規制の動きも活発です(2025〜2026年にかけて米FTCの調査や州レベルの規制——個人データに基づく値上げを禁じる州法の成立など——が進行中。最新の規制状況は要確認)。数理上の最適と、実装してよいかは別問題です。
関連ノート
- 価格最適化(利益最大化)(前提・本ノートは単一の静的最適価格を戦略的に拡張する)
- 需要曲線と価格弾力性(弾力性の違いが価格差別の利得を生む)
- 第3章 需要と価格 目次
- 価格テスト=A/B による効果検証は第7章(実験と因果推論)、需要が未知のまま価格を動かして学習する動的最適化は第8章の多腕バンディット/機械学習テキストへ
- 第2級価格差別の自己選択(バージョン・メニュー)は第4章の選択モデルとつながる
- マーケティング・サイエンス 全体目次