Logit 与 Probit 模型对比:从 IIA 特性到 3 种交通方式选择场景的 Python 模拟

离散选择模型Logit模型Probit模型交通规划
于 2026-07-08 09:50:43 修改
·本内容遵循CC 4.0 BY-SA版权协议

Logit 与 Probit 模型对比:从 IIA 特性到 3 种交通方式选择场景的 Python 模拟

在交通规划和行为经济学领域,离散选择模型是分析个体决策行为的核心工具。当我们面对私家车、公交车、地铁等多种交通方式时,如何量化不同因素对选择概率的影响?Logit 和 Probit 作为两种经典的非集计模型,提供了不同的解决方案。本文将通过完整的 Python 实现,带你深入理解它们的数学本质、适用场景和实操差异。

1. 模型原理与数学对比

离散选择模型的核心是随机效用理论——假设个体总是选择效用最大的方案。效用由可观测的固定项和不可观测的随机项组成:

TEXT
U_i = V_i + ε_i

其中,Logit 和 Probit 的根本区别在于对随机项 ε 的分布假设:

特性 Logit 模型 Probit 模型
随机项分布 独立同分布的 Gumbel 分布 多元正态分布 (MVN)
协方差处理 假设各选项完全独立 允许指定任意协方差结构
IIA 特性 存在(选择比与第三方无关) 不存在(考虑选项相关性)
计算复杂度 闭式解,计算简单 需要数值积分,计算复杂
适用场景 选项间差异明显 选项存在重叠或相似特征

**IIA(无关选项独立性)**是 Logit 的典型限制。例如当新增的共享单车与现有公交车高度相关时,Logit 会高估新选项的市场份额。Probit 通过协方差矩阵能更准确地反映这种替代关系。

数学推导:Logit 的选择概率公式为 P_i = exp(V_i)/Σexp(V_j),而 Probit 需要计算多元正态分布的累积密度函数,通常用蒙特卡洛模拟求解。

2. Python 模拟环境搭建

我们使用 statsmodelsbiogeme 库实现模型,模拟包含 1000 个虚拟出行者的数据集:

PYTHON
import numpy as np
import pandas as pd
from statsmodels.discrete.discrete_model import Logit, Probit
 
# 生成模拟数据
np.random.seed(42)
n = 1000 # 样本量
data = pd.DataFrame({
'income': np.random.lognormal(mean=10, sigma=0.3, size=n),
'distance': np.abs(np.random.normal(loc=15, scale=5, size=n)),
'car_time': np.abs(np.random.normal(loc=30, scale=8, size=n)),
'bus_time': np.abs(np.random.normal(loc=45, scale=10, size=n)),
'metro_time': np.abs(np.random.normal(loc=35, scale=7, size=n))
})
 
# 计算广义成本(时间价值按 0.3元/分钟 + 固定费用)
data['car_cost'] = 0.3*data['car_time'] + 15
data['bus_cost'] = 0.3*data['bus_time'] + 5
data['metro_cost'] = 0.3*data['metro_time'] + 8
 
# 生成真实选择(基于效用最大化)
utils = {
'car': -0.1*data['car_time'] - 0.05*data['car_cost'] + 0.002*data['income'],
'bus': -0.15*data['bus_time'] - 0.1*data['bus_cost'],
'metro': -0.12*data['metro_time'] - 0.08*data['metro_cost'] + 0.001*data['income']
}
data['choice'] = pd.DataFrame(utils).idxmax(axis=1)

3. 模型实现与结果对比

3.1 Logit 模型实现

采用多项 Logit 模型(MNL)进行估计:

PYTHON
# 数据预处理
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
data['choice_code'] = le.fit_transform(data['choice'])
 
# 构建特征矩阵
X = data[['car_time', 'bus_time', 'metro_time',
'car_cost', 'bus_cost', 'metro_cost', 'income']]
y = data['choice_code']
 
# 训练Logit模型
logit_model = Logit(y, X)
logit_result = logit_model.fit()
print(logit_result.summary())

关键参数估计结果示例:

TEXT
coef std err z P>|z|
car_time -0.0987 0.012 -8.324 0.000
bus_time -0.1521 0.011 -14.217 0.000
metro_time -0.1215 0.010 -12.453 0.000
income 0.0018 0.000 4.112 0.000

3.2 Probit 模型实现

使用 biogeme 库处理更复杂的协方差结构:

PYTHON
import biogeme.database as db
import biogeme.biogeme as bio
from biogeme.models import probit
 
# 准备biogeme数据库
database = db.Database("transport", data)
 
# 定义效用函数
ASC_CAR = Beta('ASC_CAR', 0, None, None, 0)
ASC_BUS = Beta('ASC_BUS', 0, None, None, 0)
B_TIME = Beta('B_TIME', 0, None, None, 0)
B_COST = Beta('B_COST', 0, None, None, 0)
 
V1 = ASC_CAR + B_TIME * car_time + B_COST * car_cost
V2 = ASC_BUS + B_TIME * bus_time + B_COST * bus_cost
V3 = B_TIME * metro_time + B_COST * metro_cost
 
# 关联误差项(设置公交与地铁的协方差为0.6)
chol = CholeskyParam('chol', [0.5, 0, 0.6, 0, 0, 1], 3)
 
# 构建Probit模型
prob = probit([V1, V2, V3], chol, 0, 'choice', ['car', 'bus', 'metro'])
biogeme = bio.BIOGEME(database, prob)
results = biogeme.estimate()

3.3 结果可视化对比

通过市场占有率预测展示模型差异:

PYTHON
import matplotlib.pyplot as plt
 
# 预测选择概率
logit_probs = logit_result.predict()
probit_probs = get_probit_probs() # 从biogeme结果提取
 
# 绘制对比图
fig, ax = plt.subplots(figsize=(10,6))
width = 0.35
x = np.arange(3)
ax.bar(x - width/2, logit_probs.mean(axis=0), width, label='Logit')
ax.bar(x + width/2, probit_probs.mean(axis=0), width, label='Probit')
ax.set_xticks(x)
ax.set_xticklabels(['Car', 'Bus', 'Metro'])
ax.set_ylabel('Choice Probability')
ax.legend()
plt.show()

当引入与公交车高度相似的新交通方式(如电动巴士)时,两种模型的预测差异会更加明显:

  • Logit 会均分原有公交车的份额给新旧选项
  • Probit 能保持公交类别的整体份额,仅微调内部比例

4. 模型选择决策框架

根据数据特征选择模型的实用指南:

TEXT
┌───────────────────────┐
│ 开始模型选择 │
└──────────┬────────────┘
┌───────────────────────┐
│ 检查选项相关性 │
│ - 是否有相似替代品? │
│ - 路径重叠程度? │
└──────────┬────────────┘
┌─────┐ ┌─────┐
│ 高 │ │ 低 │
└─────┘ └─────┘
↓ ↓
┌───────┐ ┌───────┐
│Probit │ │ Logit │
└───────┘ └───────┘

实际项目中的折中方案:

  1. 嵌套 Logit:将相关选项归入同一层级

    PYTHON
    # 使用biogeme实现嵌套Logit
    nest_car = OneNestedForOneAlternative('car', 1, 'lambda_car')
    nest_pt = OneNestedForSeveralAlternatives('pt', ['bus','metro'], 'lambda_pt')
  2. 混合 Logit:允许参数随机变化

    PYTHON
    # 随机参数设置示例
    B_TIME_RND = Beta('B_TIME_RND', 0, None, None, 1)
    B_TIME = B_TIME_RND * Normal(0, 0.1)
  3. 模型组合:用 Logit 快速原型,Probit 做最终验证

在交通规划项目中,我们通常会先用 Logit 进行快速分析,当发现选项间存在明显相关性(如公交与地铁的换乘关系)时,再切换到 Probit 或嵌套模型。记得始终用 Hold-out 测试集验证模型的预测准确性。