- 数据分析
- 数据科学
- 科研
【免费下载链接】statsmodels
Statsmodels: statistical modeling and econometrics in Python
本指南系统讲解 statsmodels 中基于广义矩估计(Generalized Method of Moments,GMM)的模型类与函数实现,其核心源码位于 statsmodels/sandbox/regression/gmm.py,对应官方文档 docs/source/gmm.rst。当前实现覆盖通用的非线性矩条件情形,并内置了标准的线性工具变量(IV)模型作为测试用例。读完本文,你将掌握如何通过子类化GMM定义自己的矩条件、配置 one-step / 迭代 / CUE 三种估计策略、选择合适的权重矩阵与优化器,以及如何使用LinearIVGMM/NonlinearIVGMM完成工具变量回归与过度识别检验。
一、模块定位:statsmodels 中的 GMM 实现
根据 gmm.rst 的说明,statsmodels.gmm(实际代码位于statsmodels.sandbox.regression.gmm)包含基于 GMM 估计的模型类和函数。模块的定位要点如下:
- 当前已实现通用非线性情形:
GMM接受任意非线性矩条件(moment conditions)进行估计; - 线性工具变量模型作为测试用例:模块内置了标准线性 IV 模型的示例类
IV2SLS。文档明确指出,该类的引入主要是作为测试用例,虽然运行正确,但并未利用线性结构;线性情形未来将引入专门的实现,以获得更快、数值上更精确的结果; - 估计方式灵活:既可以针对给定的权重矩阵(weighting matrix)一次性估计,也可以通过迭代方式,在“估计最优权重矩阵”与“估计参数”之间交替进行,直至收敛;
- 扩展机制明确:实现具有不同矩条件的模型,只需子类化
GMM并定义矩条件方法momcond——这是最小化的实现要求。
模块的:synopsis:将其概括为"A framework for implementing Generalized Method of Moments (GMM)",即一个用于实现广义矩估计的框架,而非单一模型。
二、类层次与模块架构
从源码结构看(statsmodels/sandbox/regression/gmm.py),该模块由三组类构成:工具变量 2SLS 类、通用 GMM 框架类、以及 IV-GMM 特化类。其层次关系可以概括如下:
| 类 | 父类 | 定位 | 源码位置 |
|---|---|---|---|
IV2SLS | LikelihoodModel | 两阶段最小二乘 IV 估计 | gmm.py#L76 |
IVRegressionResults | RegressionResults | IV2SLS 的结果类,含 Hausman 设定检验 | gmm.py#L189 |
GMM | Model | 通用 GMM 框架基类,需子类化定义momcond | gmm.py#L442 |
GMMResults | LikelihoodModelResults | 通用 GMM 结果类,提供 J 检验等 | gmm.py#L1185 |
IVGMM | GMM | 工具变量 GMM 基类,矩条件为z * u | gmm.py#L1429 |
LinearIVGMM | IVGMM | 线性 IV 模型的闭式解 GMM | gmm.py#L1476 |
NonlinearIVGMM | IVGMM | 非线性 IV 模型 GMM,需提供func | gmm.py#L1580 |
IVGMMResults | GMMResults | IVGMM 结果类,补充 fittedvalues / resid / ssr | gmm.py#L1677 |
DistQuantilesGMM | GMM | 基于分位数匹配估计分布参数的示例 | gmm.py#L1749 |
此外,模块还提供了独立的函数spec_hausman(gmm.py#L1698)用于 Hausman 设定检验。结果类通过文件末尾的results_class_dict字典(gmm.py#L1888)完成模型类到结果类的映射。
三、先用 IV2SLS 上手:两阶段最小二乘
IV2SLS是该模块中最容易上手的类,用于工具变量(Instrumental Variables)的两阶段最小二乘估计。其构造函数签名与参数含义如下(gmm.py#L102):
IV2SLS(endog, exog, instrument=None)endog:内生被解释变量,一维或二维数组(nobs × 1);exog:解释变量,一维或二维数组(nobs × k);instrument:工具变量数组,必须同时包含"未工具化的外生解释变量"和"工具变量"本身。
这里有一个关键的约定需要特别注意:根据类文档(gmm.py#L91-L99),计算中exog里的所有变量都被视为被工具化;如果exog中的某些变量不应被工具化,那么这些变量同样必须被包含在instrument数组中。另外,标准误差计算使用df_resid = nobs - k_vars,这与 Stata 中ivreg2的small选项相对应。
调用fit()(gmm.py#L119)即可完成估计,其内部按照 Greene《计量经济分析》第 5 版第 78 页第 5.4 节的教科书公式计算:
import statsmodels.sandbox.regression.gmm as gmm # endog: 被解释变量, exog: 解释变量, instrument: 工具变量(含未工具化的外生变量) mod = gmm.IV2SLS(endog, exog, instrument) res = mod.fit() print(res.summary())fit()返回一个RegressionResultsWrapper包装的IVRegressionResults实例。参数估计与协方差是准确的,但结果中的其他统计量是否无需修改即可适用,尚未经过完整测试(源码注释对此有明确提醒,见 gmm.py#L128-L134)。
IVRegressionResults在RegressionResults基础上提供了两个特殊方法:
spec_hausman(dof=None)(gmm.py#L220):Hausman 设定检验。它将 IV 估计与 OLS 估计的参数差和协方差差构造为统计量H,并按chi2分布计算 p 值,自由度为cov_diff的秩(当dof未指定时)。测试逻辑可对照独立函数 spec_hausman;summary(...):输出包含 Omnibus、Skew、Kurtosis、Durbin-Watson、Jarque-Bera、条件数等诊断信息的摘要表(gmm.py#L252)。
四、GMM 核心类:子类化与矩条件定义
GMM类是整个框架的核心(gmm.py#L442),它必须被继承使用,子类需要定义矩条件方法momcond。这是"最小化实现"的唯一硬性要求。
构造函数(gmm.py#L497)签名:
GMM(endog, exog, instrument, k_moms=None, k_params=None, missing="none", **kwds)参数含义:
| 参数 | 说明 |
|---|---|
endog | 内生被解释变量数组 |
exog | 外生解释变量数组 |
instrument | 工具变量数组 |
k_moms | 矩条件个数;为None时自动取instrument的列数,主要用于确定起始参数与起始权重矩阵的形状 |
k_params | 参数个数;为None时自动取exog的列数 |
**kwds | 任意附加变量,供矩条件计算使用,会以属性形式存储到实例上 |
源码中的一个重要设计是:GMM 类本身并不直接使用数据,endog、exog、instrument与kwds只是被存储起来供矩条件访问(gmm.py#L475-L481)。哪些数据是必需的、如何使用,完全取决于子类矩条件的定义。
一个自定义子类的最小骨架如下:
import numpy as np import statsmodels.sandbox.regression.gmm as gmm class MyGMM(gmm.GMM): def momcond(self, params): # 返回 (nobs, nmoms) 形状的矩条件数组 # 例如矩条件 E[z * (y - f(x, params))] = 0 return instrument * (self.endog - self.predict(params))[:, None] def fitstart(self): # 提供数值优化的起始值 return np.zeros(self.exog.shape[1]) mod = MyGMM(endog, exog, instrument) res = mod.fit(maxiter=10)其中momcond(params)返回每个观测对应的矩条件矩阵(形状nobs × nmoms),fit内部会通过momcond_mean(gmm.py#L1121)求均值后构造目标函数。
五、fit() 参数详解:从 one-step、迭代到 CUE
fit()是估计的入口(gmm.py#L582),其完整签名:
fit(start_params=None, maxiter=10, inv_weights=None, weights_method="cov", wargs=(), has_optimal_weights=True, optim_method="bfgs", optim_args=None)5.1maxiter:估计策略的选择
maxiter直接决定采用哪一种 GMM 估计方式,源码在 gmm.py#L690-L722 中分支处理:
maxiter取值 | 估计方式 | 说明 |
|---|---|---|
0或1 | one-step(一步估计) | 使用给定的或默认的起始权重矩阵,只做一次加权矩最小化。源码注释提醒:一步估计仍与 Stata 的gmm存在差异,默认使用异方差稳健协方差,但假设权重矩阵是最优的 |
2、10等正整数 | iterated GMM(迭代估计) | 在"估计参数 → 用参数重估最优权重矩阵 → 再估计参数"之间循环,最大迭代次数为maxiter,同时满足收敛条件可提前停止 |
"cue" | CUE(连续更新 GMM) | 在最小化 GMM 目标函数的过程中同步更新权重矩阵,起始值取自 one-step 参数(对应fitgmm_cu,见 gmm.py#L809) |
迭代流程由fititer(gmm.py#L909)实现,其收敛判据是:当迭代次数大于 2 且参数变化的绝对最大值maxabs(resgmm - start) < self.epsilon_iter时提前终止,默认epsilon_iter = 1e-6(可在实例上修改)。
5.2inv_weights:起始权重矩阵
inv_weights是起始权重矩阵的逆。若未提供,则调用子类的start_weights方法:
- 通用
GMM默认返回单位矩阵np.eye(nmoms)(gmm.py#L853); IVGMM子类返回z'z / nobs(其逆为pinv(z'z / nobs),见 gmm.py#L1450)。
5.3weights_method与wargs:权重矩阵估计方法
weights_method定义了用于构造(最优)权重矩阵的方法,其可用选项在类文档(gmm.py#L400-L411)与calc_weightmatrix(gmm.py#L997)中有详细说明:
| 方法 | 含义 | 备注 |
|---|---|---|
cov | 矩条件的简单协方差(HC0) | 默认;可通过ddof做自由度校正 |
hac | 异方差自相关一致估计(Newey-West 类) | 需在wargs中指定maxlag;默认使用 Bartlett 核(weights_bartlett),可通过kernel传入自定义核函数 |
iid | 独立同分布假设(仅Z*u情形) | 未充分测试,仅适用于工具变量情形,误差与工具独立;需传入params以重算误差项 |
flatkernel | 均匀截断窗口 | 试验版本,要求maxlag |
ac | 自相关一致估计 | 尚不可用 |
cluster | 聚类稳健 | 尚未接入 |
wargs是传递给权重矩阵方法的参数(gmm.py#L415-L424):
centered:bool,是否对矩条件做中心化(去均值)后计算权重与协方差,适用于所有方法,默认 True(见 gmm.py#L1044-L1049);ddof:int,自由度校正,当前仅适用于cov,取"k_params"时按nobs - k_params校正(gmm.py#L1059-L1067);maxlag:int,HAC 计算包含的滞后阶数,仅适用于hac/flatkernel。
5.4has_optimal_weights:协方差矩阵计算假设
has_optimal_weights=True(默认)时,参数协方差矩阵按最优 GMM(权重矩阵W = S⁻¹)的公式计算:cov = (G'Ω⁻¹G)⁻¹ / nobs;否则采用 sandwich 形式(G'WG)⁻¹(G'WΩWG)(G'WG)⁻¹ / nobs(实现见 calc_cov_params)。对于 one-step 估计,协方差计算仍假定权重矩阵最优,这正是源码在注释中提醒的已知问题之一(gmm.py#L662-L666)。
5.5optim_method与optim_args:数值优化配置
optim_method指定参数最小化所用的 scipy 优化器(fitgmm 中的映射):
| 取值 | scipy 优化器 | 是否使用解析梯度 |
|---|---|---|
bfgs(默认) | scipy.optimize.fmin_bfgs | 是(score) |
nm | scipy.optimize.fmin(Nelder-Mead) | 否 |
ncg | scipy.optimize.fmin_ncg | 是 |
cg | scipy.optimize.fmin_cg | 是 |
fmin_l_bfgs_b | scipy.optimize.fmin_l_bfgs_b | 是 |
powell | scipy.optimize.fmin_powell | 否 |
slsqp | scipy.optimize.fmin_slsqp | 否 |
梯度由数值差分实现:score(gmm.py#L1163)通过approx_fprime对目标函数求导。optim_args为优化器关键字参数,默认会注入disp=1(gmm.py#L687-L688);在测试中常见用法是{"gtol": 1e-6, "disp": 0}以抑制输出并收紧收敛容差。
六、GMM 目标函数与得分
理解了估计流程后,其数学内核值得单独说明。GMM 的目标函数为二次型(gmmobjective):
J(θ) = m̄(θ)' · W · m̄(θ)其中m̄(θ)是矩条件在参数 θ 处的样本均值(momcond_mean,gmm.py#L1121),W是当前权重矩阵。CUE 版本gmmobjective_cu(gmm.py#L879)则在每次目标函数求值内部重新调用calc_weightmatrix计算权重矩阵并取伪逆pinv,从而实现权重随参数连续更新,这是 CUE 与普通迭代 GMM 的本质区别。
七、结果对象 GMMResults:推断与检验
GMMResults(gmm.py#L1185)是fit()的返回类型,提供以下核心成员:
q:目标函数在参数估计处的值(gmmobjective(params, weights)),缓存属性;jval:q * nobs_moms,即 J 统计量的原始值(gmm.py#L1207)。注意源码注释提醒:jtest的归一化(是否乘以或除以 nobs)作者本人也不完全确定,缩放不影响估计,但影响检验量大小(gmm.py#L34-L38);jtest()(gmm.py#L1315):过度识别检验(Hansen J 检验)。返回(jstat, pvalue, df),其中df = nmoms - nparams,p 值基于卡方分布stats.chi2.sf(jstat, df);compare_j(other)(gmm.py#L1327):比较两个嵌套 GMM 估计的过度识别检验(用于检验某个矩条件被移除的情形)。该方法"未经过测试",且由于两个模型使用不同权重矩阵,差值不保证为正,使用时需谨慎;cov_params(**kwds)/bse/get_bse():参数协方差与标准误,支持通过关键字覆盖weights_method、wargs、has_optimal_weights重算;summary(...):输出摘要表,右上角显示Hansen J统计量及其 p 值(gmm.py#L1383-L1405)。
IVGMMResults(gmm.py#L1677)在GMMResults基础上补充了fittedvalues、resid与ssr(残差平方和),前提是模型具有加性误差结构y - f(x, params)。
八、工具变量 GMM 家族:IVGMM、LinearIVGMM 与 NonlinearIVGMM
8.1 IVGMM:工具变量 GMM 基类
IVGMM(gmm.py#L1429)为工具变量 GMM 提供默认实现,其核心矩条件为(momcond):
E[ z · (y - f(x, β)) ] = 0即"误差 × 工具变量"。默认的predict为线性形式x·β,start_weights返回z'z / nobs,fitstart返回零向量。文档同时说明,该类的方法应由子类覆盖——目前实现了LinearIVGMM与NonlinearIVGMM两个子类。
8.2 LinearIVGMM:线性闭式解
LinearIVGMM(gmm.py#L1476)针对线性工具变量模型E[z·(y - xβ)] = 0,用闭式表达式替代数值优化器,在每个迭代步中直接求解:
params = pinv(x'z W z'x) · (x'z W z'y) # 见 fitgmm 实现因此它的fitgmm会忽略start与optim_method参数(仅保留签名一致性),显著提高速度与数值精度。此外它重写了gradient_momcond为解析形式-z'x / nobs(gmm.py#L1558),score也使用解析表达式。
需要注意的命名约定:这里的exog指解释变量(right-hand side variables),既包含外生变量,也包含被工具化的内生解释变量;而instrument指工具变量,需同时包含"已含的外生变量"与"排他外生变量"(gmm.py#L1490-L1504)。
8.3 NonlinearIVGMM:非线性条件均值
NonlinearIVGMM(gmm.py#L1580)面向非线性条件均值函数f(X, β),矩条件为E[z·(y - f(X, β))] = 0。构造时需要额外传入可调用对象func,调用约定为func(params, exog):
def func(params, exog): return np.exp(exog @ params) # 例如指数均值函数 mod = gmm.NonlinearIVGMM(endog, exog, instrument, func) res = mod.fit(maxiter=2)该类的导数默认通过数值差分获得(jac_func/jac_error,gmm.py#L1642-L1657);如果条件均值函数的 Jacobian 已知,可以通过子类化并定义jac_func方法来提供解析导数。
九、测试验证:与 Stata ivreg2 结果对标
该模块的可靠性通过一组与 Stata 对照的测试用例得到验证,是理解正确用法的绝佳范本。
9.1 Griliches76 数据集测试(test_gmm.py)
test_gmm.py 使用经典的 Griliches 1976 数据集(griliches76.dta),构建了"受教育年限内生"的工资方程工具变量模型,并与 Stataivreg2的输出结果(存储于 results_ivreg2_griliches.py)逐项比对。测试矩阵覆盖:
- 不同估计策略:
TestGMMStOnestep(maxiter=0)、TestGMMStOneiter(maxiter=1)、TestGMMStTwostep(maxiter=2)、TestGMMSt1(maxiter=10,迭代至收敛),对应 results_gmm_griliches.py 与 results_gmm_griliches_iter.py 中保存的参考结果; - 权重矩阵差异:
TestGMMStTwostepNO/TestGMMStOnestepNO等后缀NO的类,对应不同的has_optimal_weights设定; - 与 OLS 一致性:
TestGMMOLS(test_gmm.py#L326)将exog同时作为工具变量(IVGMM(endog, exog, exog),maxiter=0),此时 GMM 估计应还原出 OLS 结果,参数与 HC0 标准误在5e-4相对容差内一致; - 线性与非线性:
setup_class中分别构造LinearIVGMM(test_gmm.py#L714)与NonlinearIVGMM(test_gmm.py#L766)参与同一基准的比对。
测试还展示了标准的调用方式:先用OLS拟合获取起始值,再以w0inv = instrument.T @ instrument / nobs作为初始权重矩阵调用fit(start, maxiter=..., inv_weights=w0inv, optim_method="bfgs", optim_args={"gtol": 1e-6, "disp": 0})(见 test_gmm.py#L303-L317)。
9.2 非线性 Poisson 测试(test_gmm_poisson.py)
test_gmm_poisson.py 进一步验证非线性矩条件:使用NonlinearIVGMM配合指数加性(moment_exponential_add)与指数乘性(moment_exponential_mult)两类均值函数估计计数模型,比较 one-step(maxiter=0)与两步(maxiter=2)估计,参考结果保存在 results_gmm_poisson.py。测试类名(如TestGMMAddOnestep、TestGMMMultTwostepDefault、TestGMMMultTwostepCenter)也验证了wargs={"centered": ...}等参数组合对结果的影响。
十、进阶示例:DistQuantilesGMM 分位数匹配
DistQuantilesGMM(gmm.py#L1749)是另一个演示子类化用法的示例:通过匹配理论分位数与经验分位数来估计分布参数。其矩条件定义为理论 CDF 与目标分位数的差:
momcond = distfn.cdf(xquant, *params) - pquant默认分位点为[0.01, 0.05, 0.1, 0.4, 0.6, 0.9, 0.95, 0.99],每个分位点对应一个矩条件。该类还演示了fitonce方法(gmm.py#L1835):当最优权重矩阵无法数值计算时(例如矩条件只有一行、无法构造逐观测协方差),使用给定权重矩阵或单位矩阵做单次估计的便捷途径,has_optimal_weights默认取False。
十一、已知问题与使用注意事项
源码头部注释(gmm.py#L5-L41)与类文档中记录了一系列已知限制,使用前应有所了解:
- one-step 估计(
maxiter=0/1)与 Stata 存在差异:默认使用异方差稳健协方差,但假设权重矩阵最优(gmm.py#L662-L666); - 权重矩阵无法数值计算的情形:如
DistQuantilesGMM只有一行矩条件时协方差计算会失效,iter=1可退化为单位权重矩阵,fitonce正是为此设计(gmm.py#L10-L19); jtest的归一化:作者对jval是否应乘以/除以nobs存疑,缩放不影响参数估计,但影响检验统计量的绝对大小(gmm.py#L34-L38);- Hausman 检验自由度:基于协方差差矩阵的秩,且该差矩阵常常是半正定/奇异矩阵,负特征值现象在 IV 示例中已被观察到(gmm.py#L30-L33);
fitonce情形下的 bse 偏大:无最优权重矩阵时的calc_cov_params公式被认为有误,因为没有对应的omega估计(gmm.py#L38-L41);- CUE 与
compare_j标注为未充分测试;iid、ac、cluster等权重方法尚未完整实现或接入(gmm.py#L395); - 各方法的选项参数"尚未完全实现,多个方法中仍有缺失"(gmm.py#L483-L486),例如
wargs中拼写错误的键不会被检测。
结语
statsmodels 的 GMM 模块(statsmodels/sandbox/regression/gmm.py)提供了一个结构清晰、扩展性强的广义矩估计框架:向上,GMM基类把"定义矩条件"与"数值估计"彻底解耦,用户只需实现momcond即可接入 one-step、迭代与 CUE 三种估计流程;向下,IV2SLS、LinearIVGMM、NonlinearIVGMM覆盖了从教科书两阶段最小二乘到非线性工具变量模型的常见计量场景,并经 Griliches 数据与 Stataivreg2结果的测试对标验证。对于需要处理内生性、或需要自定义矩条件做结构性估计的 Python 计量任务,这是一个值得熟悉的高价值工具。需要特别留意的是,该模块目前位于statsmodels.sandbox(沙盒)命名空间下,部分功能(如 CUE、HAC 权重、compare_j)仍标注为未充分测试,生产使用前建议对照 test_gmm.py 中的用法与已知问题逐项评估。
- 数据分析
- 数据科学
- 科研
【免费下载链接】statsmodels
Statsmodels: statistical modeling and econometrics in Python
相关推荐
Statsmodels广义矩估计工具变量:过度识别检验与权重选择
Statsmodels广义矩估计工具变量:过度识别检验与权重选择 你是否在处理经济数据时遇到过变量内生性问题?是否为工具变量选择和模型有效性检验而困扰?本文将通
数据分析数据科学科研告别矩形限制:LabelImg自定义形状工具完全指南
告别矩形限制:LabelImg自定义形状工具完全指南 你是否还在为标注不规则物体烦恼?使用矩形框标注圆形物体时是否觉得不够精确?本文将带你掌握LabelImg的
数据标注计算机视觉人工智能5分钟掌握raylib游戏开发:零依赖跨平台游戏编程终极指南
5分钟掌握raylib游戏开发:零依赖跨平台游戏编程终极指南 你是否曾经梦想过创建自己的游戏,却被复杂的图形库和繁琐的配置吓退?raylib游戏开发库就是为像你
数据分析数据科学科研
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考