外观
White 异方差检验
White 异方差检验(含平方项与交叉项)。
核心代码
py
@staticmethod
def white_test(
df: pd.DataFrame,
y_var: str,
x_vars: List[str],
decimals: int = 4
) -> Dict[str, Any]:
"""
White检验:检验异方差性(包含交叉项和平方项)
参数:
df: 数据框
y_var: 因变量名
x_vars: 自变量列表
decimals: 小数位数
返回:
包含检验结果的字典
"""
# 准备数据
cols = [y_var] + x_vars
df_clean = df[cols].dropna()
# 1. 估计OLS模型
formula = build_patsy_formula(y_var, x_vars)
model = smf.ols(formula, data=df_clean)
result = model.fit()
# 2. 获取残差
residuals = result.resid
# 3. 计算残差平方
resid_squared = residuals ** 2
# 4. 构造辅助回归的自变量(包含原变量、平方项和交叉项)
df_aux = df_clean[x_vars].copy()
# 添加平方项
for var in x_vars:
df_aux[f'{var}_sq'] = df_clean[var] ** 2
# 添加交叉项
for i, var1 in enumerate(x_vars):
for var2 in x_vars[i+1:]:
df_aux[f'{var1}_{var2}'] = df_clean[var1] * df_clean[var2]
# 5. 用残差平方对扩展的自变量回归
df_aux['resid_sq'] = resid_squared
aux_vars = [col for col in df_aux.columns if col != 'resid_sq']
# 检查样本量是否足够
if len(df_clean) < len(aux_vars) + 2:
# 如果样本量不足,只使用原变量和平方项(不包含交叉项)
df_aux_simple = df_clean[x_vars].copy()
for var in x_vars:
df_aux_simple[f'{var}_sq'] = df_clean[var] ** 2
df_aux_simple['resid_sq'] = resid_squared
aux_vars = [col for col in df_aux_simple.columns if col != 'resid_sq']
aux_formula = build_patsy_formula('resid_sq', aux_vars)
aux_model = smf.ols(aux_formula, data=df_aux_simple)
else:
aux_formula = build_patsy_formula('resid_sq', aux_vars)
aux_model = smf.ols(aux_formula, data=df_aux)
aux_result = aux_model.fit()
# 6. 计算LM统计量 = n * R²
n = len(df_clean)
r_squared = aux_result.rsquared
lm_stat = n * r_squared
# 7. 自由度 = 辅助回归中的自变量个数
df_test = len(aux_vars)
# 8. 计算p值(卡方分布)
p_value = 1 - chi2.cdf(lm_stat, df_test)
# 9. 判断结果
if p_value < 0.01:
conclusion = _('强烈拒绝原假设,存在显著异方差')
stars = "***"
elif p_value < 0.05:
conclusion = _('拒绝原假设,存在异方差')
stars = "**"
elif p_value < 0.1:
conclusion = _('弱拒绝原假设,可能存在异方差')
stars = "*"
else:
conclusion = _('不能拒绝原假设,不存在显著异方差')
stars = ""
return {
'test_name': 'White Test for Heteroskedasticity',
'null_hypothesis': _('误差项具有同方差性(不存在异方差)'),
'alternative_hypothesis': _('误差项具有异方差性'),
'lm_statistic': round(lm_stat, decimals),
'chi2_statistic': round(lm_stat, decimals),
'df': df_test,
'p_value': round(p_value, decimals),
'significance': stars,
'conclusion': conclusion,
'n_obs': n,
'aux_r_squared': round(r_squared, decimals),
'n_aux_vars': df_test
}