逻辑回归作为机器学习一种经典的分类算法,在实际应用中可能面临过拟合、召回率低、精度不足等各种问题,我们可以通过一些优化措施解决这些问题。
1.数据问题
在运用逻辑回归算法时,数据的质量直接影响模型性能,有效的预处理是逻辑回归优化的基础。
若数据集中缺少某些数据,就会产生缺失值,我们需要对这些缺失值进行处理,不同的数据类型继续不同的操作,数值型特征:采用均值、中位数填充(适用于正态分布或偏态分布),或用模型预测缺失值(如 KNN 填充)。类别型特征:用众数填充,或新增 "缺失值" 类别标签。
若数据出现异常,则可能导致模型参数偏移,我们需要对异常值进行修改或移除等处理。
2.特征问题
在庞大的数据集中有各式各样类型的数据,所以我们需要对特征进行一些处理,处理方式有Z标准化和归一化。
- 归一化(Normalization)
归一化通常指将数据缩放到 [0, 1] 或 [-1, 1] 的固定区间 ,也称为 "Min-Max 缩放"。最常见的是缩放到 [0, 1] 区间。
公式(缩放到 [0, 1]):
对于特征数据集中的每个样本值 x:Xnorm=X−min(X)/max(X)−min(X)
其中:min(X) 是特征 X 的最小值;max(X) 是特征 X 的最大值。
- Z 标准化(Z-Score Standardization)
Z 标准化将数据转换为均值为 0、标准差为 1 的分布,也称为 "标准化" 或 "标准差标准化"。转换后的数据称为 "Z 分数"(Z-Score)。
公式:
对于特征数据集中的每个样本值 x:Xstd=X−μ/σ
其中:μ 是特征 X 的均值(Mean);σ 是特征 X 的标准差(Standard Deviation)。
3.过拟合问题
当我们测试时的预测结果与训练时的预测结果相差过大,就产生了过拟合。根据不同的情况用不同的方法来解决过拟合问题。
1.降低复杂度
减少参数:例如减少神经网络的层数 / 神经元数量、限制决策树的深度。
选择简单模型:如用线性模型替代非线性模型(在数据规律较简单时)。
- 正则化(Regularization)
通过在损失函数中加入 "惩罚项",限制模型参数的大小,防止参数过大导致过拟合。常见方法:
L1 正则化:惩罚参数的绝对值之和,可能使部分参数变为 0。
L2 正则化:惩罚参数的平方和,使参数值普遍较小(默认使用)
正则化参数 λ(逻辑回归中常用C
表示,C=1/λ
,C
越小正则化越强)需通过交叉验证调优
3.交叉验证(Cross-Validation)
将训练数据分为多个子集,交替用不同子集训练和验证模型,帮助判断模型是否过拟合,并选择更优的参数。
- 增加训练数据
收集更多数据:更多的样本能帮助模型学习到更通用的规律,减少对噪声的依赖。
数据增强(Data Augmentation):通过对现有数据进行合理的变化,生成 "新样本",间接增加数据量。
4.类别不平衡问题
当正负样本比例失衡(如正样本占比 < 10%),模型可能偏向多数类。例如在一组银行贷款人员判断名单中我们将可以贷款的人员设为0不可以贷款的人员设为1,在这组数据中大部分人都可以贷款只有极少数人不能贷款,这时模型就会偏向0样本这一类。解决方法有:
下采样:
从多数类中随机或有策略地选取部分样本,减少其数量,使多数类与少数类的样本数量接近。
代码示例:
python
import numpy as np
import pandas as pd
data = pd.read_csv('creditcard.csv')
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
data['Amount'] = scaler.fit_transform(data[['Amount']])
data = data.drop(['Time'],axis=1)
positive_eg = data[data['Class']==0]
negative_eg = data[data['Class']==1]
positive_eg = positive_eg.sample(len(negative_eg))
data_c = pd.concat([positive_eg,negative_eg])
X = data_c.drop(['Class'],axis=1)
y = data_c['Class']
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
scores = []
C_range = [0.01,0.1,1,10,100]
for i in C_range:
lr = LogisticRegression(C=i,penalty='l2',solver='lbfgs',max_iter=1000)
score = cross_val_score(lr,X_train,y_train,cv=5,scoring='recall')
score_mean = sum(score)/len(score)
scores.append(score_mean)
best_C = C_range[np.argmax(scores)]
print('最优惩罚因子为:{}'.format(best_C))
lr1 = LogisticRegression(C=best_C,penalty='l2',max_iter=1000) # 用逻辑回归算法创建模型
lr1.fit(X_train, y_train)
test_predict = lr1.predict(X_test)
result1 = lr1.score(X_test, y_test)
print(result1)
from sklearn import metrics
print(metrics.classification_report(y_test,test_predict))
上述代码中我们先将大量的数据分为80%训练集和20%测试集,再将训练集中的多类样本随机抽取少类样本数量的数据加上少类样本的数据作为新的训练集。这样即可解决类别不平衡问题。
过采样:
对少数类样本进行复制或生成新样本,增加其数量,使少数类与多数类的样本数量接近。
代码示例:
python
import numpy as np
import pandas as pd
data = pd.read_csv('creditcard.csv')
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
data['Amount'] = scaler.fit_transform(data[['Amount']])
data = data.drop(['Time'],axis=1)
X = data.drop(['Class'],axis=1)
y = data['Class']
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
from imblearn.over_sampling import SMOTE
oversampler =SMOTE(random_state=0)
os_x_train, os_y_train = oversampler.fit_resample(X_train,y_train)
os_x_train_w,os_x_test_w,os_y_train_w,os_y_test_w = train_test_split(os_x_train,os_y_train,test_size=0.2,random_state=0)
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
scores = []
C_range = [0.01,0.1,1,10,100]
for i in C_range:
lr = LogisticRegression(C=i,penalty='l2',solver='lbfgs',max_iter=1000)
score = cross_val_score(lr,X_train,y_train,cv=5,scoring='recall')
score_mean = sum(score)/len(score)
scores.append(score_mean)
best_C = C_range[np.argmax(scores)]
print('最优惩罚因子为:{}'.format(best_C))
lr1 = LogisticRegression(C=best_C,penalty='l2',max_iter=1000) # 用逻辑回归算法创建模型
lr1.fit(os_x_train_w,os_y_train_w)
test_predict = lr1.predict(os_x_test_w)
result1 = lr1.score(os_x_test_w,os_y_test_w)
print(result1)
from sklearn import metrics
print(metrics.classification_report(os_y_test_w,test_predict))
上述代码通过 SMOTE 算法将少类样本的数量拟合到多类样本一样的数量以解决类别不平衡问题。
调整决策阈值:
在机器学习分类任务中,决策阈值(Decision Threshold) 是判断模型输出的概率(或得分值)转化为具体类别(如 "正 / 负""是 / 否")的临界值。调整决策阈值是平衡分类模型精确率(Precision) 和召回率(Recall) 的重要手段,尤其不同业务场景的需求。
代码实现;
python
from sklearn import metrics
print(metrics.classification_report(os_y_test_w,test_predict))
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
recalls = []
for i in thresholds:
y_predict_proba = lr1.predict_proba(os_x_test_w)
y_predict_proba = pd.DataFrame(y_predict_proba)
y_predict_proba = y_predict_proba.drop([0], axis=1)
y_predict_proba[y_predict_proba[[1]] > i]=1
y_predict_proba[y_predict_proba[[1]] <= i] = 0
recall = metrics.recall_score(os_y_test_w, y_predict_proba[1])
recalls.append(recall)
print(recalls)
上述代码可以通过改变决策阈值以解决类别不平衡问题。
5.了解混乱矩阵
混乱矩阵的基本结构
混乱矩阵是一个 n×n 的方阵(n 为分类任务的类别数量),其中:
行表示 实际类别(真实标签);
列表示 预测类别(模型输出的标签);
矩阵中的每个元素 Ci,j 表示 实际为第 i 类、但被预测为第 j 类的样本数量。
二分类问题的混乱矩阵(最常用)
对于二分类任务(如 "正例 / 负例""垃圾邮件 / 正常邮件"),混乱矩阵为 2×2,包含 4 个核心元素:
实际类别 \ 预测类别 | 预测为正例(Positive) | 预测为负例(Negative) |
---|---|---|
实际为正例(Positive) | 真正例(True Positive, TP) | 假负例(False Negative, FN) |
实际为负例(Negative) | 假正例(False Positive, FP) | 真负例(True Negative, TN) |
真正例(TP):实际是正例,模型也预测为正例(预测正确);
假负例(FN):实际是正例,模型却预测为负例(预测错误,漏检);
假正例(FP):实际是负例,模型却预测为正例(预测错误,误检);
真负例(TN):实际是负例,模型也预测为负例(预测正确)。
基于混乱矩阵的常用评价指标
混乱矩阵本身直观展示了错误类型,但为了量化模型性能,通常会基于其元素计算以下指标:
准确率(Accuracy, ACC)
定义:所有预测正确的样本占总样本的比例。
公式 :
ACC=(TP+TN)/(TP+TN+FP+FN)
适用场景:类别分布均衡的场景,但在不平衡数据中可能误导(如 99% 负例时,模型全预测负例也能得 99% 准确率)。
精确率(Precision, P)
定义:预测为正例的样本中,实际确实是正例的比例("预测为正的可靠性")。
公式 :
Precision=TP/TP+FP
适用场景:关注 "误检成本高" 的场景(如垃圾邮件识别,避免正常邮件被误判为垃圾邮件)。
召回率(Recall)
定义:实际为正例的样本中,被模型成功预测为正例的比例("正例的检出能力")。
公式 :
Recall=TP/TP+FN
适用场景:关注 "漏检成本高" 的场景(如疾病诊断,避免漏检真正患病的人)。
F1 分数(F1-Score)
定义:精确率和召回率的调和平均数,综合两者表现,避免单一指标的局限性。
公式 :
F1=2×Precision+RecallPrecision×Recall
适用场景:需要平衡精确率和召回率的场景(如信息检索,既希望结果相关,又希望覆盖全面)。