外观
正态性检验
基于偏度与峰度检验变量是否服从正态分布。
核心代码
py
def _fit_normality(self, df: pd.DataFrame, decimals: int, title: str) -> None:
"""
执行正态性检验,口径与 Stata sktest 保持一致。
参数:
df: 原始数据框
decimals: 小数位数
title: 表格标题
"""
valid_cols = [col for col in self.x_vars if col in df.columns]
if not valid_cols:
raise ValueError(_('没有找到可用于正态性检验的变量。'))
result_rows = []
skipped_notes = []
for col in valid_cols:
series = pd.to_numeric(df[col], errors='coerce').dropna()
sample_size = int(series.shape[0])
if sample_size == 0:
skipped_notes.append(_('%(col)s 无有效数值样本') % {'col': col})
continue
if sample_size < 8:
skipped_notes.append(_('%(col)s 有效样本量不足 8 个') % {'col': col})
continue
if series.nunique() < 2:
skipped_notes.append(_('%(col)s 没有足够变异') % {'col': col})
continue
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)
warnings.simplefilter("ignore", category=UserWarning)
skew_result = skewtest(series)
kurt_result = kurtosistest(series)
if not (
np.isfinite(skew_result.statistic)
and np.isfinite(skew_result.pvalue)
and np.isfinite(kurt_result.statistic)
and np.isfinite(kurt_result.pvalue)
):
skipped_notes.append(_('%(col)s 无法计算稳定的偏度/峰度统计量') % {'col': col})
continue
adj_chi2, prob_chi2 = self._stata_adjusted_normality_chi2(
skew_result.statistic,
kurt_result.statistic,
sample_size,
)
if not (np.isfinite(adj_chi2) and np.isfinite(prob_chi2)):
skipped_notes.append(_('%(col)s 联合检验统计量计算失败') % {'col': col})
continue
result_rows.append({
'Variable': col,
'N': sample_size,
'Pr(skewness)': float(skew_result.pvalue),
'Pr(kurtosis)': float(kurt_result.pvalue),
'Adj chi2(2)': float(adj_chi2),
'Prob>chi2': float(prob_chi2),
'结论': _('拒绝正态分布') if prob_chi2 < 0.05 else _('不能拒绝正态分布'),
})
if not result_rows:
raise ValueError(_('没有足够的数据完成正态性检验。'))
result_df = pd.DataFrame(result_rows).set_index('Variable')
title = title if title else _('正态性检验')
note = (
_('H0: 数据服从正态分布;采用与 Stata sktest 一致的偏度/峰度联合检验口径;')
+ _('当 Prob>chi2 < 0.05 时拒绝正态性。')
)
if skipped_notes:
note += _(' 未纳入变量:') + ";".join(skipped_notes) + "。"
self.custom_html = self._generate_html_table(
result_df,
title,
index_name="Variable",
decimals=decimals,
bottom_note=note,
)