需求函数的结构方程估计是指通过结构方程模型来估计需求函数的参数。
结构计量经济学:从直觉到代码的完整指南
第一章 什么是结构估计?
参见我另一篇文章的内容:动态优化结构估计大全
任何函数的结构估计都是要回归到动态最优化的形式,因为结构估计的初衷就是估计动态最优化过程。
理论上,只要你能将你的模型挂靠上动态最优化的壳,就可以做结构估计。
1.1 一个直觉性的开场
想象你观察到一个现象:油价上涨后,SUV 销量下降了。
简约式(Reduced Form)做法:
|
|
跑个回归,得到 $\beta = -0.3$,发表,收工。
结构估计的追问:
- 这个 -0.3 是从哪里来的?
- 如果政府补贴电动车,SUV 销量会变多少?
- 如果通货膨胀导致所有商品价格翻倍,这个弹性还是 -0.3 吗?
简约式回答不了这些问题,因为它只描述了数据中的相关性,没有告诉我们行为机制。
1.2 结构 vs 简约:本质区别
| 维度 | 简约式 | 结构估计 |
|---|---|---|
| 目标 | 描述条件期望 $E[Y \| X]$ | 恢复经济行为的深层参数(primitives) |
| 参数含义 | 统计相关 | 偏好/技术/信息结构 |
| 反事实分析 | ❌ 不可信 | ✅ 核心优势 |
| 模型依赖 | 低 | 高(但可检验) |
| Lucas 批判免疫 | ❌ | ✅ |
关键洞察:
结构估计的核心是相信:数据是由某个经济模型生成的,我们要做的是"逆向工程"——从数据反推模型参数。
$$ \text{Data} \xleftarrow{\text{DGP}} \text{Model}(\theta) \xrightarrow{\text{估计}} \hat{\theta} $$1.3 什么时候用结构估计?
✅ 适合用:
- 需要做政策反事实(如:取消某项补贴的福利影响)
- 关心的参数只能从模型中定义(如:消费者剩余)
- 需要将局部估计外推到新环境
❌ 可以不用:
- 只需描述因果效应,且有干净的识别策略
- 模型误设的风险太高,无法验证
⚠️ 常见陷阱: 把结构估计当作"更高级"的方法。实际上它是更强假设换取更多结论的 trade-off。
✅ 自检清单:
- 我的研究问题必须用结构模型才能回答吗?
- 我的模型假设是否可以用数据部分检验?
第二章 结构模型的三要素
任何结构模型都可以拆解为三个模块:
|
|
2.1 Primitives:你要估的东西
这些是模型的深层参数,理论上在政策变化时保持稳定。
例:离散选择需求模型
消费者 $i$ 对产品 $j$ 的效用:
$$ u_{ij} = \underbrace{\beta_i' x_j}_{\text{口味×属性}} - \underbrace{\alpha_i \cdot p_j}_{\text{价格敏感度}} + \underbrace{\xi_j}_{\text{未观测质量}} + \underbrace{\varepsilon_{ij}}_{\text{个体异质}} $$要估计的 primitives:
- $\alpha$:价格系数(用于计算弹性)
- $\beta$:属性偏好
- $\xi_j$:产品固定效应(与内生性紧密相关)
2.2 Equilibrium:模型怎么"闭合"
经济主体根据 primitives 做最优决策,均衡条件决定了可观测变量的生成。
消费者侧: 选择效用最大化的产品
$$ j_i^* = \operatorname*{arg\,max}_{j} u_{ij} $$厂商侧(如果模型包含供给): 价格满足一阶条件
$$ p_j = mc_j + \underbrace{\Delta^{-1} s(p)}_{\text{加成项 markup}} $$2.3 Observables:你手里有什么
数据通常是均衡的结果:
- 市场份额 $s_j$
- 交易价格 $p_j$
- 产品特征 $x_j$
关键洞察: 你的数据只是冰山一角,模型帮你建立 primitives → observables 的映射。
⚠️ 常见陷阱: 忘记 $\xi_j$ 这类未观测变量。它们是内生性的根源!
✅ 自检清单:
- 我是否明确列出了所有 primitives?
- 均衡概念是什么?(纳什?完美预期?)
- 哪些变量可观测,哪些需要从模型中"积分掉"?
第三章 识别(Identification)
3.1 识别在问什么?
非正式定义: 如果两组不同的参数 $\theta_1 \neq \theta_2$ 能产生完全相同的数据分布,那么参数不可识别。(参数和分布必须一一映射)
正式定义:
$$ \theta_1 \neq \theta_2 \Rightarrow P(Data | \theta_1) \neq P(Data | \theta_2) $$3.2 识别的三个层次
|
|
3.3 识别失败的直觉例子
例:需求与供给同时估计
观测到均衡点 $(p^*, q^*)$,但你不知道这是:
- 供给曲线移动后的新均衡?
- 还是需求曲线移动后的新均衡?
|
|
解决方案:工具变量
- 需求侧的 shifter(如成本冲击)帮助识别需求曲线
- 供给侧的 shifter(如收入冲击)帮助识别供给曲线
3.4 BLP 模型的识别逻辑
在 BLP 需求估计中1,核心内生性问题是:
$$ E[\xi_j | p_j] \neq 0 $$高质量产品($\xi_j$ 高)定价也高 → 价格系数 $\alpha$ 被低估。
BLP 的识别策略:
使用竞争对手特征作为工具变量:
$$ z_j = (\text{市场中其他产品的特征之和}) $$直觉:
- $z_j$ 与 $p_j$ 相关:竞争越激烈,加成越低
- $z_j$ 与 $\xi_j$ 不相关:我的产品质量和你的产品特征无关
3.5 如何检验识别
| 方法 | 适用场景 | 操作 |
|---|---|---|
| 解析证明 | 简单模型 | 求解 $\theta = f^{-1}(\text{moments})$ |
| 蒙特卡洛 | 复杂模型 | 生成数据 → 估计 → 检查是否恢复真实值 |
| 局部识别检验 | 所有模型 | 检查 Jacobian 矩阵的秩 |
局部识别的数值检验:
局部识别检验代码
|
|
⚠️ 常见陷阱:
- 只做局部识别检验,忽视全局不可识别(多个局部极小)
- 工具变量"看起来外生"但缺乏理论支撑
✅ 自检清单:
- 写出识别所依赖的排除性限制(exclusion restriction)
- 做过蒙特卡洛验证吗?
- 工具变量的有效性能用过度识别检验吗?
第四章 估计策略选择
4.1 估计方法全景图
|
|
4.2 最大似然估计(MLE)
何时使用:
- 似然函数有闭式表达
- 模型正确时效率最高
标准 Logit 的 MLE:
选择概率(假设 $\varepsilon_{ij} \sim$ Type I Extreme Value):
$$ Pr(j | i) = \frac{\exp(V_{ij})}{\sum_k \exp(V_{ik})} $$似然函数:
$$ \mathcal{L}(\theta) = \prod_i \prod_j Pr(j|i)^{y_{ij}} $$对数似然:
$$ \ell(\theta) = \sum_i \sum_j y_{ij} \log Pr(j|i) $$stata 计算 Logit 选择概率
|
|
4.3 广义矩估计(GMM)
何时使用:
- 有工具变量
- 只知道矩条件,不知道完整分布
GMM 的直觉:
模型告诉你:在正确的参数下,某些"矩条件"应该等于零。
$$ E[g(data, \theta_0)] = 0 $$估计量:找 $\hat{\theta}$ 使样本矩尽可能接近零:
$$ \hat{\theta}_{GMM} = \arg\min_\theta \ g_n(\theta)' W g_n(\theta) $$其中 $g_n(\theta) = \frac{1}{n}\sum_i g(data_i, \theta)$
BLP 中的矩条件:
$$ E[\xi_j \cdot z_j] = 0 $$其中 $\xi_j = \delta_j - x_j^{\prime} \beta$(从市场份额反推)
stata 计算 GMM 方差
|
|
4.4 模拟矩估计(SMM / MSM)
何时使用:
- 矩条件涉及高维积分,无法解析计算
- 例如混合 Logit 中对消费者异质性积分
核心思想:
用模拟代替解析积分:
$$ E_\nu[h(\nu)] \approx \frac{1}{R} \sum_{r=1}^R h(\nu_r), \quad \nu_r \sim F_\nu $$警告:模拟误差
模拟引入额外噪声。解决方案:
- 用足够多的模拟抽样 $R$
- 使用方差缩减技术(Halton 序列、重要性抽样)
- 固定随机种子以保证可复现
4.5 方法选择决策树
| 情景 | 推荐方法 | 理由 |
|---|---|---|
| 标准 Logit | MLE | 闭式似然,高效 |
| 混合 Logit | Simulated MLE 或 BLP | 需要对随机系数积分 |
| 有工具变量 | GMM / BLP | 矩条件直接处理内生性 |
| 动态模型 | Nested Fixed Point / CCP | 需要求解动态规划 |
| 高维参数 | MCMC / Variational | 避免优化困难 |
⚠️ 常见陷阱:
- 用 MLE 估计有内生性的模型(估计量不一致)
- GMM 的权重矩阵选择不当(效率损失)
- 模拟抽样数太少导致 bias
✅ 自检清单:
- 是否检查过一阶条件?
- GMM 用的是最优权重矩阵吗?
- 模拟数量的收敛性测试做了吗?
第五章 数值实现 💻
💡 Tip:算法部分使用 python,回归部分使用 stata,各司其职,让每种语言发挥自己擅长的地方。
5.1 目标函数构建
无论 MLE 还是 GMM,最终都归结为求解一个优化问题:
$$ \hat{\theta} = \arg\min_\theta Q(\theta) $$目标函数的设计原则:
- 光滑性:尽量让 $Q(\theta)$ 可微
- 尺度一致:参数的量纲要统一
- 数值稳定:避免溢出/下溢
例:带罚项的 GMM 目标函数
GMM 目标函数
|
|
5.2 嵌套不动点(Nested Fixed Point, NFXP)
BLP 的经典估计架构:
|
|
代码实现:
BLP 收缩映射
|
|
5.3 优化器选择
| 优化器 | 特点 | 适用场景 |
|---|---|---|
scipy.optimize.minimize (BFGS) |
快速,需要梯度 | 光滑目标函数 |
scipy.optimize.minimize (Nelder-Mead) |
无需梯度 | 非光滑、低维 |
scipy.optimize.minimize (L-BFGS-B) |
支持边界约束 | 参数有范围限制 |
scipy.optimize.differential_evolution |
全局搜索 | 多局部极小 |
pyomo / JuMP (Julia) |
大规模约束优化 | MPEC 重构 |
推荐的优化策略:
多阶段优化策略
|
|
5.4 起始值策略
起始值的重要性: 结构模型通常是非凸的,不同起始值可能收敛到不同的局部最优。
获取好的起始值:
| 方法 | 操作 |
|---|---|
| 简约式估计 | 先跑 OLS/Logit,用系数作为起始值 |
| 文献参考 | 使用类似研究的估计结果 |
| 参数边界 | 确保起始值在合理经济范围内 |
| 网格搜索 | 在参数空间粗略网格上评估目标函数 |
从简约式估计获取起始值
|
|
5.5 梯度计算
解析梯度 vs 数值梯度:
| 方法 | 优点 | 缺点 |
|---|---|---|
| 解析梯度 | 精确、快速 | 推导复杂、易出错 |
| 数值梯度 | 实现简单 | 慢、有截断误差 |
| 自动微分 | 两全其美 | 需要特定框架支持 |
推荐:使用自动微分
JAX 自动微分示例
|
|
⚠️ 常见陷阱:
- 内层循环(收缩映射)没收敛就返回
- 优化器默认容差太松
- 忽略参数边界导致无意义的估计值(如负的价格系数)
- 用一个起始值就下结论
✅ 自检清单:
- 内层循环的收敛容差足够紧吗?(通常 < 1e-12)
- 从多个起始值运行是否收敛到同一点?
- 目标函数值的数量级合理吗?
- 梯度检验(用数值梯度对照解析梯度)通过了吗?
第六章 完整案例:BLP 需求估计
6.1 模型设定
消费者 $i$ 对产品 $j$ 在市场 $t$ 的效用:
$$ u_{ijt} = \underbrace{x_{jt}'\beta_i}_{\text{口味}} - \underbrace{\alpha_i p_{jt}}_{\text{价格}} + \underbrace{\xi_{jt}}_{\text{未观测质量}} + \underbrace{\varepsilon_{ijt}}_{\text{个体冲击}} $$随机系数:
$$ \begin{pmatrix} \alpha_i \\ \beta_i \end{pmatrix} = \begin{pmatrix} \bar{\alpha} \\ \bar{\beta} \end{pmatrix} + \Sigma \cdot \nu_i, \quad \nu_i \sim N(0, I) $$选择概率:
$$ Pr(j|i,t) = \frac{\exp(\delta_{jt} + \mu_{ijt})}{1 + \sum_k \exp(\delta_{kt} + \mu_{ikt})} $$其中:
- $\delta_{jt} = x_{jt}'\bar{\beta} - \bar{\alpha} p_{jt} + \xi_{jt}$ (均值效用)
- $\mu_{ijt} = x_{jt}'\Sigma_\beta \nu_i^{\beta} - \Sigma_\alpha \nu_i^\alpha p_{jt}$ (个体偏离)
市场份额:
$$ s_{jt}(\delta, \Sigma) = \int Pr(j|i,t) \, dF(\nu) $$6.2 估计算法流程图
|
|
6.3 完整 Python 代码
BLP 需求估计器完整实现(约280行)
|
|
6.4 结果解读
运行上述代码后,你应该看到:
|
|
验证清单:
- 估计值接近真实值
- GMM 目标函数值足够小
- 弹性的符号正确(自价格弹性为负)
⚠️ 常见陷阱:
- 随机种子不固定导致结果不可复现
- 模拟抽样数太少(建议生产环境用 ns > 1000)
- 收缩映射容差太松(推荐 tol < 1e-12)
✅ 自检清单:
- 换不同起始值是否收敛到同一点?
- 增加模拟抽样数后估计值是否稳定?
- 预测份额与实际份额的相关性 > 0.95?
第七章 Debug 清单与稳健性检验
7.1 估计前的检查
| 检查项 | 方法 | 通过标准 |
|---|---|---|
| 数据完整性 | df.isnull().sum() |
无缺失或已处理 |
| 市场份额之和 | s.sum() |
< 1(包含外部选项) |
| 工具变量相关性 | 第一阶段 F 统计量 | F > 10(经验规则) |
| 价格变异 | p.std() / p.mean() |
有足够变异 |
7.2 估计中的检查
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 收缩映射不收敛 | σ 太大 / δ 初始值太差 | 限制 σ 范围 / 用 logit 初始化 δ |
| 优化器不收敛 | 目标函数不光滑 | 增加模拟数 / 换优化器 |
| 参数撞边界 | 边界设置不合理 | 检查模型设定 |
| 标准误过大 | 弱识别 | 检查工具变量强度 |
7.3 估计后的检查
估计后诊断代码
|
|
7.4 稳健性检验清单
| 检验类型 | 具体做法 | 预期结果 |
|---|---|---|
| 起始值敏感性 | 从 10 个随机起始点估计 | 收敛到同一最优 |
| 模拟数敏感性 | ns = 200, 500, 1000, 2000 | 估计值变化 < 5% |
| 工具变量选择 | 使用不同 IV 集合 | 点估计一致,效率可能不同 |
| 函数形式 | Logit vs Probit vs Mixed | 弹性的定性结论一致 |
| 样本分割 | 分时间段/地区估计 | 参数稳定 |
| 伪回归检验 | 打乱数据后估计 | 参数不显著 |
稳健性检验代码
|
|
第八章 总结:结构估计的思维框架
8.1 核心流程回顾
|
|
8.2 关键心智模型
-
结构估计是逆问题 模型定义了 $\theta \to Data$ 的映射,估计是反过来求 $\theta$。
-
模型是工具,不是信仰 所有模型都是错的,关键是它能否回答你的问题。
-
识别先于估计 如果不可识别,再好的算法也救不了你。
-
数值实现是手艺 同样的模型,好的实现和差的实现可以差 10 倍的时间和精度。
-
稳健性是诚信 不做稳健性检验的结构估计是不完整的。
8.3 推荐学习路径
|
|
8.4 经典文献
| 文献 | 贡献 | 阅读优先级 |
|---|---|---|
| Berry (1994) | 市场份额反演 | ⭐⭐⭐⭐⭐ |
| BLP (1995) | 随机系数需求 + IV | ⭐⭐⭐⭐⭐ |
| Nevo (2000) | BLP 估计实践指南 | ⭐⭐⭐⭐⭐ |
| Nevo (2001) | 测度市场势力 | ⭐⭐⭐⭐ |
| Rust (1987) | 动态离散选择 | ⭐⭐⭐⭐ |
| Hotz & Miller (1993) | CCP 估计 | ⭐⭐⭐⭐ |
| Dubé et al. (2012) | MPEC 方法 | ⭐⭐⭐ |
终章:一页纸速查表
|
|
祝你在结构估计的道路上一路顺风! 🎓
如果有具体问题(如某个公式推导、代码 bug、或者特定模型的实现),欢迎继续讨论。
被引用情况
-
BLP 需求模型通常指 Berry‑Levinsohn‑Pakes(1995)提出的随机系数 Logit 需求模型,是实证产业组织中用来估计差异化产品需求的经典结构模型。该模型允许不同消费者对产品特征有异质偏好,并同时处理价格内生性问题。 ↩︎