statsmodels powerdiscrepancy测试报错:样本数匹配仍触发ValueError
statsmodels powerdiscrepancy 触发 ValueError:维度一致仍报错
问题场景
调用statsmodels.stats.gof.powerdiscrepancy做拟合优度检验时,已确认观测集(真实标签Y)和模型预测结果的维度均为(140,),但仍抛出错误:
ValueError: observed and expected need to have the same number of observations, or e needs to add to 1
中文翻译:观测值与期望值需拥有相同的观测数量,或期望值总和需为1
复现代码
def discrepancy_test(Y, result): """ 针对分类问题变量计算拟合优度检验 参数 ---------- Y : np.array 真实标签数组 result : Result实例 训练好的分类模型结果 """ from statsmodels.stats.gof import powerdiscrepancy import pandas as pd print(Y.shape, result.predict().shape) dtest = powerdiscrepancy(Y, result.predict()) pd.DataFrame(dtest, columns=['variables', 'p_value']) discrepancy_test(Y, result_pr)
运行输出:
(140,) (140,) --------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[120], line 1 ----> 1 discrepancy_test(Y, result_pr) Cell In[119], line 15, in discrepancy_test(Y, result) 3 """ 4 Calculate discrepancy test for the variables of the classification problem 5 (...) 12 13 """ 14 print(Y.shape, result.predict().shape) ---> 15 dtest = powerdiscrepancy(result.predict(), Y) 16 pd.DataFrame(dtest, columns=['variables', 'p_value']) File c:\Users\user\AppData\Local\Programs\Python\Python310\lib\site-packages\statsmodels\stats\gof.py:153, in powerdiscrepancy(observed, expected, lambd, axis, ddof) 151 e = nt * e 152 else: --> 153 raise ValueError('observed and expected need to have the same ' 154 'number of observations, or e needs to add to 1') 155 k = o.shape[axis] 156 if e.shape[axis] != k: ValueError: observed and expected need to have the same number of observations, or e needs to add to 1
问题根源
这个错误的核心不是维度不匹配,而是**powerdiscrepancy对expected参数的定义和你传入的内容不匹配**:
- 该函数接受两种类型的
expected输入:- 与
observed同维度的逐样本期望值(比如每个观测对应的连续预测值); - 总和为1的概率分布(对应类别的期望占比)。
- 与
- 但分类模型的
predict()默认返回的是类别标签(如0/1、类别ID),这类值既不是逐样本的连续期望值,总和也不可能为1,因此触发校验错误。
解决办法
根据你的检验需求,选择以下两种方式之一:
方式1:传入类别计数(适合检验类别分布拟合度)
先统计真实标签和预测标签的类别出现次数,再传入函数:
def discrepancy_test(Y, result): from statsmodels.stats.gof import powerdiscrepancy import numpy as np import pandas as pd # 统计真实标签的类别计数 observed_counts = np.bincount(Y) # 统计预测标签的类别计数 predicted_counts = np.bincount(result.predict()) print(observed_counts.shape, predicted_counts.shape) dtest = powerdiscrepancy(observed_counts, predicted_counts) return pd.DataFrame(dtest, columns=['variables', 'p_value'])
方式2:传入逐样本预测概率(适合检验单样本拟合度)
如果模型支持输出概率,调用predict_proba()获取每个样本对应真实类别的预测概率,作为期望值传入:
def discrepancy_test(Y, result): from statsmodels.stats.gof import powerdiscrepancy import pandas as pd import numpy as np # 获取所有样本的类别概率矩阵 probs = result.predict_proba() # 提取每个样本对应真实类别的概率 expected_probs = probs[np.arange(len(Y)), Y] print(Y.shape, expected_probs.shape) dtest = powerdiscrepancy(Y, expected_probs) return pd.DataFrame(dtest, columns=['variables', 'p_value'])
注意:powerdiscrepancy本质是检验观测分布与期望分布的差异,输入需为计数数据或概率/连续预测值,而非原始类别标签序列。
内容的提问来源于stack exchange,提问作者Lebedev Andrey
相关产品推荐
相关产品推荐

