← 返回笔记
随机规划 2026年8月17日 约 55 分钟读完

随机规划第二节:CVaR、SAA、Multistage 与 Backward Recursion

从风险厌恶与样本平均近似,推进到样本外验证、多阶段 Policy、State、Value Function 与 Backward Recursion。

CVaRSAAValidationMultistageBackward Recursion

本节位置:承接第一份笔记中的 Two-Stage、Scenario Tree、Non-anticipativity、EVPI、VSS;本节继续学习“如何把随机规划做得更接近真实交易问题”,重点包括风险厌恶、SAA、样本外验证、多阶段策略、状态与价值函数、Backward Recursion。

当前掌握状态:SAA 主干已理解;SAA 统计下界/置信区间细节需要后续复习;Multistage / Policy / State / Backward Recursion 主干已理解;凸性与最优性证明的数学细节尚未闭环。


1. 从风险中性到风险厌恶

第一份笔记里的标准随机规划目标是:

minxE[G(x,ξ)] \boxed{ \min_x E[G(x,\xi)] }

其中:

  • xx:策略或决策;
  • ξ\xi:未来随机信息;
  • G(x,ξ)G(x,\xi):策略 xx 在场景 ξ\xi 下产生的总成本或损失。

风险中性目标只关心:

平均成本最小 \boxed{\text{平均成本最小}}

但两个策略可能有相同的平均成本,却有完全不同的尾部风险。

例如:

策略 期望成本 极端场景成本
A 40000 100000
B 45000 60000

如果只看期望,A 更好;如果特别害怕极端亏损,B 可能更符合实际风险偏好。

因此需要把风险度量直接嵌入 stochastic programming。


2. CVaR 在随机规划里怎么用

本节不重新推导 CVaR 本体,只复习它如何进入随机规划。CVaR 的详细推导已在单独的 CVaR 学习笔记中完成。

对随机损失 ZZ,尾部概率为 α\alpha 时:

CVaR1α(Z)=inft[t+1αE[(Zt)+]] \boxed{ CVaR_{1-\alpha}(Z) = \inf_t \left[ t+\frac{1}{\alpha}E[(Z-t)^+] \right] }

其中:

  • tt:辅助阈值,最优时落在对应 VaR 分位附近;
  • (Zt)+=max(Zt,0)(Z-t)^+=\max(Z-t,0):超过阈值的尾部损失;
  • α\alpha:尾部概率,例如 α=0.05\alpha=0.05 对应 95% CVaR。

在电力交易里,可以令:

Z=G(x,ξ) Z=G(x,\xi)

即某个购电策略在电价、负荷、偏差等随机场景下产生的总成本或损失。


3. 两种常见的 Risk-Averse Stochastic Programming 写法

3.1 硬风险预算

目标仍然最小化期望成本:

minxE[G(x,ξ)] \boxed{ \min_x E[G(x,\xi)] }

但是要求:

CVaR95%(G(x,ξ))τ \boxed{ CVaR_{95\%}(G(x,\xi))\le \tau }

含义:

在控制平均成本的同时,不允许尾部成本超过某个风险预算。


3.2 Mean-CVaR 加权目标

另一种写法:

minxE[G(x,ξ)]+λCVaR95%(G(x,ξ)) \boxed{ \min_x E[G(x,\xi)] + \lambda CVaR_{95\%}(G(x,\xi)) }

其中:

λ0 \lambda\ge0

表示对尾部风险的厌恶程度。

  • λ=0\lambda=0:完全风险中性;
  • λ\lambda 越大:越愿意牺牲平均收益换取尾部安全。

一个我们做过的例子

策略 A:

E[GA]=40000,CVaRA=100000 E[G_A]=40000,\qquad CVaR_A=100000

策略 B:

E[GB]=45000,CVaRB=60000 E[G_B]=45000,\qquad CVaR_B=60000

加权目标:

JA=40000+100000λ J_A=40000+100000\lambda
JB=45000+60000λ J_B=45000+60000\lambda

令两者相等:

40000+100000λ=45000+60000λ 40000+100000\lambda = 45000+60000\lambda

得到:

λ=0.125 \boxed{\lambda=0.125}

含义:

当风险惩罚权重超过 0.125,B 的低尾部风险开始抵消它在平均成本上的劣势。


4. 有限 Scenario 下的 CVaR 线性化

假设场景为:

s=1,,S s=1,\dots,S

场景概率:

ps p_s

策略 xx 在场景 ss 下的成本:

Gs(x) G_s(x)

引入辅助变量:

us0 u_s\ge0

并约束:

usGs(x)t \boxed{ u_s\ge G_s(x)-t}

于是:

CVaR1α=t+1αspsus \boxed{ CVaR_{1-\alpha} = t+\frac{1}{\alpha}\sum_s p_su_s }

这意味着,如果 Gs(x)G_s(x) 本身是线性的,那么 CVaR 也能被放进一个线性规划框架。

电力采购场景下,一个简单的损失函数可以写成:

Gs(x)=400x+700ysbuy200yssell G_s(x) = 400x + 700y_s^{buy} - 200y_s^{sell}

再把 CVaR 辅助变量和电量平衡约束一起加入模型。


5. Efficient Frontier 与 Dominance

Mean-CVaR 模型本质上是在两个维度之间做权衡:

E[G]CVaR(G) \boxed{ E[G] \quad\leftrightarrow\quad CVaR(G) }

如果一个策略在两个维度上都比另一个策略差,那么它被支配。

例如:

策略 C:

E[GC]=50000,CVaRC=50000 E[G_C]=50000,\qquad CVaR_C=50000

策略 D:

E[GD]=55000,CVaRD=80000 E[G_D]=55000,\qquad CVaR_D=80000

则:

C 同时拥有更低期望成本和更低 CVaR \boxed{C\text{ 同时拥有更低期望成本和更低 CVaR}}

所以 D 被 C 支配,无论 λ\lambda 怎么选,D 都不会成为最优策略。


6. Scenario Generation 和 SAA 不是一回事

这是后面非常重要的区分。

Scenario Generation

回答:

场景从哪里来? \boxed{\text{场景从哪里来?}}

可以来自:

  • 历史数据;
  • Monte Carlo;
  • 专家构造;
  • 条件采样;
  • 聚类 / 场景压缩。

SAA

回答:

拿到有限样本以后,如何用它近似真实期望并做优化? \boxed{\text{拿到有限样本以后,如何用它近似真实期望并做优化?}}

所以:

Scenario GenerationSAA \boxed{ Scenario\ Generation \neq SAA }

前者负责“造场景”,后者负责“把场景变成优化问题”。


7. SAA:Sample Average Approximation

真实问题:

minxXg(x) \boxed{ \min_{x\in X}g(x) }

其中:

g(x)=E[F(x,ξ)] \boxed{ g(x)=E[F(x,\xi)] }

真实分布可能非常复杂,甚至无法直接计算期望。

我们得到 NN 个样本:

ξ1,ξ2,,ξN \xi^1,\xi^2,\dots,\xi^N

构造经验平均:

g^N(x)=1Ns=1NF(x,ξs) \boxed{ \hat g_N(x) = \frac1N\sum_{s=1}^N F(x,\xi^s) }

然后求:

x^N=argminxXg^N(x) \boxed{ \hat x_N = \arg\min_{x\in X}\hat g_N(x) }

这就是 SAA。


8. SAA 最核心的直觉

在 iid SAA 中,每个样本场景被赋予经验概率:

ps=1N \boxed{p_s=\frac1N}

因此可以理解为:

当真实概率分布难以直接使用时,先用有限样本构造一个“经验分布”,再在这个经验世界里优化。

但要注意:

我们是在近似真实分布,不是在宣称真实世界就是这 N 个样本。 \boxed{ \text{我们是在近似真实分布,不是在宣称真实世界就是这 }N\text{ 个样本。} }

9. 固定 xx 求平均,不等于 SAA 优化

这是学习过程中一个重要分界。

如果固定:

x=100 x=100

然后计算:

1NsF(100,ξs) \frac1N\sum_sF(100,\xi^s)

这只是:

评价这个固定策略 \boxed{\text{评价这个固定策略}}

而不是 SAA optimization。

真正的 SAA 要让:

x x

可以变化,并求:

x^N=argminx1NsF(x,ξs) \boxed{ \hat x_N= \arg\min_x \frac1N\sum_sF(x,\xi^s) }

所以:

Sample Average + fixed x=Evaluation \boxed{ \text{Sample Average + fixed }x =\text{Evaluation} }
Sample Average + optimize over x=SAA \boxed{ \text{Sample Average + optimize over }x =\text{SAA} }

10. SAA 不是一个求解算法

SAA 做的是:

E[F(x,ξ)]1NsF(x,ξs) \boxed{ E[F(x,\xi)] \rightarrow \frac1N\sum_sF(x,\xi^s) }

也就是把随机期望问题变成有限场景优化问题。

但是得到 SAA 问题以后,仍然需要一个 optimization algorithm 去求它。

例如:

  • LP Solver;
  • MILP Solver;
  • L-shaped / Benders;
  • 其他分解算法。

因此:

SAA=近似方法,不是optimizer本身 \boxed{ SAA=近似方法,不是 optimizer 本身 }

11. SAA 的样本量和稳定性

对固定 xx

q^N(x)=1Ns=1NQ(x,ξs) \hat q_N(x) = \frac1N\sum_{s=1}^NQ(x,\xi^s)

其方差:

Var[q^N(x)]=Var[Q(x,ξ)]N \boxed{ Var[\hat q_N(x)] = \frac{Var[Q(x,\xi)]}{N} }

所以标准误差大致按:

O(N1/2) \boxed{O(N^{-1/2})}

下降。

含义:

Scenario 数量增多,样本平均通常会更稳定,但 Monte Carlo 的收敛并不快。

一个重要提醒:

稳定正确 \boxed{ \text{稳定} \neq \text{正确} }

如果样本本身存在系统性偏差,那么 NN 很大,也只是稳定地逼近一个错误分布。


12. 电力价格 Scenario 应该怎么构造

我们讨论江苏数据时,形成了三层复杂度。

Level 1:单时点 / 单时段

例如只研究每天 18:00 的价格:

ξs=P18:00(s) \xi^s=P_{18:00}^{(s)}

适合:

  • 单时点决策;
  • 没有跨时段耦合约束;
  • 先验证最基础模型。

注意:不能把所有天的 96 点无脑打平,因为这样会破坏“同一时段”的业务含义。


Level 2:分时块 Scenario

例如把一天拆为:

谷段 / 平段 / 峰段 / 晚峰 \text{谷段 / 平段 / 峰段 / 晚峰}

每个 scenario 是一个低维向量。

这是单点和完整日路径之间的折中。


Level 3:完整 96 点路径

每一天作为一个 scenario:

ξs=(P1(s),P2(s),,P96(s)) \xi^s= (P_1^{(s)},P_2^{(s)},\dots,P_{96}^{(s)})

适用于:

  • 96 点之间有耦合;
  • 储能;
  • 曲线约束;
  • 连续持仓调整;
  • 跨时段风险。

核心判断:

决策之间如果有路径依赖,就不能把每个点独立抽样。 \boxed{ \text{决策之间如果有路径依赖,就不能把每个点独立抽样。} }

13. 日前和实时必须保持联合关系

如果一个策略的成本同时取决于:

PDA P^{DA}

和:

PRT P^{RT}

那么 scenario 应尽量保存:

(PDA,PRT) \boxed{ (P^{DA},P^{RT}) }

或者直接保存价差:

ΔP=PRTPDA \boxed{ \Delta P=P^{RT}-P^{DA} }

不要独立地从两个边际分布分别抽样:

PDAFDA P^{DA}\sim F_{DA}
PRTFRT P^{RT}\sim F_{RT}

然后随机拼接。

原因:

日前和实时之间的相关结构本身就是交易风险的一部分。 \boxed{ \text{日前和实时之间的相关结构本身就是交易风险的一部分。} }

14. 为什么不能在同一批数据上既找最优又证明最优

假设有 200 天数据。

如果我们用全部 200 天求:

x^ \hat x

然后仍然在这 200 天上评价:

g^200(x^) \hat g_{200}(\hat x)

那么评价会偏乐观。

因为:

x^\hat x 本身就是专门针对这 200 天优化出来的。

所以要区分:

Optimization Sample \boxed{\text{Optimization Sample}}

和:

Out-of-Sample Evaluation \boxed{\text{Out-of-Sample Evaluation}}

15. 对时间序列,更适合 Walk-Forward

随机打乱训练/测试在 iid 问题里可以使用,但电力市场具有明显时间顺序。

因此更符合真实交易逻辑的是:

过去数据训练/构造 scenario/求解未来数据验证 \boxed{ \text{过去数据} \rightarrow \text{训练/构造 scenario/求解} \rightarrow \text{未来数据验证} }

例如:

  • 前 150 天建模;
  • 后 50 天样本外测试。

进一步可以滚动:

[1,150]151 [1,150]\rightarrow151
[2,151]152 [2,151]\rightarrow152
[3,152]153 [3,152]\rightarrow153

这就是 walk-forward。

它和 Non-anticipativity 的精神完全一致:

做历史时点的决策时,不能使用该时点之后的数据。 \boxed{ \text{做历史时点的决策时,不能使用该时点之后的数据。} }

16. Candidate Solution 的 Optimality Gap

真实目标:

g(x)=cTx+E[Q(x,ξ)] \boxed{ g(x)=c^Tx+E[Q(x,\xi)]}

真实最优值:

v=minxg(x) \boxed{ v^*=\min_xg(x)}

SAA 求出候选:

x^ \hat x

它的真实 optimality gap:

Gap(x^)=g(x^)v0 \boxed{ Gap(\hat x)=g(\hat x)-v^*\ge0 }

问题在于:

g(x^) g(\hat x)

和:

v v^*

通常都不知道。


17. 为什么候选策略比较容易评价

一旦:

x^ \hat x

固定下来,问题就从“优化”变成了“评价”。

可以用一批大的独立 OOS 样本:

ξ1,,ξN \xi^1,\dots,\xi^{N'}

计算:

g^N(x^) \hat g_{N'}(\hat x)

于是能够对:

g(x^) g(\hat x)

构造一个统计意义上的 upper bound:

U \boxed{U}

直觉:

固定一个策略以后,我们只需要反复模拟它在不同未来下的表现,不再需要搜索最优决策。


18. 为什么真实最优值 vv^* 更难估

SAA 的最优值:

v^N=minxg^N(x) \boxed{ \hat v_N=\min_x\hat g_N(x) }

需要特别注意:

v^Nv并不是每个样本都成立 \boxed{ \hat v_N\le v^* \quad\text{并不是每个样本都成立} }

某一次样本可能:

v^N>v \hat v_N>v^*

真正有保证的是:

E[v^N]v \boxed{ E[\hat v_N]\le v^* }

原因可以从:

v^N=minxg^N(x)g^N(x) \hat v_N = \min_x\hat g_N(x) \le \hat g_N(x)

开始。

对任意固定 xx 取期望:

E[v^N]E[g^N(x)]=g(x) E[\hat v_N] \le E[\hat g_N(x)] = g(x)

再对右侧取最小:

E[v^N]v \boxed{ E[\hat v_N]\le v^* }

这是我们当时重点纠正过的一点。


19. 用多次 SAA 构造 Lower Bound

独立求解 MM 次 SAA:

v^N(1),v^N(2),,v^N(M) \hat v_N^{(1)}, \hat v_N^{(2)}, \dots, \hat v_N^{(M)}

求平均:

vˉN,M=1Mm=1Mv^N(m) \boxed{ \bar v_{N,M} = \frac1M\sum_{m=1}^M\hat v_N^{(m)} }

由于:

E[v^N]v E[\hat v_N]\le v^*

所以可以进一步结合样本方差和 tt 分布,构造统计意义上的 lower bound:

L \boxed{L}

而候选策略 OOS 评价给出:

U \boxed{U}

于是:

Gap(x^)UL \boxed{ Gap(\hat x)\lesssim U-L }

这里的统计置信区间公式细节目前标记为:

主干已懂,统计推导待复习 \boxed{\text{主干已懂,统计推导待复习}}

20. SAA 的完整工作流

到这里,SAA 主线可以压缩成:

Scenario GenerationSAAx^OOS ValidationStability/Gap Check \boxed{ Scenario\ Generation \rightarrow SAA \rightarrow \hat x \rightarrow OOS\ Validation \rightarrow Stability/Gap\ Check }

对应业务语言:

先用数据构造未来 → 在样本世界里求策略 → 拿未来未见数据检验 → 检查策略是否稳定、是否接近真实最优。


21. 从 Two-Stage 进入 Multistage

Two-stage:

x1ξ2x2 \boxed{ x_1\rightarrow\xi_2\rightarrow x_2}

Multistage:

x1ξ2x2ξ3x3 \boxed{ x_1\rightarrow\xi_2\rightarrow x_2\rightarrow\xi_3\rightarrow x_3\rightarrow\cdots}

例如电力交易可以抽象成:

年度月度日前实时 \text{年度} \rightarrow \text{月度} \rightarrow \text{日前} \rightarrow \text{实时}

每一次新的信息揭晓后,都可能再次调整决策。


22. Multistage 最大的升级:Decision 变成 Policy

如果今天直接写:

(x1,x2,x3) (x_1,x_2,x_3)

很容易误解为:

今天把所有未来动作一次性写死。

但真正的多阶段决策应该是:

π={x1,x2(ξ2),x3(ξ2,ξ3),} \boxed{ \pi = \{x_1,x_2(\xi_2),x_3(\xi_2,\xi_3),\dots\} }

也就是说:

Solution = Policy \boxed{\text{Solution = Policy}}

Policy 是:

未来看到什么信息,就采取什么动作。

例如:

x2(系统偏紧)=+20 x_2(\text{系统偏紧})=+20
x2(系统宽松)=0 x_2(\text{系统宽松})=0

真正求的是这整套规则,而不是单独一个未来数字。


23. Policy 和 Non-anticipativity 是同一件事的两个方向

Policy 说:

决策可以依赖已经看到的信息 \boxed{\text{决策可以依赖已经看到的信息}}

Non-anticipativity 说:

决策不能依赖还没有看到的信息 \boxed{\text{决策不能依赖还没有看到的信息}}

所以:

相同信息历史相同当前决策 \boxed{ \text{相同信息历史} \Rightarrow \text{相同当前决策} }

这正是 Scenario Tree 中共享节点的含义。


24. Reality Forward,Optimization Backward

这是我们学习 Backward Recursion 时最重要的认知修正。

现实世界的执行方向永远是:

S0a1ξ2S1a2ξ3 \boxed{ S_0 \rightarrow a_1 \rightarrow \xi_2 \rightarrow S_1 \rightarrow a_2 \rightarrow \xi_3 \rightarrow\cdots }

也就是说:

Reality runs forward \boxed{\text{Reality runs forward}}

随着信息逐步揭晓,Scenario Tree 会从大量可能路径逐渐收缩到真正发生的一条路径。

但今天为了决定 a1a_1,必须提前知道:

不同动作会给未来留下什么状态,而这些状态未来值多少钱?

于是 optimizer 内部要:

从未来往现在计算价值 \boxed{\text{从未来往现在计算价值}}

即:

Optimization runs backward \boxed{\text{Optimization runs backward}}

25. Scenario 收缩、Backward Recursion、Scenario Reduction 不要混淆

Scenario Tree Execution

现实中随着信息揭晓:

{A,B,C,D}{A,B}{A} \{A,B,C,D\} \rightarrow \{A,B\} \rightarrow \{A\}

这是:

现实路径逐步确定 \boxed{\text{现实路径逐步确定}}

Backward Recursion

事前计算:

未来状态值多少钱今天怎么做 \boxed{\text{未来状态值多少钱} \rightarrow \text{今天怎么做}}

Scenario Reduction

为了省算力,在求解前主动:

10000 scenarios100 representative scenarios 10000\text{ scenarios} \rightarrow 100\text{ representative scenarios}

这是:

模型近似 / 计算降维 \boxed{\text{模型近似 / 计算降维}}

三者不是同一件事。


26. 为什么算叶子时不需要知道上面最终做了什么

这是 Backward Recursion 真正被理解的关键。

最开始的疑问是:

算最后一个叶子时,我还不知道前面的节点到底做了什么,怎么能算最后阶段成本?

答案:

最后阶段先算的是一个函数,不是一个固定数字 \boxed{\text{最后阶段先算的是一个函数,不是一个固定数字}}

例如:

Q3(q,P)=(100q)P Q_3(q,P) = (100-q)P

其中:

q q

是进入最后阶段时已经持有的电量。

我们暂时不知道最终会是:

q=50,80,100 q=50,80,100

中的哪一个。

没关系,先得到整个函数:

qQ3(q,P) \boxed{ q\mapsto Q_3(q,P) }

上一阶段的动作再决定最终把哪个 qq 代入这个函数。


27. Value Function / Cost-to-go

最重要的记忆句:

State从这个状态往后能够达到的最小成本 \boxed{ \text{State} \rightarrow \text{从这个状态往后能够达到的最小成本} }

这就是 Value Function。

例如:

Vt(st) V_t(s_t)

表示:

当前处于状态 sts_t 时,从现在一直到结束,在以后都采取最优动作的前提下,能够达到的最小期望总成本。

它不是:

  • 当前动作;
  • 当前成本;
  • 单独一个未来 Scenario 的成本。

它是:

从现在开始整段未来的最优价值 \boxed{\text{从现在开始整段未来的最优价值}}

28. State 到底是什么

我们后来把书里的 xtx^t 暂时换成更直观的:

st s_t

表示 state。

State 不是“所有历史数据”。

更好的定义:

st=截至现在,对未来决策仍然有用的信息的充分摘要 \boxed{ s_t = \text{截至现在,对未来决策仍然有用的信息的充分摘要} }

例如电力交易里,可以粗略写成:

st=(qt,L^t,供需状态,价格状态) s_t= ( q_t, \hat L_t, \text{供需状态}, \text{价格状态} )

其中:

  • qtq_t:当前持仓;
  • L^t\hat L_t:最新负荷预测;
  • 供需状态:偏紧 / 宽松;
  • 价格状态:影响未来价格分布的信息。

29. 为什么只知道“持仓=80”可能不够

两个状态都持仓:

q=80 q=80

但:

A:39℃、负荷继续上调、系统偏紧;

B:25℃、负荷继续下调、系统宽松。

则:

P(ξt+1IA)P(ξt+1IB) P(\xi_{t+1}\mid I_A) \neq P(\xi_{t+1}\mid I_B)

所以:

Vt(80IA)Vt(80IB) \boxed{ V_t(80\mid I_A) \neq V_t(80\mid I_B) }

因此:

相同持仓相同状态 \boxed{ \text{相同持仓}\neq\text{相同状态} }

只要信息会影响未来条件分布、约束或成本,它就应该被 state 保留。


30. State 要足够,但不要冗余

假设两条历史路径完全不同,但到了当前:

  • 持仓相同;
  • 当前约束相同;
  • 对未来所有随机变量的条件分布相同。

那么 optimizer 不需要再区分完整历史。

所以:

State 是对历史的压缩,不是历史本身。 \boxed{ \text{State 是对历史的压缩,不是历史本身。} }

判断标准:

在知道当前 state 后,额外知道过去,还会不会改变对未来的预测或可行动作?

如果不会,这部分历史可以丢掉。

这已经非常接近 Markov 思想:

P(未来st,完整过去)=P(未来st) \boxed{ P(\text{未来}\mid s_t,\text{完整过去}) = P(\text{未来}\mid s_t) }

目前只需要理解这个直觉,不需要继续展开 Markov 理论。


31. Action 和 State 不能混

定义:

at=当前阶段采取的动作 \boxed{a_t=\text{当前阶段采取的动作}}

例如:

at{不买,买20} a_t\in\{\text{不买},\text{买20}\}

而:

st+1=动作 + 新随机信息共同形成的下一状态 \boxed{s_{t+1}=\text{动作 + 新随机信息共同形成的下一状态}}

因此:

atst+1 \boxed{a_t\neq s_{t+1}}

更准确的关系是:

(st,at,ξt+1)st+1 \boxed{ (s_t,a_t,\xi_{t+1}) \rightarrow s_{t+1} }

例如:

当前持仓 80,选择买 20,再遇到实时价格 700:

(80,买20,700)(100,700) (80,\text{买20},700) \rightarrow (100,700)

32. QH(xH1,ξH)Q^H(x^{H-1},\xi^H) 的三个角色

Birge & Louveaux 在最后阶段写:

QH(xH1,ξH)=minxHcHxH \boxed{ Q^H(x^{H-1},\xi^H) = \min_{x^H} c^Hx^H }

subject to:

WHxH=hHTH1xH1 W^Hx^H = h^H-T^{H-1}x^{H-1}

这里:

xH1x^{H-1}

上一个阶段留下来的状态 / 输入 \boxed{\text{上一个阶段留下来的状态 / 输入}}

ξH\xi^H

进入最后阶段后已经揭晓的环境信息 \boxed{\text{进入最后阶段后已经揭晓的环境信息}}

xHx^H

最后阶段当前真正要优化的动作 \boxed{\text{最后阶段当前真正要优化的动作}}

所以:

QH Q^H

不是一个动作,而是这个最后阶段小优化问题的最优值函数。


33. 带随机状态的 QQ 和取完期望的 QQ

这是多阶段递归里另一个关键区别。

未来已经揭晓

Qt+1(xt,ξt+1) \boxed{ Q^{t+1}(x^t,\xi^{t+1}) }

含义:

给定当前留下的状态 xtx^t,并且下一阶段真实随机状态已经发生后,后面最优成本是多少?

未来还没揭晓

当前阶段真正需要的是:

Qt+1(xt)=E[Qt+1(xt,ξt+1)It] \boxed{ Q^{t+1}(x^t) = E\left[ Q^{t+1}(x^t,\xi^{t+1}) \mid I_t \right] }

含义:

当前还不知道下一阶段真实情况时,这个状态对应的未来最优期望成本。

所以月度阶段如果还不知道实时价格 PRTP^{RT},就不能偷看:

QRT(x,PRT) Q^{RT}(x,P^{RT})

而应该使用:

QRT(x) \boxed{Q^{RT}(x)}

34. 信息更新为什么会改变 Value Function

同样持仓:

x=80 x=80

但是当前信息不同:

IA=系统明显偏紧 I_A=\text{系统明显偏紧}
IB=系统明显宽松 I_B=\text{系统明显宽松}

则未来实时价格条件分布可能不同:

P(PRTIA)P(PRTIB) P(P^{RT}\mid I_A) \neq P(P^{RT}\mid I_B)

所以:

QRT(80IA)QRT(80IB) \boxed{ Q^{RT}(80\mid I_A) \neq Q^{RT}(80\mid I_B) }

完整链条:

信息更新条件分布更新Q/V 更新最优动作更新 \boxed{ \text{信息更新} \rightarrow \text{条件分布更新} \rightarrow Q/V\text{ 更新} \rightarrow \text{最优动作更新} }

这就是 Multistage 相比于简单 Two-Stage 真正多出来的动态性。


35. 当前动作的总价值:Jt(st,at)J_t(s_t,a_t)

为了避免把“动作”和“状态价值”混在一起,我们引入:

Jt(st,at)=Ct(st,at)+E[Vt+1(st+1)st,at] \boxed{ J_t(s_t,a_t) = C_t(s_t,a_t) + E[V_{t+1}(s_{t+1})\mid s_t,a_t] }

其中:

  • CtC_t:现在做这个动作的直接成本;
  • Vt+1V_{t+1}:动作和随机结果把系统送入下一状态后,从那里往后的最优未来成本。

所以:

Jt=选定某一个动作后的总期望成本 \boxed{ J_t=\text{选定某一个动作后的总期望成本} }

36. Value Function:Vt(st)V_t(s_t)

当前状态有多个可选动作:

a1,a2, a_1,a_2,\dots

每个动作有自己的:

Jt(st,ai) J_t(s_t,a_i)

真正的状态价值是:

Vt(st)=minatJt(st,at) \boxed{ V_t(s_t) = \min_{a_t}J_t(s_t,a_t) }

也就是:

Vt(st)=minat[Ct(st,at)+E[Vt+1(st+1)st,at]] \boxed{ V_t(s_t) = \min_{a_t} \left[ C_t(s_t,a_t) + E[V_{t+1}(s_{t+1})\mid s_t,a_t] \right] }

这就是我们目前对 Bellman / Backward Recursion 最直观的理解。


37. min\minargmin\arg\min 不要混

假设:

J(a1)=40 J(a_1)=40
J(a2)=32 J(a_2)=32
J(a3)=35 J(a_3)=35

那么:

Vt(st)=32 \boxed{V_t(s_t)=32}

因为:

min(40,32,35)=32 \min(40,32,35)=32

而最优动作:

at=a2 \boxed{a_t^*=a_2}

因为:

at=argminatJt(st,at) \boxed{ a_t^* = \arg\min_{a_t}J_t(s_t,a_t) }

所以:

min最优值是多少 \boxed{ \min\rightarrow\text{最优值是多少} }
argmin哪个动作取得最优值 \boxed{ \arg\min\rightarrow\text{哪个动作取得最优值} }

38. 我们亲手做过的一轮 Backward Recursion

当前状态:

st=(持仓80,系统偏紧) s_t=(\text{持仓80},\text{系统偏紧})

两个动作:

a1=不买 a_1=\text{不买}
a2=买20 a_2=\text{买20}

当前买入价:

350 元/MWh 350\text{ 元/MWh}

实时价格:

PRT={700,70%200,30% P^{RT}= \begin{cases} 700,&70\%\\ 200,&30\% \end{cases}

下一阶段 Value Function 已经提前算好:

Vt+1(80,700)=14000 V_{t+1}(80,700)=14000
Vt+1(80,200)=4000 V_{t+1}(80,200)=4000
Vt+1(100,700)=0 V_{t+1}(100,700)=0
Vt+1(100,200)=0 V_{t+1}(100,200)=0

38.1 动作 1:不买

当前成本:

0 0

未来期望成本:

0.7×14000+0.3×4000 0.7\times14000+0.3\times4000
=9800+1200 =9800+1200
=11000 =11000

所以:

Jt(st,不买)=11000 \boxed{ J_t(s_t,\text{不买})=11000 }

38.2 动作 2:买20

当前成本:

20×350=7000 20\times350=7000

买完持仓 100,未来补购成本:

0 0

所以:

Jt(st,买20)=7000 \boxed{ J_t(s_t,\text{买20})=7000 }

因此:

Vt(st)=min(11000,7000)=7000 \boxed{ V_t(s_t)=\min(11000,7000)=7000 }

最优动作:

at=买20 \boxed{ a_t^*=\text{买20} }

39. 再往前倒一层

回到:

st1=(持仓60,尚不知道系统松紧) s_{t-1}=(\text{持仓60,尚不知道系统松紧})

两个动作:

不买 \text{不买}
买20 \text{买20}

当前价格:

300 元/MWh 300\text{ 元/MWh}

下一阶段:

P(偏紧)=60% P(\text{偏紧})=60\%
P(宽松)=40% P(\text{宽松})=40\%

已知:

Vt(80,偏紧)=7000 V_t(80,\text{偏紧})=7000
Vt(80,宽松)=2000 V_t(80,\text{宽松})=2000

如果买 20:

Jt1(买20)=6000+0.6×7000+0.4×2000 J_{t-1}(\text{买20}) = 6000 +0.6\times7000 +0.4\times2000
=6000+4200+800 = 6000+4200+800
=11000 \boxed{=11000}

如果不买,假设:

Vt(60,偏紧)=16000 V_t(60,\text{偏紧})=16000
Vt(60,宽松)=6000 V_t(60,\text{宽松})=6000

则:

Jt1(不买)=0.6×16000+0.4×6000 J_{t-1}(\text{不买}) = 0.6\times16000 +0.4\times6000
=9600+2400 =9600+2400
=12000 \boxed{=12000}

于是:

Vt1(st1)=min(11000,12000)=11000 \boxed{ V_{t-1}(s_{t-1}) = \min(11000,12000) = 11000 }

最优动作:

at1=买20 \boxed{ a_{t-1}^*=\text{买20} }

40. 为什么这叫“递归”

上一轮我们求出来的:

Vt V_t

在更前一层已经不再是最终答案,而变成:

下一层可以直接调用的未来价目表 \boxed{\text{下一层可以直接调用的未来价目表}}

因此:

Vt+1VtVt1V0 \boxed{ V_{t+1} \rightarrow V_t \rightarrow V_{t-1} \rightarrow \cdots \rightarrow V_0 }

每往回一层都做同一件事:

比较当前动作当前成本+未来价值取最小生成新的 Value Function \boxed{ \text{比较当前动作} \rightarrow \text{当前成本+未来价值} \rightarrow \text{取最小} \rightarrow \text{生成新的 Value Function} }

41. Value Function 为什么能压缩整棵未来子树

假设从某个当前状态往后还有:

  • 多个价格场景;
  • 多个负荷场景;
  • 多个未来动作;
  • 多级 Scenario Tree。

一旦这些都在下一层被优化过,就可以把整棵 subtree 压缩成:

Vt(st) \boxed{V_t(s_t)}

所以更前一层不用重新展开所有叶子,只需要查:

这个下一状态值多少钱? \boxed{\text{这个下一状态值多少钱?}}

这就是 Dynamic Programming 能够做 backward recursion 的核心结构。


42. “当前局部最优” vs “基于当前信息的全局最优”

每一阶段并不是只最小化:

Ct(st,at) C_t(s_t,a_t)

否则容易出现:

现在便宜,但给未来留下一个非常昂贵的状态。

真正比较:

Ct(st,at)+E[Vt+1(st+1)] \boxed{ C_t(s_t,a_t) + E[V_{t+1}(s_{t+1})] }

所以:

当前阶段追求的是“基于当前信息的全局最优”,不是当前成本局部最优。 \boxed{ \text{当前阶段追求的是“基于当前信息的全局最优”,不是当前成本局部最优。} }

43. Ex-Ante Optimal 和 Ex-Post Optimal

即使一个策略是当时信息条件下的最优:

xt x_t^*

真实未来发生后,回头看可能存在一个更好的动作。

这不代表原决策一定错。

需要区分:

Ex-Ante Optimal

基于决策时点当时可获得的信息,做出的最优决策 \boxed{\text{基于决策时点当时可获得的信息,做出的最优决策}}

Ex-Post / Oracle Optimal

已经知道真实未来以后,回头计算出来的最优决策 \boxed{\text{已经知道真实未来以后,回头计算出来的最优决策}}

所以:

事后亏损证明事前决策错误 \boxed{ \text{事后亏损}\neq\text{证明事前决策错误} }

这和第一份笔记中的:

RPvsWS RP \quad\text{vs}\quad WS

是同一条逻辑。


44. 电力交易复盘因此要拆成两层

以后做交易复盘,不能只问:

实际价格发生后,哪个策略赚得最多?

还要问:

在当时的信息集下,真实可实施的策略中,哪个是最优?

因此可以区分:

Strategy / Decision Quality \boxed{\text{Strategy / Decision Quality}}

和:

Forecast / Distribution Quality \boxed{\text{Forecast / Distribution Quality}}

一个决策可能:

  • 事后结果很差,但基于当时分布是合理策略;
  • 事后碰巧赚钱,但当时实际上是一个风险极高的错误决策。

45. 目前还没有完全闭环的数学问题

我们已经知道 Birge & Louveaux 对多阶段随机线性规划给出:

  • 相应 feasibility sets 和 value functions 具有凸性;
  • 有限 scenario 时进一步具有 polyhedral 性质。

但是下面这些数学层面的证明目前还没有真正掌握

为什么递归后仍然凸? \boxed{ \text{为什么递归后仍然凸?} }
为什么求到的是模型内全局最优? \boxed{ \text{为什么求到的是模型内全局最优?} }
LP duality / KKT / optimality certificate 如何严格证明最优? \boxed{ \text{LP duality / KKT / optimality certificate 如何严格证明最优?} }

所以这里明确标记:

Needs Evidence / Later Review \boxed{ \text{Needs Evidence / Later Review} }

不要因为主线暂时继续,就误以为这部分数学已经完全掌握。


46. 本节完整知识链

这一节可以压成:

Risk NeutralCVaR Risk Control \boxed{ \text{Risk Neutral} \rightarrow CVaR\text{ Risk Control} }

然后:

True DistributionScenario GenerationSAAx^OOSGap/Validation \boxed{ \text{True Distribution} \rightarrow Scenario\ Generation \rightarrow SAA \rightarrow \hat x \rightarrow OOS \rightarrow Gap/Validation }

再继续:

Two-StageMultistagePolicyStateValue FunctionBackward Recursion \boxed{ Two\text{-}Stage \rightarrow Multistage \rightarrow Policy \rightarrow State \rightarrow Value\ Function \rightarrow Backward\ Recursion }

最后形成:

信息更新条件分布更新状态价值更新最优动作更新 \boxed{ \text{信息更新} \rightarrow \text{条件分布更新} \rightarrow \text{状态价值更新} \rightarrow \text{最优动作更新} }

47. 复习时最应该检查的 15 个问题

如果下面问题能脱稿回答,本节主干基本恢复。

  1. Risk-neutral stochastic programming 为什么可能不够?
  2. Mean-CVaR 和 CVaR hard constraint 分别表达什么风险偏好?
  3. Scenario Generation 和 SAA 有什么区别?
  4. 为什么 SAA 场景通常可以看成每个概率 1/N1/N
  5. 固定 xx 求样本平均为什么不叫 SAA optimization?
  6. 为什么“样本更多”只能说明更稳定,而不能自动说明更正确?
  7. 为什么日前和实时场景不能随意独立重采样?
  8. 为什么交易回测更适合 walk-forward,而不是随意随机打乱?
  9. Gap(x^)=g(x^)vGap(\hat x)=g(\hat x)-v^* 中,哪个量容易 OOS 估计,哪个更难?
  10. 为什么不能写成“每次 v^Nv\hat v_N\le v^*”,而只能说 E[v^N]vE[\hat v_N]\le v^*
  11. Multistage 的 solution 为什么是一套 policy,而不是一串提前写死的数字?
  12. Reality Forward 和 Optimization Backward 分别是什么意思?
  13. State 为什么不是完整历史,而是对未来仍有用的信息摘要?
  14. Jt(st,at)J_t(s_t,a_t)Vt(st)V_t(s_t) 有什么区别?
  15. min\minargmin\arg\min 分别给出什么?

48. 最小记忆版

如果过几天忘了细节,只先恢复下面这些。

Risk-Averse

minE[G]+λCVaR(G) \boxed{ \min E[G] + \lambda CVaR(G) }

SAA

E[F(x,ξ)]1Ns=1NF(x,ξs) \boxed{ E[F(x,\xi)] \approx \frac1N\sum_{s=1}^NF(x,\xi^s) }
x^N=argminxg^N(x) \boxed{ \hat x_N = \arg\min_x\hat g_N(x) }

Validation

Gap(x^)=g(x^)v \boxed{ Gap(\hat x)=g(\hat x)-v^* }
E[v^N]v \boxed{ E[\hat v_N]\le v^* }
Gap(x^)UL \boxed{ Gap(\hat x)\lesssim U-L }

Multistage Policy

π={x1,x2(ξ2),x3(ξ2,ξ3),} \boxed{ \pi= \{x_1,x_2(\xi_2),x_3(\xi_2,\xi_3),\dots\} }

State

st=截至现在,对未来决策仍有用的信息摘要 \boxed{ s_t= \text{截至现在,对未来决策仍有用的信息摘要} }

Value Function

Vt(st)=从当前状态往后能够达到的最小期望成本 \boxed{ V_t(s_t) = \text{从当前状态往后能够达到的最小期望成本} }

Action Value

Jt(st,at)=Ct(st,at)+E[Vt+1(st+1)st,at] \boxed{ J_t(s_t,a_t) = C_t(s_t,a_t) + E[V_{t+1}(s_{t+1})\mid s_t,a_t] }

Backward Recursion

Vt(st)=minatJt(st,at) \boxed{ V_t(s_t) = \min_{a_t}J_t(s_t,a_t) }
at=argminatJt(st,at) \boxed{ a_t^*=\arg\min_{a_t}J_t(s_t,a_t)}

最核心的一句话

未来先告诉现在:“你给我什么状态,我就告诉你以后最少要花多少”; \boxed{ \text{未来先告诉现在:“你给我什么状态,我就告诉你以后最少要花多少”;} }
现在再决定:“那我应该通过什么动作,把系统送到哪个状态”。 \boxed{ \text{现在再决定:“那我应该通过什么动作,把系统送到哪个状态”。} }

49. 下一阶段学习入口

当前已经具备继续进入下面内容的基础:

Scenario Tree Explosion \boxed{ Scenario\ Tree\ Explosion }
Scenario Reduction \boxed{ Scenario\ Reduction }
Rolling Horizon \boxed{ Rolling\ Horizon }
L-shaped/Benders Decomposition \boxed{ L\text{-}shaped/Benders\ Decomposition }

再往后才进入更高级的:

Nested CVaR/Dynamic Risk/Time Consistency/DRO \boxed{ Nested\ CVaR / Dynamic\ Risk / Time\ Consistency / DRO }

50. 参考来源与对应章节

  1. John R. Birge & François Louveaux, Introduction to Stochastic Programming

    • Chapter 2.5:Random Variables and Risk Aversion
    • Chapter 3.5:Multistage Stochastic Programs with Recourse
    • Chapter 10:Monte Carlo Methods
  2. Alexander Shapiro & Andy Philpott, A Tutorial on Stochastic Programming

    • Section 2.2:Monte Carlo / SAA
    • Section 2.3:Candidate solution evaluation / optimality gap
    • Section 3:Multi-stage stochastic programming / policy / backward dynamic programming
    • Section 4:Risk-averse optimization / chance constraints / VaR / CVaR
  3. Rockafellar & Uryasev, Optimization of Conditional Value-at-Risk

    • CVaR 辅助函数与 scenario-based optimization 形式。