获取分类数据AIC/BIC值时遇ValueError:endog为多列数组
二元分类变量拟合OLS模型触发ValueError的解决方法
问题场景
我有一个700行×2列的DataFrame,两列均为取值为Yes/No的category类型数据。尝试用statsmodels的ols公式C(Private) ~ C(Elite)拟合模型以获取AIC/BIC值时,报错:
ValueError: endog has evaluated to an array with multiple columns that has shape (700, 2)
即使将Yes/No替换为1/0并转为数值类型,仍出现相同错误。
可复现示例代码
import pandas as pd df = pd.DataFrame(columns=['Private','Elite']) df[''] = ['Abilene Christian University', 'Center for Creative Studies', 'Florida Institute of Technology', 'LaGrange College', 'Muhlenberg College', 'Saint Mary-of-the-Woods College', 'Union College KY'] df = df.set_index('') df['Private'] = 'Yes' df['Elite'] = 'No' for x in df.columns: df[x] = df[x].astype('category') df_train = df.copy(deep=True)
报错的拟合代码
from statsmodels.formula.api import ols fit = ols('C(Private) ~ C(Elite)', data=df_train).fit() fit.summary()
数值转换后仍报错的代码
from statsmodels.formula.api import ols df_train = df_train.replace('Yes', int(1)) df_train = df_train.replace('No', int(0)) for x in df_train.columns: df_train[x] = pd.to_numeric(df_train[x]) fit = ols('C(Private) ~ C(Elite)', data=df_train).fit() fit.summary()
错误原因
核心问题在于:对二元分类变量使用C()函数时,statsmodels会默认生成虚拟变量矩阵(多列),而OLS模型的因变量(endog)要求是单列数据,不能是多列矩阵。比如C(Private)会把Yes/No分类转为两列(如Private_Yes和Private_No),导致因变量形状变为(700,2),触发报错。
解决方法
方法1:直接使用数值列作为因变量(无需C()包裹)
如果已经将分类值转为1/0的数值类型,直接用列名作为因变量即可,不需要用C()包裹:
from statsmodels.formula.api import ols # 简化数值转换 df_train = df_train.replace({'Yes': 1, 'No': 0}) df_train = df_train.apply(pd.to_numeric) # 直接使用列名作为因变量 fit = ols('Private ~ C(Elite)', data=df_train).fit() print(fit.summary()) print(f"AIC: {fit.aic}, BIC: {fit.bic}")
方法2:为分类因变量指定参考类别
如果要保留category类型,可以在C()中通过reference参数指定参考类别,让statsmodels只生成单一对比列,确保因变量为单列:
from statsmodels.formula.api import ols # 指定参考类别,避免生成多列 fit = ols('C(Private, reference="No") ~ C(Elite)', data=df_train).fit() print(fit.summary()) print(f"AIC: {fit.aic}, BIC: {fit.bic}")
更优模型选择:逻辑回归
对于二元因变量的场景,OLS模型的假设(因变量连续)并不适配,更推荐使用Logit逻辑回归模型,该模型专为二元分类任务设计,同样能输出AIC/BIC值:
from statsmodels.formula.api import logit # 拟合Logit模型(需确保因变量为0/1数值) df_train = df_train.replace({'Yes':1, 'No':0}) df_train = df_train.apply(pd.to_numeric) fit_logit = logit('Private ~ C(Elite)', data=df_train).fit() print(fit_logit.summary()) print(f"AIC: {fit_logit.aic}, BIC: {fit_logit.bic}")
内容的提问来源于stack exchange,提问作者guin0x
相关产品推荐
相关产品推荐

