机器学习第二课之逻辑回归(二)LogisticRegression
简介
接上一篇博客最后
机器学习第二课之逻辑回归(一)LogisticRegression
这是我们对银行贷款的检测结果,现在我们就对这些结果指标进行进一步分析。
一.分类评估⽅法
1.混淆矩阵
在分类任务下,预测结果(Predicted Condition)与正确标记(True Condition)之间存在四种不同的组合,构成混淆矩阵(适⽤于多分类)
- TP(True Positive,真正例):预测为正例且实际为正例的数量
- FP(False Positive,伪正例):预测为正例但实际为负例的数量
- FN(False Negative,伪反例):预测为负例但实际为正例的数量
- TN(True Negative,真反例):预测为负例且实际为负例的数量
准确率是一个常用的性能指标,但在类别不平衡的情况下可能会产生误导。例如,如果大多数样本是负类,模型只需简单地预测所有样本为负类即可获得高准确率。
2.精确率(Precision)与召回率(Recall)
精确率:预测结果为正例样本中真实为正例的⽐例
精确率衡量的是模型在预测为正类时的准确性。在某些应用中(如疾病筛查),我们希望尽量减少假阳性,因为假阳性可能导致不必要的后续检查或治疗。
召回率:真实为正例的样本中预测结果为正例的⽐例(查得全,对正样本的区分能⼒)
召回率衡量的是模型对正类样本的识别能力。在某些情况下(如癌症检测),我们希望尽量减少假阴性,因为漏掉一个真实的阳性样本可能会导致严重后果。
3.F1-score
单独用精确率或者召回率不能很好的评估模型好坏。当 P 和 R 同时为 1 时,F1=1。当有一个很大,另一个很小的时候,比如 P=1,R~0,此时 F1~0。分子 2PR 的 2 完全了为了使最终取值在 0-1 之间,进行区间放大,无实际意义。
4.分类评估报告api
sklearn.metrics.classification_report(y_true, y_pred, labels=[], target_names=None )
- y_true:真实⽬标值
- y_pred:估计器预测⽬标值
- labels:指定类别对应的数字
- target_names:⽬标类别名称
- return:每个类别精确率与召回率
2.正则化惩罚
对于逻辑回归的API:
LogisticRegression(penalty='l2', dual=False, tol=0.0001, C=1.0, fit_intercept=True,intercept_scaling=1, class_weight=None, random_state=None, solver='liblinear',max_iter=100, multi_class='ovr', verbose=0, warm_start=False, n_jobs=1)
其中有个参数C表示:正则化强度。为浮点型数据。正则化系数 λ
的倒数,float
类型,默认为 1.0
。必须是正浮点型数。像 SVM
一样,越小的数值表示越强的正则化。我们就来探讨一下这个正则化惩罚到底是什么含义。
当我们进行梯度下降的时候,可能遇到一种情况,我们遇到了两处都是寻找的极值点,但是要怎么去区分这两个极值点那个是我们最需要的呢?
对于一个我们获取的训练得到的函数
我们现在有个输入 ,这是一个包含 4 个元素的输入向量。经过我们得到对于w有两个不同的权重都取得相同的极值点。假设w0为1
权重与输入的乘积:
与输入 X的乘积为:
与输入 X的乘积为:
权重的效果 :
只关注第一个输入特征,而忽略其他特征,这可能导致模型过拟合(即模型在训练数据上表现很好,但在新数据上表现差)。
均匀地关注所有输入特征,因此能够学习到每个特征的信息,泛化能力更强,效果更好。
均方差损失函数
均方差损失函数用于衡量模型预测值与真实值之间的差异,公式为:
其中:
是预测值,y 是真实值。
- N 是样本数量。
是正则化惩罚项,用于防止过拟合。
正则化惩罚的功能:
正则化惩罚主要用于惩罚权重参数 w,防止模型过拟合。常见的正则化方法有:
- L1 正则化:
,通过惩罚权重的绝对值来产生稀疏解(即让一些权重变为 0)。
- L2 正则化:
,通过惩罚权重的平方来防止权重过大。
3.⽋拟合和过拟合
- 过拟合:⼀个假设在训练数据上能够获得⽐其他假设更好的拟合, 但是在测试数据集上却不能很好地拟合数据, 此时认为这个假设出现了过拟合的现象。(模型过于复杂)
- ⽋拟合:⼀个假设在训练数据上不能获得更好的拟合,并且在测试数据集上也不能很好地拟合数据,此时认为这个假设出现了⽋拟合的现象。(模型过于简单)
那么是什么原因导致模型复杂?线性回归进⾏训练学习的时候变成模型会变得复杂,这⾥就对应前⾯再说的线性回归的两种关系,⾮线性关系的数据,也就是存在很多⽆⽤的特征或者现实中的事物特征跟⽬标值的关系并不是简单的线性关系。
原因以及解决办法
4.K折交叉验证
对于上次我们的银行贷款的检测结果召回率只有百分之六十二,而对于银行来说,主要看的就是模型的召回率,他们会尽量要求不能给失信的人贷款,所有其他的准确率可以低一点但是召回率必须要达到理想。然而我们就可以使用交叉验证对模型进行提升。
就是在训练集中选一部分样本用于测试模型。
保留一部分的训练集数据作为验证集/评估集,对训练集生成的参数进行测试,相对客观的判断这些参数对训练集之外的数据的符合程度。
K折交叉验证(k-fold cross validation)
进行模型评估方式存在的弊端,提出Cross Validation 交叉验证。
Cross Validation:简言之,就是进行多次数据划分;每次划分时,在不同的数据集上进行训练、测试评估,从而得出一个评价结果;如果是5折交叉验证,意思就是在原始数据集上,进行5次划分,每次划分进行一次训练、评估,最后得到5次划分后的评估结果,一般在这几次评估结果上取平均得到最后的 评分。k-fold cross-validation ,其中,k一般取5或10
- 训练模型需要在大量的数据集基础上,否则就不能够识别数据中的趋势,导致错误产生
- 同样需要适量的验证数据点。 验证集太小容易导致误差
- 多次训练和验证模型。需要改变训练集和验证集的划分,有助于验证模型。
- 随机将整个数据集分成k折;
- 如图中所示,依次取每一折的数据集作验证集,剩余部分作为训练集
- 算出每一折测试的召回率
- 取这里K次的记录平均值 作为最终结果
交叉验证目的
我们本次的目的是去寻找最合适的C值,提升模型召回率,对于选取C的最优值,我们就要把不同C值放到模型里面训练,然后用验证集去验证得到结果进行比较,如果只是简单地将数据集划分为训练集和测试集,模型在测试集上的性能会受到数据划分方式的影响。不同的划分可能会导致模型在测试集上的表现差异较大,这样得到的评估结果稳定性差,不能可靠地反映模型的真实泛化能力 。例如,某次划分刚好将一些具有特殊特征的样本集中在测试集,模型在这个测试集上的性能就不能代表其在一般情况下的性能。
在逻辑回归中,参数C
是正则化强度的倒数。C
值较小,意味着正则化强度较大,会对模型的权重进行更严格的约束,使模型更加简单,防止过拟合;C
值较大,正则化强度较弱,模型可以学习到更复杂的模式,但也增加了过拟合的风险 。
通过交叉验证,对不同C
值进行评估,可以直观地了解每个C
值下模型在不同数据子集上的表现。如果C
值过小,模型在交叉验证中的表现可能会在训练集和验证集上都较差,出现欠拟合;如果C
值过大,虽然在训练集上表现较好,但在验证集上的性能会下降,出现过拟合。通过交叉验证,能够找到一个合适的C
值,使得模型在训练集和验证集上都能有较好的平衡,既具有一定的拟合能力,又有较好的泛化能力。
5.代码分析
我们了解了分类评估方法、也了解了正则化惩罚、k折交叉验证等,最终的目的都是让我们的模型的召回率得到提升,那怎么能得到提升呢 ?
导入依赖库
import pandas as pd # 数据处理
import numpy as np # 数值计算
from sklearn.preprocessing import StandardScaler # 特征标准化
from sklearn.model_selection import train_test_split # 数据划分
from sklearn.linear_model import LogisticRegression # 逻辑回归模型
from sklearn import metrics # 模型评估指标
from sklearn.model_selection import cross_val_score # 交叉验证
数据加载与预处理
# 加载数据集
data = pd.read_csv("creditcard.csv")# 特征标准化:对Amount列进行标准化(均值为0,标准差为1)
scaler = StandardScaler()
data["Amount"] = scaler.fit_transform(data[["Amount"]])# 特征选择:删除Time列(可能与欺诈检测无关)
data = data.drop(["Time"], axis=1)
划分特征与标签
x = data.iloc[:, :-1] # 所有行,除最后一列外的所有列(特征)
y = data.iloc[:, -1] # 所有行,最后一列(标签:0=正常,1=欺诈)
划分训练集与测试集
x_train_w, x_test_w, y_train_w, y_test_w = train_test_split(x, y, test_size=0.4, random_state=100
)
交叉验证优化参数 C
scores = []
c_param_range = [0.01, 0.1, 1, 10, 100] # 待测试的正则化参数Cfor i in c_param_range:# 定义逻辑回归模型,使用L2正则化lr = LogisticRegression(C=i, penalty="l2", solver='lbfgs', max_iter=1000)# 8折交叉验证,评估指标为召回率(recall)score = cross_val_score(lr, x_train_w, y_train_w, cv=8, scoring="recall")score_mean = sum(score) / len(score) # 计算平均召回率scores.append(score_mean)print(f"C等于{i}的召回率为{score_mean}")# 选择最佳C值(平均召回率最高的C)
best_c = c_param_range[np.argmax(scores)]
print("最好的c是:", best_c)
- 通过交叉验证选择最优正则化参数
C
,平衡模型过拟合与欠拟合。 - 参数说明:
C
:逻辑回归正则化强度的倒数(C
越小,正则化越强)。penalty="l2"
:使用 L2 正则化(防止权重过大)。cv=8
:8 折交叉验证,充分利用训练数据评估性能。scoring="recall"
:选择召回率作为评估指标(对欺诈检测至关重要,因为需要尽可能识别所有欺诈交易,避免漏检)。
训练最终模型并评估
# 使用最佳参数C训练模型
estimator = LogisticRegression(C=best_c)
estimator.fit(x_train_w, y_train_w)# 在训练集上的准确率
score = estimator.score(x_train_w, y_train_w)
print(score)# 在测试集上的详细评估报告
print(metrics.classification_report(y_test_w, test_predicted))
- 用最优
C
值训练最终模型,并评估性能:estimator.score
:输出训练集上的准确率(正确分类的样本比例)。classification_report
:输出测试集上的详细指标,包括精确率(precision)、召回率(recall)、F1 值等,尤其关注欺诈类(1)的召回率(避免漏检欺诈交易)。
完整代码
import pandas as pd
import numpy as np
import matplotlib as plt
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
import pylab as mpl
from sklearn.model_selection import cross_val_scoredata=pd.read_csv("creditcard.csv")scaler=StandardScaler()
data["Amount"]=scaler.fit_transform(data[["Amount"]])
data=data.drop(["Time"], axis=1)x=data.iloc[:, :-1]
y=data.iloc[:, -1]x_train_w,x_test_w,y_train_w,y_test_w=train_test_split(x,y,test_size=0.4,random_state=100)#交叉验证
scores=[]
c_param_range=[0.01, 0.1, 1, 10, 100]
for i in c_param_range:lr=LogisticRegression(C=i, penalty="l2", solver='lbfgs', max_iter=1000)score=cross_val_score(lr, x_train_w, y_train_w, cv=8, scoring="recall")score_mean=sum(score)/len(score)scores.append(score_mean)print("C等于{}的召回率为{}".format(i, score_mean))best_c=c_param_range[np.argmax(scores)]
print("最好的c是:",best_c)estimator=LogisticRegression(C=best_c)
estimator.fit(x_train_w,y_train_w)
test_predicted=estimator.predict(x_test_w)
score=estimator.score(x_train_w,y_train_w)
print(score)
print(metrics.classification_report(y_test_w,test_predicted))