自定义带p值的Logistic Regression报错LinAlgError:奇异矩阵
解决自定义Logistic回归模型中的奇异矩阵错误
嘿,这个问题我之前也碰到过!咱们一步步来拆解原因并解决它:
问题根源
你遇到的LinAlgError: Singular matrix是因为计算Fisher信息矩阵的逆时,矩阵不可逆。而原生sklearn.linear_model.LogisticRegression默认启用了L2正则化(penalty='l2'),正则化会给矩阵添加一个小的对角项,避免矩阵奇异;但你的自定义模型直接计算原始Fisher矩阵,没有处理共线性问题,所以触发了错误。
常见导致矩阵奇异的原因:
- 哑变量陷阱:对有n个类别的特征生成了n个哑变量(比如性别变量生成「男」「女」两个哑变量),这两个特征完全线性相关,会导致共线性。
- 零方差特征:某个特征的所有样本值完全相同(比如所有样本的某个特征都是0),这类特征对模型无贡献还会破坏矩阵可逆性。
- 高度相关特征:两个或多个特征的相关系数接近1,导致共线性。
解决方案
1. 先排查并修复数据层面的共线性问题
- 处理哑变量陷阱:生成哑变量时使用
drop_first=True(比如pd.get_dummies(data, drop_first=True)),去掉一个冗余的哑变量,避免完全共线性。 - 删除零方差特征:计算每个特征的方差,过滤掉方差为0的特征:
from sklearn.feature_selection import VarianceThreshold selector = VarianceThreshold(threshold=0) inputs_train = selector.fit_transform(inputs_train) - 检测高度相关特征:计算特征的相关系数矩阵,或使用VIF(方差膨胀因子)找出高度相关的特征,移除其中一个:
from statsmodels.stats.outliers_influence import variance_inflation_factor vif_data = pd.DataFrame() vif_data["feature"] = your_feature_names vif_data["VIF"] = [variance_inflation_factor(inputs_train, i) for i in range(inputs_train.shape[1])] # 移除VIF值远大于10的特征
2. 给自定义模型添加正则化处理
把原生sklearn的正则化逻辑加入你的自定义模型,确保Fisher矩阵可逆。修改fit方法中的Fisher矩阵计算代码:
def fit(self,X,y): self.model.fit(X,y) #### Get p-values for the fitted model #### denom = (2.0 * (1.0 + np.cosh(self.model.decision_function(X)))) denom = np.tile(denom,(X.shape[1],1)).T # 加入L2正则化项,对应sklearn的C参数(alpha = 1/C) alpha = 1.0 / self.model.C F_ij = np.dot((X / denom).T,X) + alpha * np.eye(X.shape[1]) ## 加入正则化后的Fisher Information Matrix Cramer_Rao = np.linalg.inv(F_ij) ## Inverse Information Matrix sigma_estimates = np.sqrt(np.diagonal(Cramer_Rao)) z_scores = self.model.coef_[0] / sigma_estimates # z-score for each model coefficient p_values = [stat.norm.sf(abs(x)) * 2 for x in z_scores] ### two tailed test for p-values self.coef_ = self.model.coef_ # 修正笔误:self.mode 应该是 self.model.intercept_ self.intercept_ = self.model.intercept_ # 把p值也存到实例里方便调用 self.p_values = p_values
3. 修正代码中的笔误
注意到你代码最后一行self.intercept_ = self.mode是笔误,应该改为self.intercept_ = self.model.intercept_,不然之后调用reg.intercept_会报错。
验证
修改完成后,再运行你的调用代码:
reg = LogisticRegression_with_p_values() reg.fit(inputs_train,loan_data_targets_train) # 可以查看p值 print(reg.p_values)
内容的提问来源于stack exchange,提问作者Billeh Sarkozy
相关产品推荐
相关产品推荐

