欢迎光临寒舍

结构估计实操攻略(中级)

8378 字

学完初级再来看。

结构估计方法选择与参数识别完美攻略

在学习完初级后,对实操有了一定的了解,再次基础上,想要写出更高质量的论文,就需要这篇中级 42 章经了。

第一章:决策树(从数据到方法)

1.1 终极决策树(15 个节点)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
START: 你要做结构估计
├─【NODE 1】你有个体层的选择数据吗?
│         (即能观测到"消费者选择了哪个产品"?)
├─YES → 【NODE 2】数据量有多大?
│       ├─ 小(<1000) → 检查Node 3
│       ├─ 中(1000-100k) → 检查Node 3
│       └─ 大(>100k) → 可用MLE或随机抽样MLE
├─【NODE 3】产品有多少个?(J=?)
│       ├─ 少(J<=5) → 【NODE 4A】
│       ├─ 中(5<J<=100) → 【NODE 4B】
│       └─ 多(J>100) → 【NODE 4C】
├─【NODE 4A】少产品+个体数据 → 优先MLE
│       ├─ 消费者特性异质吗?
│       │  ├─YES → Logit+随机系数 or Mixed Logit
│       │  └─NO → Multinomial Logit
│       └─ 需要反演质量ξ吗?
│          ├─YES → 转向BLP框架(见NODE 8)
│          └─NO → 纯MLE估计
├─【NODE 4B】中等产品+个体数据 → 考虑样本
│       ├─ 是否有缺失或不均衡?
│       │  ├─YES → 用子样本MLE(见Node 5)
│       │  └─NO → 仍用MLE但要关注收敛
│       └─ 跳转Node 3分析参数维度
├─【NODE 4C】多产品+个体数据 → 立即降维
│       ├─ 产品有聚类吗?(如品牌内产品)
│       │  ├─YES → 按品牌分层Logit
│       │  └─NO → 使用嵌套Logit (Nested Logit)
│       └─ 仍需反演质量ξ?
│          └─YES → BLP with dimensionality reduction
├─NO → 【NODE 5】你有市场份额数据吗?
│      (即只知道"产品j的销售占比",
│       不知道"谁买的"?)
├─YES → 【NODE 6】有产品特征数据吗?
│       ├─YES → 【NODE 7】产品变化的时间维度
│       │       ├─ 截面(单时期) → BLP GMM or IV-GMM
│       │       ├─ 面板(多时期) → 动态BLP (含lagged shares)
│       │       └─ 跳转Node 11分析工具变量
│       │
│       └─NO → 【NODE 6B】
│               ├─ 能用行业报告补充特征?
│               │  ├─YES → 组合数据后用BLP
│               │  └─NO → 只能做聚合层分析
│               └─ 使用矩估计而非参数估计
├─NO → 【NODE 8】你能获得更多数据吗?
│       ├─ 能 → 回到Node 1重新评估
│       ├─ 不能 → 【NODE 8B】
│               ├─ 有外部信息源?
│               │  (如已发表的参数)
│               │  ├─YES → 校准法(Calibration)
│               │  └─NO → 仅能进行描述分析
│               └─ 放弃结构估计
├─【NODE 11】处理内生性问题
│         (当X与扰动项相关)
├─问题1:价格与质量相关吗?
│       ├─ 是(价格高→质量好) → 价格内生
│       │  ├─ 有成本数据?
│       │  │  ├─YES → BLP 一阶条件反演成本
│       │  │  └─NO → 需要工具变量(IV)
│       │  └─ 工具变量有吗?
│       │     ├─YES → IV-GMM or BLP+IV
│       │     └─NO → 用函数形式假设识别
│       └─ 不是 → 继续
├─问题2:选择集与竞争相关吗?
│       (如小公司进入某些市场)
│       ├─ 是 → 需要样本选择修正
│       │  ├─Heckman-style correction
│       │  └─或控制函数法
│       └─ 不是 → 继续
├─【NODE 13】参数维度检查
│         k_params = ?
│       ├─ 小(k<10) → 任何方法都可以
│       ├─ 中(10<k<50) → MLE/GMM可行,BLP要小心
│       ├─ 大(50<k<200) → GMM优于MLE,BLP需优化
│       └─ 很大(k>200) → 需要降维或变分推断
├─【NODE 14】计算资源检查
│         你有多少时间和计算力?
│       ├─ 有GPU+1个月 → 可用神经网络辅助的BLP
│       ├─ 普通电脑+1周 → MLE或GMM,不要嵌套抽样
│       └─ 普通电脑+几天 → 简化模型
└─【NODE 15】最终决策输出
         根据以上所有信息,输出:
         优先方法 + 备选方案 + 关键假设

1.2 决策树使用指南

快速定位(3 分钟了解自己在哪)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
问自己这5个问题,快速定位:

1. "我能看到消费者买的是什么吗?"
   NO  → 你在NODE 5(只有市场份额)
   YES → 继续问2

2. "消费者数据有多少条?"
   <1000  → 用MLE
   >1M    → 用GMM或分块MLE
   → 继续问3

3. "我的产品数量?"
   <5     → MLE直接就行
   5-50   → 考虑降维
   >50    → 必须用GMM或BLP
   → 继续问4

4. "价格与产品质量相关吗?"
   不知道 → 假设相关,用IV处理
   明确不相关 → 可以不用IV
   → 继续问5

5. "我需要反演隐含质量ξ吗?"
   需要(做反事实分析)→ 用BLP框架
   不需要(只要参数)→ 用MLE或GMM

结果:你现在知道应该用哪个方法了!

第二章:按数据类型的完整攻略(实用性拉满)

2.1 数据类型 1:微观个体选择数据

数据样貌

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
典型形态:
consumer_id | product_id | price | features | choice
1           | A          | 20    | [...]    | 1
1           | B          | 25    | [...]    | 0
1           | C          | 22    | [...]    | 0
2           | A          | 20    | [...]    | 0
2           | B          | 25    | [...]    | 1
...

特点:
- 每个消费者选择1个产品(不选为0)
- 可以看到整个选择集
- 消费者特征已知
- 数据量:通常1000-1M行

方法优先级排序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
┌─ 【优先级1】Multinomial Logit (MNL)
│  ├─ 何时用:产品≤20且特征≤5
│  ├─ 为什么:计算快、收敛容易、诊断简单
│  ├─ 识别条件:基准产品V_0=0
│  ├─ 代码复杂度:★☆☆☆☆
│  └─ 计算时间:分钟级
├─ 【优先级2】Mixed Logit / Random Coefficients Logit
│  ├─ 何时用:产品≤50且需要消费者异质性
│  ├─ 为什么:比MNL更灵活,替代弹性更合理
│  ├─ 识别条件:基准产品+正态分布假设
│  ├─ 代码复杂度:★★★☆☆
│  ├─ 计算时间:小时级
│  └─ 困难点:需要数值积分(仿真ML)
├─ 【优先级3】BLP(Berry, Levinsohn, Pakes)
│  ├─ 何时用:产品>50或需要反演质量ξ
│  ├─ 为什么:可处理高维产品,获得质量参数
│  ├─ 识别条件:复杂(见后文)
│  ├─ 代码复杂度:★★★★★
│  ├─ 计算时间:天级
│  └─ 困难点:内循环优化难以收敛
└─ 【优先级4】Neural Network + Choice Model
   ├─ 何时用:参数>200或非参数偏好
   ├─ 为什么:参数维度无限制
   ├─ 识别条件:需要正则化
   ├─ 代码复杂度:★★★★★
   └─ 计算时间:小时级(有GPU)

识别矩的推导

对于 MNL:

模型:

$$ \begin{aligned} U_{ij} &= V_{ij}(X_j, \beta) + \varepsilon_{ij} \\ V_{ij} &= \beta' X_j \end{aligned} $$$$ \varepsilon_{ij} \sim \text{i.i.d. Gumbel} \implies P(\text{choose } j|\beta) = \frac{\exp(V_{ij})}{\sum_k \exp(V_{ik})} $$

识别矩条件:

$m_1(\beta)$: log-likelihood

$$ \ell(\beta) = \sum_i \sum_j y_{ij} \cdot \log(P_{ij}(\beta)) $$

其中 $y_{ij} = 1$ if consumer $i$ chooses $j$, else $0$

这给出一个矩条件:$\partial\ell/\partial\beta = 0$

识别要求:

  • 基准化:$V_1 = 0$(第一个产品无吸引力)
  • $\sum_j P_{ij} = 1$(概率和为 1)
  • $\text{rank}(\partial P/\partial\beta) = k$(参数维度)

识别充要条件的检查:

  • ☑ 有变量在某个产品特异但在其他产品相同吗?

    • 例:产品 A 的品牌特征($B_A$)在产品 B 中为 0
    • → 可以识别$B_A$的系数
  • ☑ 选择概率随$X$变化吗?(避免完美共线性)

    • 例:如果所有产品的价格完全相同
    • → 无法识别价格系数
  • ☑ 有足够的观测吗?(通常$n>100k$)

    • 否则参数估计不稳定

对于 Mixed Logit:

模型:

$$ \begin{aligned} U_{ij} &= \beta_i' X_j + \varepsilon_{ij} \\ \beta_i &\sim N(\bar{\beta}, \Sigma_\beta) \quad \text{(消费者$i$的参数随机)} \\ \varepsilon_{ij} &\sim \text{i.i.d. Gumbel} \end{aligned} $$$$ P(\text{choose } j|\beta_i) = \frac{\exp(\beta_i' X_j)}{\sum_k \exp(\beta_i' X_k)} $$$$ P(\text{choose } j|\bar{\beta}, \Sigma_\beta) = \int P(j|\beta) \cdot \varphi(\beta|\bar{\beta}, \Sigma_\beta) \, d\beta $$

识别矩条件:

  • $m_1(\bar{\beta})$: $\mathbb{E}[\partial \log P / \partial \bar{\beta}] = 0$(均值参数)
  • $m_2(\Sigma_\beta)$: $\mathbb{E}[\partial \log P / \partial \Sigma_\beta] = 0$(方差参数)

识别要求:

  • 基准化:$\Sigma_\beta$的某个对角元 $= 1$ or fixed
  • 消费者有重复选择吗?
    • → 有,可以识别$\Sigma_\beta$(从重复选择的相关性)
    • → 没有,$\Sigma_\beta$无法识别(需要额外假设)

识别充要条件的检查:

  • ☑ 每个消费者多个观测?

    • 如果每个消费者只有 1 个选择观测
    • → 只能识别$\bar{\beta}$,无法识别$\Sigma_\beta$
  • ☑ 产品特征的时间/空间变异足够大?

    • 例:同一消费者在不同时期面对不同价格
    • → 可以从不同时期的不同选择推断$\Sigma_\beta$
  • ☑ 交叉购买模式清晰吗?

    • 例:有人总是选"奢侈品",有人总是选"经济品"
    • → 暗示偏好异质性很大,$\Sigma_\beta$值得识别

常见的 3 个坑及解决方案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
【坑1】完美预测(Quasi-separation)
问题:某个产品被所有高收入消费者选择
     某个特征与选择完美相关
     → 参数估计趋向无穷

症状:
- 优化不收敛
- 参数估计很大(>100)
- 标准误巨大

解决:
方案A:检查数据质量
   ☑ 是否有数据输入错误?
   ☑ 是否样本量太小?
   ☑ 是否特征相关性太高?

方案B:正则化
   在目标函数中加惩罚项:
   ℓ(β) - λ·β'β

方案C:贝叶斯先验
   给参数添加先验:P(β)~N(0,σ²)
   避免参数发散


【坑2】多重共线性
问题:特征之间高度相关
     例:房子面积和房间数高度相关
     → 无法分离两个参数的效应

症状:
- 参数估计不稳定
- 改变样本后参数差异很大
- 标准误很大但系数也很大
- 相关性矩阵显示r>0.8

解决:
方案A:删除冗余特征
   ☑ 计算VIF (Variance Inflation Factor)
   ☑ 删除VIF>10的变量

方案B:主成分分析(PCA)
   将相关特征合并为不相关的主成分

方案C:岭回归(Ridge)
   正则化回归以处理共线性


【坑3】基准化错误
问题:没有正确设定基准产品
     或在不同模型间切换基准
     → 参数无法比较或标准误计算错误

症状:
- 改变基准产品后,其他系数也变化
- 系数之和不对
- 与文献数值明显不符

解决:
方案A:明确选择基准
   常见选择:
   ① Outside good (不选任何产品)
   ② 最受欢迎的产品
   ③ 某个标准产品(易于解释)

   确保:V_base = 0 在所有估计中

方案B:相对系数报告
   永远报告相对于基准的系数
   例:"相对于产品A,产品B高1.5单位"

方案C:协方差矩阵验证
   参数的SE应该反映基准选择
   用不同基准重新估计,验证SE不变

Python 代码框架

MNL估计框架
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import numpy as np
from scipy.optimize import minimize
import pandas as pd

# ========== MNL估计框架 ==========

class MNLModel:
    def __init__(self, data, product_features, price_col):
        """
        data: DataFrame with columns [consumer_id, product_id, choice]
        product_features: array of shape (J, K)
        price_col: array of shape (J,)
        """
        self.data = data
        self.X = product_features
        self.P = price_col
        self.J = product_features.shape[0]
        self.K = product_features.shape[1]

    def indirect_utility(self, beta):
        """
        计算间接效用: V = X @ beta + price_coef * ln(P)

        beta: array of shape (K+1,) where
              beta[:-1] = feature coefficients
              beta[-1] = price coefficient (should be negative)
        """
        feature_coef = beta[:-1]  # K个特征系数
        price_coef = beta[-1]      # 价格系数

        V = self.X @ feature_coef + price_coef * np.log(self.P)
        V = V - V[0]  # 基准化:第一个产品的V=0

        return V

    def choice_probability(self, beta):
        """
        计算选择概率: P(choose j) = exp(V_j) / sum_k exp(V_k)
        """
        V = self.indirect_utility(beta)
        exp_V = np.exp(V - np.max(V))  # 数值稳定性
        prob = exp_V / np.sum(exp_V)
        return prob

    def loglikelihood(self, beta):
        """
        目标函数:对数似然
        """
        prob = self.choice_probability(beta)

        ll = 0
        for _, row in self.data.iterrows():
            j = int(row['product_id'])
            ll += np.log(prob[j])

        return -ll  # 返回负LL用于最小化

    def estimate(self, beta_init=None, method='BFGS'):
        """
        估计参数
        """
        if beta_init is None:
            beta_init = np.zeros(self.K + 1)
            beta_init[-1] = -0.1  # 初始价格系数为负

        result = minimize(self.loglikelihood, beta_init,
                         method=method,
                         options={'disp': True})

        self.beta_est = result.x
        self.result = result

        return self.beta_est

# ========== 使用例子 ==========

# 生成模拟数据
np.random.seed(42)
n_consumers = 1000
J = 3  # 3个产品
K = 2  # 2个特征

# 产品特征
X_true = np.array([
    [1.0, 0.5],
    [0.5, 1.5],
    [1.5, 0.2]
])

# 产品价格
P = np.array([10, 15, 12])

# 真实参数
beta_true = np.array([0.3, 0.2, -0.15])  # [feature1_coef, feature2_coef, price_coef]

# 生成消费者选择
def generate_data(X, P, beta, n_consumers):
    V = X @ beta[:-1] + beta[-1] * np.log(P)
    V = V - V[0]  # 基准化
    exp_V = np.exp(V - np.max(V))
    prob = exp_V / np.sum(exp_V)

    choices = np.random.choice(J, n_consumers, p=prob)

    data_list = []
    for i in range(n_consumers):
        for j in range(J):
            data_list.append({
                'consumer_id': i,
                'product_id': j,
                'choice': 1 if choices[i] == j else 0
            })

    return pd.DataFrame(data_list)

data = generate_data(X_true, P, beta_true, n_consumers)

# 估计模型
model = MNLModel(data, X_true, P)
beta_est = model.estimate()

print("估计的参数:", beta_est)
print("真实参数:", beta_true)
print("参数误差:", np.abs(beta_est - beta_true))

2.2 数据类型 2:市场份额聚合数据

当你的数据没那么细致时……

数据样貌

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
典型形态:
market | year | product | price | market_share | features
1      | 2000 | A       | 15    | 0.35         | [...]
1      | 2000 | B       | 18    | 0.40         | [...]
1      | 2000 | C       | 12    | 0.25         | [...]
1      | 2001 | A       | 16    | 0.33         | [...]
...

特点:
- 不知道具体是谁买的,只知道比例
- 通常有多个市场(地区/时间)
- 数据维度小(J×T行)
- 通常J=5-100,T=5-20

方法优先级排序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
┌─ 【优先级1】BLP框架 (Berry, Levinsohn, Pakes)
│  ├─ 何时用:有多个市场+需要反演质量ξ
│  ├─ 为什么:标准方法,文献广泛应用
│  ├─ 识别条件:需要工具变量处理价格内生性
│  ├─ 代码复杂度:★★★★★
│  ├─ 计算时间:小时-天级
│  └─ 文献:产业组织学标配
├─ 【优先级2】矩估计 (GMM)
│  ├─ 何时用:无需反演ξ,只要参数
│  ├─ 为什么:更快,更简单,参数数量少
│  ├─ 识别条件:需要工具变量
│  ├─ 代码复杂度:★★★☆☆
│  ├─ 计算时间:分钟-小时级
│  └─ 最佳场景:快速实证检查
├─ 【优先级3】直接MLE(市场层)
│  ├─ 何时用:有代表性代理人假设
│  ├─ 为什么:少量参数时很快
│  ├─ 识别条件:简单(类MNL)
│  ├─ 代码复杂度:★★☆☆☆
│  ├─ 计算时间:秒-分钟级
│  └─ 警告:可能有偏(聚合偏差)
└─ 【优先级4】Logit差分法 (Differentiation BLP)
   ├─ 何时用:产品有多维特征
   ├─ 为什么:避免需要估计全部市场势能
   ├─ 识别条件:特征差异足够大
   └─ 代码复杂度:★★★★☆

识别矩的推导

BLP 识别逻辑:

核心思想:

给定偏好参数$\beta$,可以从市场份额反演质量$\xi$

步骤 1:从市场份额反演市场势能$\delta$

在 Logit 模型中:

$$ s_j = \frac{\exp(\delta_j)}{1 + \sum_k \exp(\delta_k)} $$

反演:

$$ \delta_j = \log\left(\frac{s_j}{s_0}\right) $$

其中$s_0$是 outside good 的市场份额。

步骤 2:从$\delta$分离出观测特征和$\xi$

$$ \delta_j = X_j' \beta + \xi_j $$

给定$\beta$,可以反演:

$$ \xi_j = \delta_j - X_j' \beta $$

步骤 3:$\beta$的识别来自工具变量矩条件

问题:价格与$\xi$相关(内生性),高质量产品定价更高

解决:使用工具变量(IV)

最常用 IV 组合:

  • $Z_{1j}$ = 其他产品的特征和($\sum_{k \neq j} X_k$)

    • 含义:竞争压力反映的成本信息
  • $Z_{2j}$ = 其他产品的价格和($\sum_{k \neq j} P_k$)

    • 含义:市场结构变化

矩条件:

$$ \mathbb{E}[Z' \cdot (\xi_j - \mathbb{E}[\xi_j|Z])] = 0 $$

即:$\mathbb{E}[Z' \cdot \xi_j] = 0$(如果假设$\mathbb{E}[\xi_j|Z] = 0$)

在实践中,使用 GMM 最小化:

$$ \min_{\beta} \left( \sum_j Z_j' \xi_j(\beta) \right)' W \left( \sum_j Z_j' \xi_j(\beta) \right) $$

识别充要条件检查:

  • ☑ 有多个市场吗?($T \geq 5$)

    • 否则:$\xi$无法识别(太少观测)
  • ☑ 工具变量与价格相关吗?($\text{Cor}(Z, P) > 0.3$)

    • Check: 回归$P$ on $Z$,检查$R^2 > 0.1$
    • 否则:弱 IV 问题
  • ☑ 工具变量与$\xi$无关吗?($\mathbb{E}[Z' \xi] = 0$)

    • 经济学假设:竞争结构不直接影响质量
    • 但可能有问题(如品牌集团的内部竞争)
  • ☑ 特征在市场间变化吗?

    • 如果$X$完全相同,无法识别$\beta$
    • 需要$X$有足够的时间或空间变异

GMM 识别逻辑:

如果不反演$\xi$,直接用矩估计:

假设:

$$ \mathbb{E}[X' \varepsilon] = 0 \quad \text{(外生性)} $$$$ \mathbb{E}[Z' \varepsilon] = 0 \quad \text{(工具变量正交性)} $$

其中$\varepsilon$是市场份额的预测误差:

$$ \varepsilon_j = s_j^{\text{actual}} - s_j^{\text{predicted}}(\beta) $$

矩条件:

$$ m(\beta) = \mathbb{E}[(X_j, Z_j)' \cdot \varepsilon_j] $$

样本矩:

$$ \hat{m}(\beta) = \frac{1}{N} \sum_j [(X_j, Z_j)' \cdot \varepsilon_j] $$

GMM 估计:

$$ \hat{\beta} = \arg \min_{\beta} \hat{m}(\beta)' W \hat{m}(\beta) $$

识别条件:

  • ☑ 矩条件数$\geq$参数数

    • 如果只有$K$个参数,需要至少$K$个矩条件
    • 超度时($>K$个矩),可做过度识别检验(Sargan)
  • ☑ 矩条件线性独立

    • 即:$\text{rank}(\mathbb{E}[\partial m / \partial \beta]) = K$
  • ☑ 参数真值在参数空间内部

    • 不能在边界上

常见的 3 个坑及解决方案

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
【坑1】弱工具变量问题
症状:
- 参数估计不稳定
- 改变子样本后结果变化很大
- IV的F统计量<10

原因:
- Z与X的相关性太弱
- 样本量太小
- 市场变异不足

解决方案:
方案A:更强的工具变量
   优化IV选择:
   ① Own & competitors' BLP
      Z_IVjt = Σ_{k≠j} X_kt (竞争对手特征)

   ② Cost shifters
      Z_IVjt = 供应链成本指数

   ③ Geographic instruments
      Z_IVjt = 其他地区产品特征

方案B:扩大样本
   如果有市场(地区/时间)维度:
   ☑ 增加时间跨度
   ☑ 增加地理覆盖

   样本量翻倍→参数精度√2提高

方案C:用过度识别检验选最强IV
   对不同IV组合计算J统计量
   选择J值最小的IV组合(最一致)


【坑2】聚合偏差 (Aggregation Bias)
症状:
- 用代表性代理人模型拟合市场份额
- 但预测的市场行为与微观数据不符
- 例:预测的价格弹性太小

原因:
- 市场份额是聚合数据,掩盖了消费者异质性
- 消费者对价格的敏感性不同
- 简单的Logit假设IIA(无关选择独立性)不成立

解决方案:
方案A:用Random Coefficients Logit
   允许消费者对特征有不同敏感性
   这会改变市场份额-价格的关系

   但代价:计算更复杂,需要数值积分

方案B:从微观数据校准异质性
   如果有微观数据(哪怕是样本):
   ① 用微观数据估计异质性分布
   ② 在BLP中导入这个分布
   ③ 用市场份额数据估计水平参数

方案C:用Logit差分法
   不直接估计,而是用产品差异
   减少需要估计的参数
   自动处理部分异质性


【坑3】内生性处理不当
症状:
- 系数符号不合经济直觉
  例:预期价格系数为负,却得到正的
- 价格系数很小(无法解释)
- 虽然用了IV,但仍然有偏

原因:
- 多种形式的内生性混淆
- 工具变量本身可能内生
- 没有处理样本选择偏差

解决方案:
方案A:分开不同的内生性来源

   1) 价格与质量相关(最常见)
      解决:用成本数据或质量指标做工具变量

   2) 企业选择进入哪个市场(选择偏差)
      解决:控制进入方程(Heckman校正)

   3) 产品特征本身是内生(企业选择特征)
      解决:用成本或技术限制作IV

方案B:进行内生性检验
   ① Durbin-Wu-Hausman检验
      比较OLS和IV的估计值
      如果接近→OLS已足够(不需要IV)

   ② Sargan过度识别检验
      检验IV是否真的外生

   ③ 弱IV诊断
      看IV的F统计量
      如果F<10,IV太弱

方案C:用多个IV做稳健性检查
   不同的IV→不同的β̂
   如果都相似→估计稳健
   如果差异大→问题可能在IV选择

Python 代码框架

BLP框架代码
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import numpy as np
import pandas as pd
from scipy.optimize import minimize
from scipy.linalg import inv
from scipy.stats import norm

# ========== BLP框架代码 ==========

class BLPModel:
    def __init__(self, data, instruments):
        """
        data: DataFrame with columns
              [market, product, price, market_share, features...]

        instruments: dict of lists
                     {'own': [own features],
                      'competitors': [competitors' features]}
        """
        self.data = data
        self.instruments = instruments

        # 提取基本信息
        self.markets = data['market'].unique()
        self.products = data['product'].unique()
        self.J = len(self.products)
        self.T = len(self.markets)

    def logit_invert(self, s, s0=None):
        """
        从市场份额反演市场势能δ

        Logit模型:s_j = exp(δ_j) / (1 + Σ_k exp(δ_k))
        反演:δ_j = log(s_j / s_0)
        """
        if s0 is None:
            s0 = 1 - np.sum(s)  # outside good份额

        delta = np.log(s / s0)
        return delta

    def invert_xi(self, delta, X, beta):
        """
        从δ反演ξ
        δ = X'β + ξ
        ξ = δ - X'β
        """
        X_beta = X @ beta
        xi = delta - X_beta
        return xi

    def market_share_logit(self, delta):
        """
        从δ计算市场份额(Logit)
        """
        exp_delta = np.exp(delta - np.max(delta))  # 稳定性
        denom = 1 + np.sum(exp_delta)
        market_share = exp_delta / denom
        return market_share

    def gmm_objective(self, beta, W_matrix):
        """
        GMM目标函数

        用途:最小化 m'Wm
        其中 m = (1/T) Σ_t Z'_t ξ_t(β)
        """

        # 计算所有市场的ξ
        xi_all = []
        Z_all = []

        for market in self.markets:
            market_data = self.data[self.data['market'] == market]

            # 提取数据
            s = market_data['market_share'].values
            P = market_data['price'].values
            X = market_data[['feature_1', 'feature_2']].values  # 根据实际调整

            # 反演δ和ξ
            delta = self.logit_invert(s)
            xi = self.invert_xi(delta, X, beta)

            # 构造工具变量Z
            # 标准选择:[X, competitors'X, competitors'P]
            Z_own = X
            Z_comp = np.mean(X[1:], axis=0)  # 竞争对手特征平均
            Z = np.column_stack([Z_own, Z_comp, P])

            xi_all.extend(xi)
            Z_all.extend(Z)

        # 计算样本矩
        Z_all = np.array(Z_all)
        xi_all = np.array(xi_all)

        moment = (Z_all.T @ xi_all) / len(xi_all)

        # GMM目标函数
        gmm_obj = moment @ W_matrix @ moment

        return gmm_obj

    def estimate(self, beta_init=None):
        """
        BLP估计步骤:
        步骤1:初始估计权重矩阵W (恒等矩阵或2SLS)
        步骤2:用W最小化GMM目标函数,得β̂
        步骤3:计算高效权重矩阵W*
        步骤4:再次最小化GMM(高效GMM)
        """

        # 步骤1:初始化W为恒等矩阵
        W = np.eye(self.J)

        if beta_init is None:
            beta_init = np.zeros(2)  # 假设2个特征

        # 步骤2-4:GMM迭代
        for iteration in range(2):
            # 最小化GMM目标函数
            result = minimize(self.gmm_objective, beta_init,
                            args=(W,),
                            method='BFGS')

            beta_new = result.x

            # 更新权重矩阵(有效GMM)
            # W* = (Z'ΣZ)^{-1},其中Σ是矩的协方差

            beta_init = beta_new

        self.beta_est = beta_new
        self.gmm_result = result

        return self.beta_est

# ========== 使用例子 ==========

# 生成模拟数据
np.random.seed(42)
T = 10  # 10个市场
J = 3   # 3个产品

data_list = []
for t in range(T):
    for j in range(J):
        data_list.append({
            'market': t,
            'product': j,
            'price': np.random.uniform(10, 30),
            'market_share': np.random.uniform(0.1, 0.5),
            'feature_1': np.random.uniform(0, 2),
            'feature_2': np.random.uniform(0, 2),
        })

data = pd.DataFrame(data_list)

# 标准化市场份额(每个市场内和为1)
data['market_share'] = data.groupby('market')['market_share'].transform(
    lambda x: x / x.sum()
)

# 创建模型和估计
instruments = {'own': ['feature_1', 'feature_2'],
               'competitors': ['price']}

model = BLPModel(data, instruments)
beta_est = model.estimate()

print("估计的β:", beta_est)

2.3 数据类型 3:面板数据

我们最常用的其实是面板数据……

数据样貌

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
典型形态:
consumer_id | time | product_id | choice | price | features
1           | 1    | A          | 1      | 20    | [...]
1           | 1    | B          | 0      | 25    | [...]
1           | 2    | A          | 0      | 21    | [...]
1           | 2    | C          | 1      | 19    | [...]
...

特点:
- 同一消费者或市场的多期观测
- 可能有动态效应(过去的选择影响现在)
- 可能有个体固定效应
- 维度:N×T个观测

方法选择

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
┌─ 【优先级1】静态面板Logit(忽视面板结构)
│  ├─ 何时用:没有明显的动态或固定效应
│  ├─ 操作:直接使用Logit/MNL,把面板数据当截面
│  └─ 适用:N很大,T很小(<5)
├─ 【优先级2】随机效应Logit (Chamberlain方法)
│  ├─ 何时用:有消费者固定偏好,但偏好不变
│  ├─ 模型:U_it = X_it'β + α_i + ε_it
│  │        α_i ~ N(0, σ_α²)
│  ├─ 识别:需要每个i有多个t
│  └─ 代码:使用条件MLE或积分出α
├─ 【优先级3】固定效应Logit (Chamberlain, 1980)
│  ├─ 何时用:α_i可能与X相关(固定效应处理)
│  ├─ 方法:只用个体内方差(within变换)
│  ├─ 警告:丧失固定特征的识别(如性别)
│  └─ 识别:只能估计时变变量的系数
├─ 【优先级4】动态模型(包含lag)
│  ├─ 何时用:Y_{t-1}显著影响Y_t的选择
│  ├─ 模型:U_it = X_it'β + γ·Y_{it-1} + α_i + ε_it
│  ├─ 困难:γ同时受α和Y_{t-1}影响(偏差项)
│  ├─ 解决:使用Arellano-Bond GMM或Blundell-Bond
│  └─ 代码复杂度:★★★★★
└─ 【优先级5】结构性动态模型
   ├─ 何时用:需要解构消费者的状态依赖
   ├─ 模型:Bellman方程+ 动态规划
   ├─ 计算:嵌套固定点迭代
   └─ 代码复杂度:★★★★★(最难)

识别检查

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
动态模型识别的关键条件:

1. 需要足够的历史数据
   Rule of thumb: T ≥ 4

   为什么?设定检验需要T个过度识别条件

2. 最初条件需要处理
   Y_0(初始选择)与α相关

   解决:
   - 用Blundell-Bond初始条件模型
   - 或使用Heckman的两步法

3. 弱外生性
   需要:E[ε_it | X_i1,...,X_iT, Y_i0,...,Y_i,t-1] = 0

   即:未来的X不能影响当前的ε

   检验:用Granger因果关系检验

2.4 数据类型 4:含缺失值的数据

我想,这是每一个研究者都头疼的问题,数据缺失……

类型识别

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
缺失机制分类:

【类型A】随机缺失 (MCAR)
缺失概率与任何数据都无关
P(missing | Y, X) = P(missing)

处理:直接删除缺失行(样本容量减少)

【类型B】可忽略缺失 (MAR)
缺失取决于观测数据,但不取决于缺失值本身
P(missing | Y, X) = P(missing | X)

处理:
- 多重插补 (Multiple Imputation)
- 逆概率加权 (Inverse Probability Weighting)

【类型C】不可忽略缺失 (NMAR)
缺失取决于缺失值本身
P(missing | Y, X) = P(missing | Y, X)

处理:
- 需要检验模型
- 或需要外部信息证明缺失机制

处理方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
方法1:删除缺失(只在MCAR时适用)
优点:简单
缺点:样本量减少,可能有偏

方法2:多重插补(MI)
步骤:
1. 用多元回归或其他方法补全K次(通常K=5-10)
2. 对每个补全数据集进行MLE/GMM估计
3. 综合K个估计值(Rubin规则)

公式:
β̂_MI = (1/K) Σ_k β̂_k

SE_MI = √[(1/K)Σ_k SE_k² + (1 + 1/K)·(1/(K-1))Σ_k(β̂_k-β̂_MI)²]

方法3:EM算法
设定隐变量模型,用EM估计

方法4:样本选择修正 (Heckman)
如果缺失取决于另一个变量(选择变量)

模型:
Y_i = X_i'β + ε_i    (结果方程)
S_i = Z_i'γ + u_i    (选择方程)

观测Y当且仅当S_i > 0

矫正方法:
加入Heckman λ项到结果方程
Y_i | S_i>0 = X_i'β + ρσ·λ(Z_i'γ) + ε_i*

其中λ = φ(·)/Φ(·)是逆Mills比

第三章:按参数类型的识别攻略(重点)

3.1 参数类型 1:偏好参数 (β)

识别原理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
为什么偏好参数能被识别?

因为:消费者面对不同的价格和特征时做出不同的选择
      这种选择模式反映了偏好

例子:
产品A:价格10,质量1 → 50%消费者选择
产品B:价格15,质量1 → 30%消费者选择
产品C:价格12,质量2 → 20%消费者选择

从选择概率的变化推断:
- 价格上升(10→15),份额下降(50%→30%)
  → 价格系数β_P < 0

- 同样的质量,但价格便宜,份额更高
  → 质量系数β_Q > 0

关键:选择对价格和特征的敏感性

识别矩

标准的识别矩条件:

  1. 一阶条件 (FOC 矩)

    $$ m_j(\beta) = \left.\frac{\partial \ell}{\partial \beta}\right|_j = 0 $$

    含义:对数似然对参数的偏导为 0

  2. 外生性矩

    $$ \mathbb{E}\left[ Z' (Y_j - P_j(\beta)) \right] = 0 $$

    其中 $Z$ 是工具变量,$Y$ 是实际选择,$P$ 是模型预测

  3. 原始矩 (Sample Moments)

    $$ \mathbb{E}\left[(Y_j - s_j(\beta)) \cdot g(X_j)\right] = 0 $$

    其中 $g(X)$ 是特征函数

检验矩条件是否足够:

  • ☑ 参数数量 $K$
  • ☑ 独立矩条件数 $M$
  • ☑ $M \ge K$(识别)
  • ☑ $M > K$(过度识别,可做 Sargan 检验)

常见的陷阱

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
【陷阱1】参数与特征的共线性
问题:两个特征高度相关(如房屋面积和房间数)
后果:无法分离两个参数

检验:
计算VIF = 1/(1-R²_j)
如果VIF > 5 → 问题严重

解决:
① 删除一个特征
② 用PCA合并特征
③ 加入先验信息约束参数


【陷阱2】特征在样本内无变异
问题:所有消费者面对相同的价格
后果:无法识别价格系数

检验:
计算特征的标准差
如果SD接近0 → 问题

解决:
① 检查是否数据有错误
② 寻找自然实验(不同地区价格不同)
③ 使用工具变量


【陷阱3】参数被固定效应吸收
问题:在固定效应Logit中,产品固定特征消失

例如:固定品牌品质的估计
在:U_it = β_price·P_it + β_quality·Q_i + α_i + ε_it

固定效应变换后:
ΔU_it = β_price·ΔP_it + 0·ΔQ_i + Δε_it
         品质Q_i消失了!

解决:
① 不使用固定效应(假设α_i外生)
② 用随机效应,允许α_i与X相关
③ 用Mundlak设定:α_i = X̄_i'δ + a_i

3.2 参数类型 2:成本参数 (MC)

识别原理

成本参数通常不直接观测,需要反演

反演的基础:企业利润最大化

Bertrand 模型(价格竞争):

$$ \max \pi_j = (P_j - \text{MC}_j) \cdot Q_j(P) $$

FOC: $\partial \pi_j / \partial P_j = 0$

求解得:

$$ P_j - \text{MC}_j = -\frac{Q_j}{\partial Q_j / \partial P_j} = -\frac{s_j \cdot M}{\partial s_j / \partial P_j} $$

其中$M$是市场大小,$s_j$是份额。

反演:

$$ \text{MC}_j = P_j + \frac{s_j}{\text{价格弹性}_j} $$

关键:给定需求参数$\beta$(已估计),可以精确计算 MC。

识别矩

识别 MC 需要的条件:

  1. 需求参数已估计

    • ☑ 已有$\hat{\beta}$
  2. 市场结构已知

    • ☑ 什么定价方式(Bertrand vs Cournot)
    • ☑ 是否有差异化产品
  3. 市场份额与价格

    • ☑ 能计算$s_j$
    • ☑ 能计算$\partial s_j / \partial P_j = \alpha \cdot s_j (1-s_j)$ in Logit

然后:

$$ \text{MC}_j = P_j - \frac{s_j}{\alpha \cdot s_j (1-s_j)} = P_j - \frac{1}{\alpha (1-s_j)} $$

这不是"估计",而是"计算"!

常见陷阱

【陷阱 1】市场结构假设错误

问题:假设 Bertrand,实际是 Cournot

后果:反演的 MC 值不对

Cournot 模型:

$$ \frac{\partial \pi_j}{\partial Q_j} = 0 $$$$ P - \text{MC}_j = \frac{S_j \cdot M}{\partial Q_j / \partial P_j \cdot M} = \frac{S_j^2}{\text{弹性}} $$

反演式与 Bertrand 完全不同!

解决:

用兼并分析或进入分析来判断,观察兼并后价格如何变化,与模型预测对比。


【陷阱 2】忽视多产品企业

问题:忽视企业跨产品的利润考虑

多产品 FOC:

$$ \frac{\partial \pi_{\text{firm}}}{\partial P_j} = 0, \quad \sum_j \frac{\partial \pi_j}{\partial P_j} = 0 $$

企业在为产品$j$定价时,会考虑对其他产品$Q_k$的影响。

解决:

用系统的 FOC 求解:

$$ \text{MC}_j = [\text{Price vector} - \text{Inverse elasticity matrix}] $$

需要估计完整的价格竞争矩阵。


【陷阱 3】静态模型的局限

问题:假设静态,实际有动态

企业可能:

  • 为了获得市场份额而低价
  • 通过高价收割品牌溢价
  • 进行长期竞争

静态模型捕捉不到这些。

解决:

用动态博弈模型,或至少在解释中加入警告。

3.3 参数类型 3:质量参数 (ξ)

识别原理

质量$\xi$定义为:消费者能观测到但我们看不到的产品特征

识别逻辑:

如果消费者选择了产品$j$而不是$k$,说明 $U_j > U_k$

$$ V_j + \varepsilon_j > V_k + \varepsilon_k $$$$ X_j' \beta + \xi_j + \varepsilon_j > X_k' \beta + \xi_k + \varepsilon_k $$$$ \xi_j - \xi_k > (X_k - X_j)' \beta + (\varepsilon_k - \varepsilon_j) $$

在大样本下,观测频率反映概率:选择$j$的频率 $\approx P(U_j > U_k)$

给定$\beta$(已估计)和$X_j$(可观测),我们可以从这个频率反演出相对的$\xi_j$

BLP 反演:

在 Logit 模型中,市场份额是充分统计量:

$$ s_j = \frac{\exp(\delta_j)}{1 + \sum_k \exp(\delta_k)} $$

反演$\delta$:

$$ \delta_j = \ln(s_j) - \ln(s_0) $$

分解$\delta$:

$$ \delta_j = X_j' \beta + \xi_j $$$$ \xi_j = \delta_j - X_j' \beta $$

识别矩

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
质量参数的识别条件:

1. 基准化约束
   通常设定:ξ_1 = 0(第一个产品的相对质量为0)
   或:Σ_j ξ_j = 0(相对质量平均为0)

2. 市场份额的足够变异
   ξ通过市场份额反演
   如果s_j不变化,ξ无法识别

   ☑ 需要多个市场(T ≥ 5)
   ☑ 每个市场份额有变化

3. 选择集的内稳定性
   产品集合J在市场间相同
   否则无法比较不同市场的ξ

4. 不可观测特征与观测特征无关
   E[ξ_j | X_j] = 0(可能需要工具变量处理)

识别矩条件:
给定β,ξ可以从市场份额唯一反演
这不是"估计",而是确定的计算

常见陷阱

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
【陷阱1】反演使用了错误的参数β
问题:如果β有偏,ξ也会有偏

偏差传递:
ξ̂ = δ - X'β̂
E[ξ̂] = E[δ] - X'E[β̂]
      = ξ + X'(β - E[β̂])

β的偏差→ξ的偏差

检验:
进行敏感性分析
改变β的值(±10%),看ξ如何变化
如果ξ变化>50%,问题严重

解决:
① 提高β的估计精度
② 报告参数的置信区间和对应的ξ范围
③ 进行大量蒙特卡洛模拟


【陷阱2】市场份额测量误差
问题:市场份额本身有测量误差
      如:销售额不准、市场定义不清

后果:
反演的ξ包含了测量误差

ξ̂_j = δ_j^obs - X_j'β
     = (δ_j^true + noise) - X_j'β
     = ξ_j^true + noise

质量参数被污染

检验:
看ξ的时间序列
如果抖动很大(ξ_j在年份间变化>100%)→疑似测量误差

解决:
① 使用更可靠的销售数据来源
② 对ξ进行平滑(如3年均值)
③ 用卡尔曼滤波分解信号和噪声


【陷阱3】不可观测异质性偏差
问题:ξ包含两部分
      ① 产品的真实不可观测质量
      ② 市场-产品特异的需求冲击

无法分离这两部分

例如:产品在南方畅销
是因为:① 真实适合南方气候?
        ② 南方人恰好偏好该风格?

反演的ξ混合了两者

解决:
① 引入消费者特征数据
   看相同消费者的跨地区选择

② 使用工具变量
   假设气候影响选择,但通过产品质量
   用气候作为ξ的工具变量

③ 检验ξ是否稳定
   同一产品在不同市场的ξ
   应该有相关性(>0.3)
   否则测量有问题

3.4 参数类型 4:异质性参数 (σ)

识别原理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
异质性参数σ_β测量消费者偏好差异

为什么能识别?

在同一消费者的多期观测中:
如果偏好确实不同,会体现为:
- 相同特征的产品,不同消费者的选择不同
- 特征小幅变化,某些消费者转向,某些不转向

从选择的交叉价格弹性推断异质性:

低异质性(σ=0)→ 所有消费者相同
  交叉价格弹性:ε_{jk} = -α·P_j·s_j (IIA性质)

高异质性(σ很大)→ 消费者差异大
  交叉价格弹性:ε_{jk} = -α·P_j·s_j + (高阶项)
  两个替代品的替代弹性很小(消费者有强烈的理想品牌)

识别条件:
☑ 有重复观测(同一消费者多期)
☑ 特征有充分变异
☑ 消费者确实做出了分化的选择

识别矩

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
异质性参数的识别:

使用广义矩估计(GMM):

矩条件1:对数似然的一阶条件
E[∂ℓ/∂β̄] = 0  (均值参数)
E[∂ℓ/∂Σ_β] = 0  (协方差参数)

矩条件2:交叉价格弹性矩
E[ε_{jk}(实际) - ε_{jk}(模型预测)] = 0

对于Mixed Logit:
实际的交叉弹性取决于σ
通过比较实际和预测,推断σ

数学上:
Price elasticity = Cov(α_i, ∂P_ij/∂P_j)

这个协方差取决于σ_α(价格敏感性的异质性)

常见陷阱

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
【陷阱1】过度参数化
问题:允许每个特征都有异质性
      参数数量爆炸

例如:3个特征都允许随机系数
      β_price, β_quality, β_brand都是随机
      参数变为:3个均值 + 3个方差 + 3个协方差 = 9个!

后果:
难以收敛,估计不稳定,过度拟合

解决:
① 只对重要特征允许异质性
   用似然比检验判断:
   H0: σ = 0(无异质性)
   如果LR统计量>3.84,才加入

② 假设异质性之间独立
   Cov(β_i, β_j) = 0 for i≠j
   减少参数


【陷阱2】分布假设错误
问题:假设异质性为正态分布
      实际可能不是

后果:
参数估计有偏

检验:
估计后,计算隐含的β_i分布
用Q-Q图检验是否正态

如果明显偏态或多峰→问题

解决:
① 使用半参数分布
   如:logit normal(β通过logit映射)

② 进行稳健性检验
   用不同分布重新估计
   比较结果


【陷阱3】无法识别所有矩
问题:在某些情况下,数据不足以识别σ

例如:
- 消费者没有重复观测→无法识别σ_β
- 产品特征变化很小→σ无法识别
- 样本全部来自一个区域→σ_区域无法识别

检测:
进行秩检验
rank(∂m/∂σ) < σ的维度
→无法识别

解决:
① 添加外部数据(如消费者调查)
② 固定某些σ值(基于文献或先验)
③ 报告识别集合而非点估计

第四章:方法对比表与决策矩阵

4.1 完整方法对比

维度 MLE GMM BLP IV-GMM 动态
数据需求 微观选择 市场份额+特征 市场份额+特征 市场份额+工具变量 面板
参数维度限制(k<?) <100 <50 <200 <50 <50
计算时间 分钟-小时 秒-分钟 小时-天 分钟-小时 小时
收敛难度 极低 中等 中等
反演 ξ 是(核心) 可以
处理内生性 困难 容易(IV) 容易 容易 困难
标准误推断 标准清晰 需要 δ 方法 需要 δ 方法 标准清晰 需要
过度识别检验 是(Sargan)
文献应用 广 广 产业组织 逐增加 特定
代码资源
学习难度 ★★☆☆☆ ★★☆☆☆ ★★★★★ ★★★☆☆ ★★★★
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
何时用每个方法(简单判断):

MLE:
  ☑ 有个体消费者选择数据
  ☑ 产品数<50
  ☑ 不需要反演质量
  ☑ 快速估计是首要目标

GMM:
  ☑ 只有市场份额
  ☑ 需要处理内生性
  ☑ 参数数量<50
  ☑ 快速计算很重要

BLP:
  ☑ 需要反演质量ξ(做反事实)
  ☑ 产品很多(>50)
  ☑ 有足够的多市场数据
  ☑ 计算资源和时间充足

IV-GMM:
  ☑ 有很强的内生性问题
  ☑ 有好的工具变量
  ☑ 想要精确的因果效应

动态:
  ☑ 明显的状态依赖效应
  ☑ 需要结构性解释(如习惯效应)
  ☑ 有充足的面板数据

4.2 决策矩阵(快速选择)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
根据你的具体情况,找到对应的单元格:

                    产品数
                小       中       大
        ┌─────────────┬──────────┬──────────┐
   有微 │    MLE      │  BLP或   │   BLP    │
微 观 │  (直接用)   │  抽样MLE │ (必选)   │
观 个 │             │          │          │
数 体 │  时间:分钟  │ 时间:小时│ 时间:天  │
据 │             │          │          │
   └─────────────┴──────────┴──────────┘
        ┌─────────────┬──────────┬──────────┐
   只有 │  简单矩估   │   BLP    │   BLP    │
市 份 │   或GMM    │          │          │
场 额 │             │          │          │
数 │  时间:秒-分钟│时间:分钟-小时│时间:小时│
据 │             │          │          │
   │  需要IV:   │需要IV:  │需要IV:  │
   │  用IV-GMM  │ 加入BLP  │ 加入BLP  │
   └─────────────┴──────────┴──────────┘

需要反演ξ?    → 用BLP框架
有内生性?     → 用GMM或BLP+IV
个体数据?     → 用MLE
快速估计?     → 用GMM
有动态效应?   → 考虑动态框架(Arellano-Bond等)

第五章:完整案例流程

案例 A:简单情景(新手友好)

问题描述:电商平台的手机选择分析

数据特征

1
2
3
4
- 2000个消费者的手机选择记录
- 5个手机品牌(iPhone, 三星, 华为, OPPO, 小米)
- 观测变量:价格、屏幕大小、电池容量、品牌
- 无时间维度(截面数据)

第 1 步:通过决策树定位

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
START
【有微观选择数据吗?】YES
【产品数量?】5个(少)
【特征数?】4个(中等)
【需要反演质量吗?】NO(只是比较品牌)
【消费者异质性强吗?】YES(可能有)
【结论】使用Mixed Logit(随机系数Logit)

第 2 步:选择理由

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
为什么选Mixed Logit而非MNL?

1. 产品差异化:5个品牌,消费者有强偏好
   MNL假设IIA(独立无关性)不合理
   消费者不会因为新增iPhone 12而改变对三星的相对偏好

2. 消费者异质性:
   学生可能看重价格
   商务人士可能看重品质
   MNL无法捕捉这种差异

3. 替代效应:
   MNL预测:如果iPhone降价,三星份额也会同比例下降
   现实:iPhone降价可能只影响其他高端机

Mixed Logit允许:
各消费者有不同的价格敏感性β_i,price
不同的品牌偏好β_i,brand
这样的差异会自然产生合理的替代弹性

第 3 步:参数识别检查

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
需要估计的参数:

待估参数θ = {β̄_price, β̄_screen, β̄_battery, β̄_brand,
              σ_price, σ_screen, σ_battery}

共:4个均值 + 3个方差 = 7个参数

识别条件检查:

1. 样本量足够吗?
   2000个消费者 >> 7个参数
   ✓ 足够(规则:n/k > 100)

2. 特征有变异吗?
   价格:1000-5000元(SD大)✓
   屏幕:5.5-6.7英寸(SD中等)✓
   电池:3000-5000mAh(SD大)✓
   品牌:5类别(离散)✓

3. 消费者选择有分化吗?
   iPhone份额:25%
   三星份额:20%
   华为份额:30%
   (不是某个品牌垄断)✓

4. 是否有完美分离?
   检查:任何品牌-特征组合都有人选有人不选
   (否则某个品牌系数无法识别)✓

结论:参数可以识别

第 4 步:数据准备代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import pandas as pd
import numpy as np
from scipy.optimize import minimize
from scipy import stats

# 加载数据
data = pd.read_csv('phone_choice.csv')
# 列:consumer_id, choice_brand, price, screen, battery, ...

# 数据检查
print(data.head())
print(data.describe())

# 创建虚拟变量(品牌固定效应)
brands = ['iPhone', 'Samsung', 'Huawei', 'OPPO', 'Xiaomi']
for brand in brands[:-1]:  # 留最后一个作为基准
    data[f'brand_{brand}'] = (data['choice_brand'] == brand).astype(int)

# 标准化特征(帮助收敛)
data['price_std'] = (data['price'] - data['price'].mean()) / data['price'].std()
data['screen_std'] = (data['screen'] - data['screen'].mean()) / data['screen'].std()
data['battery_std'] = (data['battery'] - data['battery'].mean()) / data['battery'].std()

# 创建选择矩阵(每个消费者看每个产品)
# 扩展数据框:每个消费者-产品对一行
choice_expanded = []
for i in range(len(data)):
    consumer_features = data.iloc[i]
    for j, brand in enumerate(brands):
        choice_expanded.append({
            'consumer_id': consumer_features['consumer_id'],
            'brand': brand,
            'price_std': np.random.normal(consumer_features['price_std'], 0.1),
            # (这里简化了,实际应该有每个产品的特征)
            'choice': 1 if consumer_features['choice_brand'] == brand else 0
        })

data_expanded = pd.DataFrame(choice_expanded)

第 5 步:Mixed Logit 估计代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
class MixedLogitModel:
    def __init__(self, data, J, K):
        """
        data: 扩展数据框 (消费者×产品行数)
        J: 产品数
        K: 特征数
        """
        self.data = data
        self.J = J
        self.K = K
        self.n_consumers = len(data) // J

    def simulate_betas(self, mean_beta, cov_beta, n_draws=100):
        """
        模拟消费者参数从正态分布
        """
        betas = np.random.multivariate_normal(mean_beta, cov_beta,
                                              size=(self.n_consumers, n_draws))
        # shape: (n_consumers, n_draws, K)
        return betas

    def logit_choice_prob(self, X, betas_sim):
        """
        计算Logit选择概率(对每个draw求平均)
        """
        # X: (n_consumers*J, K) 特征矩阵
        # betas_sim: (n_consumers, n_draws, K)

        # 计算效用
        # U = X @ beta (每个draw,每个消费者,每个产品)

        # 这里简化为向量化计算
        X = self.data[['price_std', 'screen_std', 'battery_std']].values

        # 重新组织X为 (n_consumers, J, K)
        X_reshaped = X.reshape(self.n_consumers, self.J, -1)

        probs = []
        for i in range(self.n_consumers):
            # 该消费者的各draw的参数
            beta_i_draws = betas_sim[i]  # (n_draws, K)

            # 计算每个draw下的效用
            U_i_draws = X_reshaped[i] @ beta_i_draws.T  # (J, n_draws)

            # Logit概率(对每个draw)
            exp_U = np.exp(U_i_draws - np.max(U_i_draws, axis=0))
            prob_draws = exp_U / np.sum(exp_U, axis=0)  # (J, n_draws)

            # 对draws求平均
            prob_i = np.mean(prob_draws, axis=1)  # (J,)
            probs.append(prob_i)

        return np.array(probs)  # (n_consumers, J)

    def loglikelihood(self, theta, n_draws=100):
        """
        计算对数似然
        theta = [mean_beta, cov_beta_params]
        """
        # 从theta提取参数
        K = self.K
        mean_beta = theta[:K]

        # 协方差矩阵参数(仅对角元素,简化)
        std_beta = np.exp(theta[K:2*K])  # 指数变换保证正
        cov_beta = np.diag(std_beta**2)

        # 模拟draw
        betas_sim = self.simulate_betas(mean_beta, cov_beta, n_draws)

        # 计算选择概率
        probs = self.logit_choice_prob(self.data, betas_sim)

        # 计算似然
        ll = 0
        for i in range(self.n_consumers):
            for j in range(self.J):
                if self.data.iloc[i*self.J + j]['choice'] == 1:
                    ll += np.log(max(probs[i, j], 1e-10))

        return -ll

    def estimate(self, initial_guess=None):
        """估计参数"""
        if initial_guess is None:
            initial_guess = np.zeros(2*self.K)

        result = minimize(self.loglikelihood, initial_guess,
                         method='BFGS',
                         options={'disp': True, 'maxiter': 1000})

        self.theta_est = result.x
        self.result = result

        return result

# 使用
model = MixedLogitModel(data_expanded, J=5, K=3)
result = model.estimate()

print("估计的平均参数:")
print(result.x[:3])
print("\n标准差参数:")
print(np.exp(result.x[3:6]))

第 6 步:结果解读

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
估计结果(示例):
┌──────────────────────┬─────────┬───────────┬────────┐
│ 参数                 │ 估计值  │ 标准误    │ t值    │
├──────────────────────┼─────────┼───────────┼────────┤
│ β̄_price              │ -0.025* │ 0.005     │ -5.0   │
│ β̄_screen             │  0.312* │ 0.045     │ 6.9    │
│ β̄_battery            │  0.158* │ 0.032     │ 4.9    │
│ σ_price              │  0.015* │ 0.003     │ 5.0    │
│ σ_screen             │  0.089* │ 0.022     │ 4.0    │
│ σ_battery            │  0.045* │ 0.018     │ 2.5    │
└──────────────────────┴─────────┴───────────┴────────┘

解读:

1. 平均效应
   - 价格每增加1000元(相对于标准化),选择概率降低2.5%
   - 屏幕每大0.5英寸,选择概率增加15.6%
   - 电池每增加500mAh,选择概率增加7.9%

2. 异质性
   - 消费者对价格的敏感性标准差:0.015
     某些消费者对价格很敏感(β=-0.04)
     某些不敏感(β=-0.01)
   - 屏幕偏好异质性更大(σ=0.089)
     反映学生vs商务的差异

3. 经济学含义
   - 消费者更看重屏幕大小(β_screen最大)
   - 对价格相当敏感(负系数且显著)
   - 电池容量重要但不如屏幕

4. 替代弹性
   估计:iPhone降价10%
   Mixed Logit预测:
   - iPhone份额:↑3.2%(来自其他高端机)
   - 三星份额:↓1.8%(失去高端消费者)
   - 小米份额:↓0.4%(低端品牌影响小)

第 7 步:诊断检查

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 1. 模型的拟合度
actual_share = data.groupby('choice_brand').size() / len(data)
predicted_share = model.predict_market_share()

print("实际市场份额:", actual_share.values)
print("预测市场份额:", predicted_share)
print("MAE:", np.mean(np.abs(actual_share.values - predicted_share)))

# 2. 参数稳定性检验
# 用不同初始值重新估计
for init_seed in [1, 2, 3]:
    np.random.seed(init_seed)
    initial_guess = np.random.normal(0, 0.1, 2*K)
    result_alt = model.estimate(initial_guess)
    print(f"Seed {init_seed}:", result_alt.x[:K])
# 如果结果相近→收敛

# 3. 蒙特卡洛模拟标准误
n_boot = 200
theta_boots = []
for b in range(n_boot):
    # 有放回抽样
    idx_boot = np.random.choice(len(data), len(data), replace=True)
    data_boot = data.iloc[idx_boot]

    model_boot = MixedLogitModel(data_boot, J=5, K=3)
    result_boot = model_boot.estimate(model.theta_est)
    theta_boots.append(result_boot.x)

theta_boots = np.array(theta_boots)
se_boot = np.std(theta_boots, axis=0)
print("Bootstrap标准误:", se_boot[:K])

# 4. Sargan过度识别检验(如果用了IV)
# 这个案例没有内生性,所以跳过

案例 B:复杂情景(进阶学习)

问题描述:汽车市场的 BLP 估计与并购分析

数据特征

1
2
3
4
5
- 20年(1990-2009)的汽车市场数据
- 每年150-200个车型
- 市场份额、价格、燃油效率、马力、大小、产地等
- 企业-产品对应关系
- 多个市场(不同国家)

方法选择路径

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
START
【数据形态】市场份额+产品特征(聚合数据)
【产品数】150-200个(很多)
【需要反演质量】YES(做并购反事实)
【有多市场】YES(20年×多国)
【需要处理价格内生性】YES(质量与定价相关)
【结论】BLP框架 + 工具变量 + 多市场

估计策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
步骤1:需求端估计
─────────────────
使用BLP框架:
δ_jt = X_jt'β + ξ_jt + ε_jt

其中:
- δ是市场势能(从份额反演)
- X_jt是可观测特征
- ξ_jt是不可观测质量
- ε_jt是模型拟合误差

识别:
- 基准化:X_1包含常数项(品牌固定效应)
- 工具变量:
  IV_1 = 竞争车型特征(成本代理)
  IV_2 = 自身滞后价格(动态结构)
  IV_3 = 其他产品成本代理(供给侧信息)

步骤2:供给端
───────────
从一阶条件反演边际成本:

Bertrand定价:
(P_jt - MC_jt) = -s_jt / ∂s_jt/∂P_jt

反演:
MC_jt = P_jt + s_jt / (|ε_{jt,price}|)

步骤3:进行反事实
────────────────
并购模拟:
1. 设定两个企业合并
2. 假设并购后利润函数合并
3. 重新求解Bertrand均衡
4. 计算新价格、份额、消费者福利

步骤4:政策含义
──────────────
与基准比较,计算:
- 消费者福利变化
- 企业利润变化
- 社会福利影响

完整代码框架

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import numpy as np
import pandas as pd
from scipy.optimize import fminbound, minimize, root
from scipy.linalg import inv
import matplotlib.pyplot as plt

class BLPModel:
    """
    BLP离散选择模型估计
    """

    def __init__(self, market_data, firm_data):
        """
        market_data: DataFrame
        columns: [market_id, product_id, price, share, features...]

        firm_data: DataFrame
        columns: [product_id, firm_id]
        """
        self.market_data = market_data
        self.firm_data = firm_data

        self.markets = sorted(market_data['market_id'].unique())
        self.n_markets = len(self.markets)

        # 提取市场和产品信息
        self.products_by_market = {}
        for market in self.markets:
            prods = market_data[market_data['market_id']==market]['product_id'].unique()
            self.products_by_market[market] = list(prods)

    def invert_shares_to_delta(self, shares, market_id):
        """
        用Logit反演δ
        s_j = exp(δ_j) / (1 + Σ_k exp(δ_k))
        """
        # 计算outside good份额
        s0 = 1 - np.sum(shares)

        # 防止log(0)
        shares = np.clip(shares, 1e-10, 1-1e-10)
        s0 = np.clip(s0, 1e-10, 1)

        # 反演
        delta = np.log(shares / s0)

        return delta

    def estimate_demand_BLP(self, X, Z, shares, n_iter=2):
        """
        BLP两步GMM估计

        X: (J×T, K) 产品特征矩阵
        Z: (J×T, L) 工具变量矩阵
        shares: (J×T,) 市场份额向量
        """

        J_total = len(shares)
        K = X.shape[1]
        L = Z.shape[1]

        # 第一步:用恒等矩阵作权重矩阵
        W = np.eye(L)

        for iteration in range(n_iter):
            # 反演δ
            # (需要按市场分组)
            delta_all = []
            for market in self.markets:
                market_mask = self.market_data['market_id'] == market
                shares_m = self.market_data[market_mask]['share'].values
                delta_m = self.invert_shares_to_delta(shares_m, market)
                delta_all.extend(delta_m)

            delta = np.array(delta_all)

            # 计算ξ = δ - X'β (对初始β=0)
            # β̂ = arg min_β (Z'ξ(β))'W(Z'ξ(β))

            def gmm_objective(beta):
                xi = delta - X @ beta
                moment = (Z.T @ xi) / len(xi)
                return moment @ W @ moment

            # 优化
            result = minimize(gmm_objective, np.zeros(K), method='BFGS')
            beta_new = result.x

            # 更新权重矩阵(高效GMM)
            xi = delta - X @ beta_new
            G = (Z.T @ X) / len(xi)  # (L, K)
            S = (Z.T @ (xi**2)[:, None] * Z) / len(xi)  # (L, L) 残差协方差
            W = inv(S) @ G @ inv(G.T @ inv(S) @ G) @ G.T @ inv(S)

            print(f"Iteration {iteration+1}: β={beta_new}, GMM_obj={gmm_objective(beta_new)}")

        self.beta_est = beta_new
        self.xi = xi

        return beta_new

    def supply_side_estimation(self, prices):
        """
        从供给侧一阶条件反演边际成本和定价权
        """

        # 用估计的β计算价格弹性
        # ε_jj = α_price * P_j * (1 - s_j)

        # (简化版,实际应该构造完整的Jacobian矩阵)

        results = []
        for market in self.markets:
            market_mask = self.market_data['market_id'] == market
            s = self.market_data[market_mask]['share'].values
            p = self.market_data[market_mask]['price'].values

            # 估计的α(价格系数,应该是负数)
            alpha_price = self.beta_est[self.feature_names.index('price')]

            # 计算自身价格弹性
            elast = alpha_price * p * (1 - s)

            # Bertrand FOC:P - MC = -s / ε
            mc = p - s / elast

            for i, (prod, p_i, mc_i) in enumerate(zip(
                self.products_by_market[market], p, mc)):
                results.append({
                    'market': market,
                    'product': prod,
                    'price': p_i,
                    'marginal_cost': mc_i,
                    'markup': p_i - mc_i
                })

        return pd.DataFrame(results)

    def counterfactual_merger(self, firm1, firm2, new_ownership=None):
        """
        并购反事实:重新求解Bertrand均衡
        """

        # 合并两个企业的产品
        merged_products = self.firm_data[
            self.firm_data['firm'].isin([firm1, firm2])
        ]['product_id'].unique()

        # 新的所有权矩阵
        if new_ownership is None:
            ownership = self.get_ownership_matrix()
            # 修改:两个企业的交叉所有权从0变为1
            for i in merged_products:
                for j in merged_products:
                    ownership[i, j] = 1
        else:
            ownership = new_ownership

        # 求新均衡
        # 这需要嵌套求解(内循环:给定定价求份额,外循环:优化价格)

        # (简化:用一阶条件直接更新价格)
        new_prices = self.solve_bertrand_equilibrium(ownership)

        return new_prices

    def solve_bertrand_equilibrium(self, ownership_matrix, max_iter=100, tol=1e-6):
        """
        求Bertrand均衡价格
        """

        prices_old = self.market_data['price'].values.copy()

        for iteration in range(max_iter):
            prices_new = self.bertrand_foc_update(prices_old, ownership_matrix)

            if np.max(np.abs(prices_new - prices_old)) < tol:
                print(f"Bertrand均衡在{iteration}次迭代后收敛")
                break

            prices_old = prices_new

        return prices_new

    def get_ownership_matrix(self):
        """构造所有权矩阵"""
        products = sorted(self.firm_data['product_id'].unique())
        J = len(products)

        ownership = np.zeros((J, J))
        for i, prod_i in enumerate(products):
            for j, prod_j in enumerate(products):
                firm_i = self.firm_data[self.firm_data['product_id']==prod_i]['firm'].values[0]
                firm_j = self.firm_data[self.firm_data['product_id']==prod_j]['firm'].values[0]
                ownership[i, j] = 1 if firm_i == firm_j else 0

        return ownership

# 使用例子
blp = BLPModel(market_data, firm_data)

# 1. 准备特征矩阵
X = market_data[['price', 'fuel_efficiency', 'horsepower', 'size']].values
# 标准化
X = (X - X.mean(axis=0)) / X.std(axis=0)

# 2. 准备工具变量
Z = market_data[['competitors_avg_price', 'competitors_avg_size']].values

shares = market_data['share'].values

# 3. 估计需求
beta = blp.estimate_demand_BLP(X, Z, shares)
print("估计的特征系数:")
print(beta)

# 4. 供给端估计
supply = blp.supply_side_estimation(market_data['price'].values)
print("边际成本估计:")
print(supply.head())

# 5. 并购反事实
new_prices = blp.counterfactual_merger('Toyota', 'Honda')
print("并购后的新价格:")
print(new_prices)

# 6. 福利分析
welfare_change = blp.calculate_welfare_change(new_prices)
print("消费者福利变化:", welfare_change)

主要输出与解释

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
需求端估计结果:
┌──────────────┬──────────┬────────────┐
│ 特征         │ 系数     │ 含义       │
├──────────────┼──────────┼────────────┤
│ Price        │ -0.082*  │ 很敏感     │
│ Fuel Eff.    │  0.045*  │ 看重经济性 │
│ Horsepower   │  0.032*  │ 关心性能   │
│ Size         │  0.027*  │ 偏好更大   │
└──────────────┴──────────┴────────────┘

这告诉我们消费者的偏好顺序:
1. 价格最敏感(系数绝对值最大)
2. 燃油效率其次
3. 性能和大小相当

反事实结果:

丰田-本田并购后:
- 丰田车型平均提价:+$300(约2%)
- 本田车型平均提价:+$250(约1.8%)
- 竞争对手价格变化:-$50(被并购企业抢占份额)

消费者福利:
- 基准消费者剩余:$2500(平均)
- 并购后消费者剩余:$2350
- 福利损失:-$150(6%下降)
  原因:并购企业行使定价权

产业福利:
- 消费者:-$5亿
- 并购企业:+$8亿
- 竞争对手:+$2亿
- 社会:+$5亿(企业获利>消费者损失)
  但考虑消费者权重,总体可能是负的

政策含义:
- 并购会增加市场竞争关注
- 需要考虑反垄断审查

第六章:诊断检查清单与快速参考

6.1 估计后的诊断检查表(8 个指标)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
【指标1】收敛诊断
───────────────
检查项目:
☑ 优化算法是否收敛?
  (优化器的消息是"success"吗?)

☑ 多次初始值是否收敛到相同位置?
  (用3个不同初值估计,结果接近?)

☑ 参数估计是否稳定?
  (小样本变化不应导致大的参数变化)

判断标准:
✓ 优化器报告success
✓ 不同初值的估计差异<5%
✓ 目标函数值跨初值相同
✓ 梯度范数<1e-6

常见问题:
✗ "未收敛"→增加迭代次数或改变算法
✗ 不同初值差异>10%→可能有多个局部最优
✗ 梯度太大→检查参数规范化


【指标2】参数合理性检验
──────────────────────
检查项目:
☑ 参数符号合经济直觉吗?
  ✓ 价格系数应为负
  ✓ 产品质量系数应为正
  ✓ 成本系数应为正

☑ 参数大小合理吗?
  价格系数-0.1 ← 合理
  价格系数-0.001 ← 太小(消费者对价格无反应)
  价格系数-1000 ← 太大(不现实)

☑ 异质性参数合理吗?
  σ_β应该<<|β̄|(异质性<平均值)
  否则可能过度参数化

判断标准:
✓ 所有系数符号与理论一致
✓ 大小在文献范围内(对标其他论文)
✓ σ_β < 0.5×|β̄|
✓ 没有参数估计值为0或无穷


【指标3】拟合度检验
──────────────────
计算指标:

平均绝对误差(MAE):
MAE = (1/J) Σ_j |ŝ_j - s_j|

平均相对误差(MAPE):
MAPE = (1/J) Σ_j |ŝ_j - s_j| / s_j

判断标准:
✓ MAE < 0.05(预测份额误差<5%)
✓ MAPE < 0.10 (相对误差<10%)
✓ 某个产品的误差不>20%

视觉检验:
绘制实际vs预测份额:
plot(s_actual, s_predicted)
应该接近45度线

常见问题:
✗ MAE > 0.1 → 模型设定可能有问题
✗ 某个产品预测特别差 → 检查该产品数据
✗ 系统性偏差(全都高估或低估)→ 可能有遗漏变量


【指标4】标准误合理性
──────────────────────
检查项目:
☑ 标准误是否太小?
  如果SE < |coeff|/10
  可能有高度共线性或样本选择

☑ t值是否过高?
  t值 > 100 → 疑似问题
  可能是数据单位问题或参数规范化不足

☑ 信息矩阵是否奇异?
  计算行列式 det(Hessian)
  应该是正的(不接近0)

判断标准:
✓ SE在5%-20%的系数范围内
✓ t值在2-20范围内
✓ 所有参数的SE都能算出(Hessian可逆)


【指标5】识别检验(过度识别)
─────────────────────────────
仅当有超过参数数的矩条件时:

Sargan检验统计量:
J_stat = n × m'W m

其中m是样本矩,W是权重矩阵

渐近分布:χ²(L-K)
其中L=矩条件数,K=参数数

判断标准:
☑ J_stat < χ²_{0.95}(L-K)
  √ p值 > 0.05 → IV外生性无法拒绝

常见问题:
✗ J_stat很高 → IV可能内生或模型错设


【指标6】内生性诊断(如果用了IV)
──────────────────────────────────
Durbin-Wu-Hausman检验:

DWH_stat = (β̂_OLS - β̂_IV)' Var_diff (β̂_OLS - β̂_IV)

如果显著→OLS有偏→确实需要IV

判断标准:
☑ DWH_stat > χ²_{0.95}(K)
  √ p值 < 0.05 → 确实有内生性

弱IV诊断:
☑ IV的F统计量 > 10
  (检验Z对内生变量的解释力)

判断标准:
✓ F > 10 → IV足够强
✓ F < 10 → 弱IV问题,小样本偏差可能大


【指标7】参数敏感性分析
────────────────────────
改变关键假设,重新估计:

敏感性矩阵 (对每个参数):
当假设A变化(±10%) → 参数β变化百分比

示例:
│ 假设              │ β_price改变 │ 判断     │
│ 样本容量 -10%    │    +2%     │ 稳定     │
│ 特征标准化 改变   │    +1%     │ 稳定     │
│ 丢弃top 5% 样本  │    +8%     │ 相对敏感 │
│ 换不同IV         │   +25%     │ 高度敏感 │

判断标准:
✓ 所有敏感性 < 10% → 很稳健
✓ 敏感性 10%-25% → 中等敏感
✓ 敏感性 > 25% → 结果不稳定,需谨慎

常见问题:
✗ 丢弃小样本后参数大变 → 可能有离群值影响
✗ 换IV后参数大变 → IV选择有问题


【指标8】替代弹性检验(仅对选择模型)
────────────────────────────────────
计算交叉价格弹性:
ε_{jk} = (∂s_j/∂P_k) × (P_k/s_j)

MNL的不合理特征(IIA):
ε_{jk} / ε_{j'k} 应该与j'无关

Mixed Logit应该避免这个问题

判断标准:
绘制交叉弹性矩阵:
如果MNL的结果显示:
┌─────┬────┬────┬────┐
│ ε   │ A  │ B  │ C  │
├─────┼────┼────┼────┤
│ A   │-1.5│0.15│0.08│
│ B   │0.10│-1.2│0.05│
│ C   │0.15│0.20│-1.5│
└─────┴────┴────┴────┘

看B对A的弹性(0.10)与C对A的弹性(0.15)的比率
应该等于B和C的相对竞争力

✓ 如果比率接近 → IIA假设大致成立
✗ 如果比率偏离 → 混合模型更合适

6.2 一页纸快速参考卡

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
╔════════════════════════════════════════════════════════════════════════╗
║        结构估计方法快速决策表(打印出来贴在办公室)                     ║
╚════════════════════════════════════════════════════════════════════════╝

┌─ 我有什么数据?
├─ 【A】个体的选择(消费者选了什么产品)
│  ├─ 产品数<20 → 【方法】MNL or Mixed Logit
│  │              【时间】分钟级
│  │              【难度】简单
│  │              【工具】Scipy.optimize.minimize
│  │
│  ├─ 产品数20-100 → 【方法】Mixed Logit with sampling
│  │                  【时间】小时级
│  │                  【难度】中等
│  │                  【工具】PyLogit or Biogeme
│  │
│  └─ 产品数>100 → 【方法】BLP框架 or Neural Network
│                   【时间】小时-天级
│                   【难度】困难
│                   【工具】Custom code or BLP codes
├─ 【B】市场份额+产品特征(聚合数据)
│  ├─ 只需要参数 → 【方法】GMM or 简单矩估计
│  │              【时间】秒-分钟级
│  │              【难度】简单
│  │
│  ├─ 需要反演质量ξ → 【方法】BLP框架
│  │                   【时间】小时-天级
│  │                   【难度】困难
│  │
│  └─ 有内生性 → 【方法】IV-GMM or BLP+IV
│               【时间】小时级
│               【难度】中等-困难
├─ 【C】面板数据(多期个人选择)
│  ├─ 静态偏好 → 【方法】随机系数Logit
│  │            【特殊】加入消费者固定效应
│  │
│  ├─ 动态效应 → 【方法】Arellano-Bond 或结构性动态模型
│  │            【难度】最困难(★★★★★)
│  │
│  └─ 缺失值 → 【方法】多重插补 + MLE/GMM
│            【备选】EM算法估计

┌─ 我需要处理什么问题?
├─【内生性】价格与质量相关
│  → 使用工具变量(IV)
│  → IV选择:竞争对手特征、成本指标、地区变异
├─【样本选择】某些产品进入而某些不进入
│  → 使用样本选择修正(Heckman)
│  → 或估计进入模型
├─【测量误差】销售数据不准确
│  → 用更可靠的数据源
│  → 或加入测量误差模型
├─【多重共线性】特征间高度相关
│  → 计算VIF,删除VIF>10的特征
│  → 或使用PCA降维
└─【参数太多】k>100个参数
   → 降维(PCA)
   → 或用贝叶斯/正则化方法

┌─ 我要做什么检验?
├─ 【基础检验】
│  ✓ 模型收敛了吗?(优化器报告success?)
│  ✓ 参数符号对吗?(负数/正数?)
│  ✓ t值合理吗?(2-20之间?)
├─ 【拟合度检验】
│  ✓ MAE或MAPE < 10%?
│  ✓ 某个产品拟合不好吗?(检查数据)
├─ 【识别检验】
│  ✓ Sargan检验 p值 > 0.05?(过度识别约束成立)
│  ✓ IV的F统计量 > 10?(不是弱IV)
├─ 【稳健性检验】
│  ✓ 不同初值收敛到同样结果?
│  ✓ 子样本估计结果相近?
│  ✓ 丢弃异常值后参数变化<10%?
└─ 【政策含义检验】
   ✓ 反事实分析结果符合经济学直觉?
   ✓ 敏感性分析显示结果稳健?

┌─ 我该用什么代码库?
├─ Python工具
│  ├─ MLE/Logit: statsmodels, scipy
│  ├─ Mixed Logit: PyLogit, biogeme(Biogeme官网)
│  └─ BLP: 自写(可参考github上的BLP_py)
├─ R工具
│  ├─ Logit: mlogit, nnet
│  ├─ Mixed: bayesm, mlogit
│  └─ BLP: blp-py (github)
├─ Julia工具(计算最快)
│  └─ BLP: BLP.jl (github)
└─ Stata工具
   ├─ Logit: mlogit, cmlogit
   └─ GMM: gmm命令

╔════════════════════════════════════════════════════════════════════════╗
║ 最后的话:不要过度复杂化。选择足以回答你的研究问题的最简单的方法。  ║
╚════════════════════════════════════════════════════════════════════════╝

BLP.jl dev; github


第七章:常见问题解答 (FAQ)

Q1: 我应该用 MLE 还是 GMM?

:根据以下决策:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
MLE最合适当:
✓ 你有微观选择数据
✓ 产品数<50
✓ 参数数<30
✓ 可以快速估计

GMM最合适当:
✓ 你只有市场份额数据
✓ 需要处理内生性(有工具变量)
✓ 参数数<50
✓ 想做过度识别检验

一句话判断: 有微观数据就用 MLE,没有就用 GMM。


Q2: 为什么我的参数收敛不了?

最常见的 3 个原因:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
原因1:参数初值太差
解决:用多个初值估计,或用OLS/简单Logit的估计作初值

原因2:参数规范化有问题
解决:
- 检查X矩阵是否有极端值(如价格从0.1到10000)
  → 标准化:(X - mean(X)) / std(X)
- 检查某个特征完全相同
  → 删除恒定特征

原因3:模型设定有问题
解决:
- 简化模型:去掉异质性项
- 检查因变量是否有极端值
- 查看样本是否有问题(如缺失值)

快速诊断代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 1. 检查X的条件数(共线性诊断)
cond_number = np.linalg.cond(X.T @ X)
if cond_number > 1000:
    print("高度共线性!")
    # 标准化或删除变量

# 2. 检查初值
beta_init = np.random.normal(0, 0.1, K)
result_init = minimize(objective, beta_init)

# 用不同初值尝试多次
for i in range(5):
    beta_init_i = np.random.normal(0, 0.1*i, K)
    result_i = minimize(objective, beta_init_i)
    print(result_i.fun)  # 如果目标函数值相同,说明收敛

# 3. 逐步简化模型
# 从最简单的开始估计,逐步加入复杂性

Q3: 我的识别矩条件是什么?

答:最常见的四个矩条件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
矩条件1:一阶条件(对于MLE)
m₁(β) = ∂log L/∂β = 0

检验:
优化完成后,梯度应接近0
print(gradient(theta_est))  # 应该<1e-6

矩条件2:外生性矩(对于OLS/IV)
m₂(β) = E[X'·ε] = 0
其中ε = Y - Y_pred

检验:
residual = Y_actual - Y_predicted
moment = (X.T @ residual) / len(residual)
print(moment)  # 应该接近0

矩条件3:工具变量正交性(对于IV)
m₃(β) = E[Z'·ε] = 0

检验:
moment_iv = (Z.T @ residual) / len(residual)
print(moment_iv)  # 应该接近0

矩条件4:市场份额一致(对于BLP)
m₄(β) = s_predicted(β) - s_actual = 0

检验:
shares_pred = predict_market_shares(beta_est)
print(np.max(np.abs(shares_pred - shares_actual)))  # 应该<0.01

Q4: 如何判断我的工具变量好不好?

答:三步诊断法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
第1步:检查IV与内生变量的相关性(强度)
────────────────────────────────────
做辅助回归:内生变量 ~ IV + 其他外生变量

计算F统计量:
f_stat = (RSS_restricted - RSS_full) / (RSS_full / (n-k))

判断:
F > 10 ✓ 足够强(标准是10)
F > 5  中等
F < 5  ✗ 太弱(可能导致小样本偏差)

```python
# Python代码
from scipy import stats

# 辅助回归
X_aux = np.column_stack([Z, other_exog])
endog = market_data['price'].values

model = OLS(endog, X_aux).fit()
f_stat = model.f_statistic

print(f"F统计量: {f_stat.statistic:.2f}")
if f_stat.statistic < 10:
    print("警告:弱IV问题!")

第 2 步:检查 IV 是否外生(有效性) ──────────────────────────────── Sargan 检验:J_stat = n·m’Wm ~ χ²(L-K)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# GMM估计后
moment = (Z.T @ residual) / len(residual)
J_stat = len(residual) * moment @ W @ moment

p_value = 1 - stats.chi2.cdf(J_stat, df=L-K)

if p_value > 0.05:
    print("✓ IV很可能是外生的(Sargan检验未拒绝)")
else:
    print("✗ IV可能内生(Sargan检验拒绝)")

第 3 步:检查一阶条件(必要性) ──────────────────────────── Durbin-Wu-Hausman 检验: DWH_stat ~ χ²(内生变量数)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 比较OLS和IV估计
beta_ols = np.linalg.inv(X.T @ X) @ X.T @ y
beta_iv = ...  # IV估计

# 计算DWH统计量
var_diff = ...  # 两个估计值方差的差
DWH_stat = (beta_ols - beta_iv).T @ var_diff @ (beta_ols - beta_iv)

if DWH_stat > stats.chi2.ppf(0.95, df=1):
    print("✓ 需要用IV(OLS有偏)")
else:
    print("✗ OLS就足够(不需要IV)")

总结判断表: ┌─────────────────────┬──────────────┐ │ F>10 & p 值>0.05 │ ✓ IV 很好用 │ │ F>10 & p 值<0.05 │ ⚠ IV 有问题 │ │ F<10 & p 值>0.05 │ ⚠ IV 太弱 │ │ F<10 & p 值<0.05 │ ✗ 不该用 IV │ └─────────────────────┴──────────────┘

1
2
3
4
5
6

---

### Q5: 我应该报告什么结果?

**答:最小完整报告内容(参考检查清单):**

【必须报告】

  1. 估计的参数

    • 系数值、标准误、t 值
    • 表格形式
  2. 拟合度指标

    • Log-likelihood、AIC、BIC
    • 或 MAE/MAPE
  3. 样本信息

    • 样本大小、产品数、市场数
    • 变量描述统计
  4. 模型设定

    • 用了什么模型(MNL/Mixed Logit/BLP 等)
    • 包含了什么特征

【强烈建议报告】 5. 识别检验

  • 如果用了 IV,报告 Sargan 检验和弱 IV 诊断
  1. 敏感性分析

    • 至少展示 1 个重要参数在假设改变下的稳健性
  2. 经济学含义

    • 参数的经济学解释
    • 价格弹性、消费者剩余等衍生指标

【如果做了反事实】 8. 反事实方法描述

  • 如何模拟新场景
  • 求解均衡的方法
  1. 结果对比
    • 基准 vs 反事实的对比表格
    • 福利变化的分解

【可选但增加信誉】 10. 代码可获得性 - 提供 code repository 链接 - 便于复现

示例表格框架: ┌───────────────────┬────────┬───────┬────────┐ │ 变量 │ 系数 │ S.E. │ t-值 │ ├───────────────────┼────────┼───────┼────────┤ │ Log(Price) │-0.082* │ 0.012 │ -6.83 │ │ Fuel Efficiency │ 0.045* │ 0.008 │ 5.63 │ │ Horsepower │ 0.032* │ 0.007 │ 4.57 │ │ Size │ 0.027* │ 0.006 │ 4.50 │ ├───────────────────┼────────┼───────┼────────┤ │ Log-Likelihood │-8324 │ │ │ │ R-squared │ 0.742 │ │ │ │ Observations │ 2145 │ │ │ └───────────────────┴────────┴───────┴────────┘ 注:*** p<0.01, ** p<0.05, * p<0.1

衍生指标表: ┌──────────────────────────────────┐ │ 平均价格弹性 │ -0.85 │ 消费者剩余(平均) │ $2,340 │ 品牌 ξ 值排序: │ │ Apple: +2.34 │ │ Samsung: +1.58 │ │ Others: -1.92 │ └──────────────────────────────────┘

1
2
3
4
5
6

---

## 第八章:最后的学习建议

### 学习路线图(3-6个月快速上手)

第 1 个月:基础理论与 MNL ──────────────────── 周 1-2:理解参数空间-数据空间映射 阅读:我之前详细讲的参数空间那部分 练习:手工推导一个简单的 Logit 模型

周 3-4:学习 MNL 估计 视频:Train 的 discrete choice chapter 代码:用 statsmodels 实现 MNL 数据:自己生成模拟数据或找教学数据集

周 5:复习与小项目 项目 1:用实际数据(如汽车选择)估计 MNL 输出:参数表、拟合度、经济学解释

第 2 个月:进阶方法 ────────────── 周 1-2:随机系数 Logit 学习异质性来源 代码:实现简单的 Mixed Logit

周 3-4:BLP 框架初步 理解质量反演逻辑 学习工具变量概念 (先不深入求解,理解思路)

周 5:GMM 基础 理解矩条件 学习如何选择工具变量

第 3 个月:深入应用 ────────────── 选择 1: 如果主要用 MLE/GMM

  • 实现完整的 GMM 估计
  • 掌握标准误计算(delta method)
  • 做敏感性分析

选择 2: 如果需要用 BLP

  • 学习内循环算法(contraction mapping)
  • 实现简化版 BLP(1 个市场)
  • 理解为什么难以收敛

第 4-6 个月:论文级应用 ──────────────────

  • 应用到自己的研究问题
  • 解决实际难题(数据问题、识别、收敛)
  • 进行敏感性和反事实分析
  • 投稿并根据审稿意见改进
1
2
3
4

### 推荐资源

**必读论文(按难度):**

入门: □ Train (2009) “Discrete Choice Methods with Simulation” 最清晰的教材,适合初学者

□ McFadden (1973) “Conditional Logit Analysis of Qualitative Choice” 经典,基础但重要

进阶: □ Berry (1994) “Estimating Discrete-Choice Models of Product Differentiation” BLP 框架的基础论文

□ Berry, Levinsohn & Pakes (1995) “Automobile Prices and Product Characteristics” 应用 BLP 框架的经典案例

□ Nevo (2000) “Mergers Analysis with Random Coefficients” 展示如何在 BLP 中处理异质性

高级: □ Ackerberg, Caves & Frazer (2007) “Structural Identification of Production Functions” 更广泛的识别问题讨论

1
2

**代码资源:**

Python:

  • PyLogit: github.com/timothyf/PyLogit
  • Biogeme: biogeme.epfl.ch
  • BLP_py: 搜索 github 上的实现

R:

  • mlogit: 包含各种 logit 模型
  • bayesm: 贝叶斯离散选择

Julia:

  • 最快,但文档较少,主要用于大规模计算
1
2

**数据集(练习用):**

公开可用: -美国汽车市场数据(多篇 BLP 论文使用的数据)

  • UCI 机器学习库的 choice 数据
  • 运输运输部门的出行选择调查数据

如何找:搜索 “discrete choice dataset” 或看论文的 appendix,很多提供下载链接

1
2
3
4

---

## 总结:从小白到精通的完整路径

你现在理解了:

✓ 参数空间与数据空间如何映射 ✓ 如何通过决策树选择方法 ✓ 为什么某个参数能或不能识别 ✓ 如何进行完整的诊断检验 ✓ 如何向他人清楚地呈现结果

关键一点:结构估计没有"最好的方法",只有"最合适的方法" 根据你的:

  • 数据类型(微观/宏观、个体/市场)
  • 研究问题(要什么参数,需要反事实吗)
  • 时间和资源限制

灵活地选择。

最后的话:不要被复杂的数学吓倒。本质上,结构估计就是:

  1. 建立你认为真实发生的经济过程的数学模型
  2. 从数据中学习该模型的参数
  3. 确认参数确实被数据识别了
  4. 用参数做有趣的分析

简单如斯!

使用 Hugo 构建
主题 StackJimmy 设计