在逻辑回归里,准确度、精确率、召回率常作为模型的评估指标,我们介绍一下这三个评估指标基本概念:
- 真阳性(TP):模型预测为正例,且实际确实是正例(把垃圾邮件正确判断为垃圾邮件)。
- 假阳性(FP):模型预测为正例,但实际是负例(把正常邮件误判为垃圾邮件)。
- 假阴性(FN):模型预测为负例,但实际是正例(把垃圾邮件误判为正常邮件)。
- 真阴性(TN):模型预测为负例,且实际确实是负例(把正常邮件正确判断为正常邮件)。
1. 准确率(Accuracy)
人话:模型整体判断对的比例,不管是正例还是负例,只要猜对了都算。
公式:
例子:100 封邮件里,模型对了 80 封(不管是垃圾还是正常),准确率就是 80%。
2. 精确率(Precision)
人话:模型说 “是正例” 的那些样本里,真正是正例的比例(少冤枉好人)。
公式:
例子:模型说 10 封是垃圾邮件,其中 8 封真的是,精确率就是 80%(剩下 2 封是正常邮件被误判了)。
3. 召回率(Recall)
人话:所有实际是正例的样本里,被模型成功找出来的比例(别放过坏人)。
公式:
例子:实际有 10 封垃圾邮件,模型只认出了 7 封,召回率就是 70%(剩下 3 封漏网了)。
一句话总结区别:
- 准确率:整体蒙对的概率;
- 精确率:说 “是” 的时候,对的概率;
- 召回率:该 “是” 的东西,被找出来的概率。
在处理实际问题中,我们更关注该 “是” 的东西,被找出来的概率,也就是召回率。
交叉验证
交叉验证的目的
简单说,就是让模型的 “考试成绩” 更可信。
比如你训练了一个模型,只拿一批数据当 “测试卷”,可能这次题目刚好对胃口(得分虚高),也可能刚好不擅长(得分偏低),结果不准。
交叉验证通过 “多次换试卷、取平均分”,过滤掉这种偶然因素,让你更清楚模型的真实水平。
最常用的 K 折交叉验证步骤
- 分份:把所有数据随机切成 K 等份(比如 K=5,切成 5 小份);
- 轮次测试:
- 第 1 轮:用 4 份当 “教材”(训练集),剩下 1 份当 “试卷”(测试集),考完打分;
- 第 2 轮:换另 1 份当 “试卷”,剩下 4 份当 “教材”,再考再打分;
- ... 直到每一份都当过一次 “试卷”(共 K 轮);
- 算平均分:把 K 次的分数取平均,就是模型的最终 “成绩单”。
代码实现:
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
# 假设x是特征数据,y是标签数据(需要你自己准备)
# 定义要尝试的正则化参数C的候选值
c_list = [0.01, 0.1, 1, 10, 100]
scores = [] # 用于存储不同C对应的平均召回率
# 遍历每个C值,进行交叉验证
for c in c_list:
# 创建逻辑回归模型,使用L2正则化
model = LogisticRegression(C=c, penalty='l2', max_iter=1000)
# 进行6折交叉验证,评估指标为召回率
cv_scores = cross_val_score(model, x, y, cv=6, scoring='recall')
# 计算交叉验证的平均召回率
mean_recall = sum(cv_scores) / len(cv_scores)
scores.append(mean_recall)
print(f"C={c} 时的平均召回率: {mean_recall:.4f}")
# 找到最优的C值(对应最大的平均召回率)
best_c = c_list[np.argmax(scores)]
print(f"\n最优的正则化参数C是: {best_c}")
# 使用最优的C值训练最终模型
best_model = LogisticRegression(C=best_c, penalty='l2', max_iter=1000).fit(x, y)
下采样与过采样
在二分类中,假设我们的数据集中负例有280000条,正例只有500条,正负样本差距太大,输入训练模型,模型会因为正例子的数据量不够,训练出的模型不能更好的识别正类样本,那对于样本的缺陷,我们可以使用下采样与过采样平衡样本的数量。
先进行数标准化与训练集与测试集切分,代码如下
s=StandardScaler()#数据标准化对象
data=pd.read_csv(r"F:\download\creditcard.csv")#pandas导入本地csv文件
data['Amount']= s.fit_transform(data[['Amount']])#将计算后的标准化
data = data.drop(['Time'],axis=1)#删除无用行
x=data.iloc[:,:-1]#获取特征
y=data.iloc[:,-1]#获取标签
x_train,x_test,y_train,y_test=train_test_split(x, y, test_size=0.5,random_state=50)#划分集
下采样
经过上面数据标准化,训练集与测试集切分之后,假设正例子只有300条,那我们从负样本中随机抽取300条,把这两个样本合并得到新的训练集这个,正负样本的数量配合,输入模型,模型就可以更好的学正负特征。代码如下
data=pd.concat([x_train,y_train],axis=1)#训练集的特征与标签连接起来
xx=data[data.iloc[:,-1]==0]#取出标签为0的样本
yy=data[data.iloc[:,-1]==1]#取出标签为1的样本
xx=xx.sample((len(yy)))#在标签为0的样本随机抽样300条
data1=pd.concat([xx,yy])#把两样本结合
x=data1.iloc[:,:-1]#取出特征
y=data1.iloc[:,-1]#取出标签
过采样
当负样本切分之后还有190000条,正样本有300条,过采样就用函数方法把300条拟合成190000
实现样本平衡,使用这个拟合函数要安装imblearn库,实现过采集代码如下。
from imblearn.over_sampling import SMOTE
oversampler=SMOTE(random_state=0)#调用imbLearn中的方法创建拟合对象
xx,yy=oversampler.fit_resample(x_train,y_train)#自动检测样本的差距,平衡样本
修改阈值
当通过上面的方法优化后模型的召回率只有0.94,对于我们的项目要求召回率0.96还有点距离,我们可以通过修改阈值的方法去调整召回率,代码如下
gg=np.arange(0.1, 0.9, 0.1)#生成0.1到0.9的概率数组
a=model.predict_proba(x_test)[:, 1]#获取真实值是1,每个样本能预测对的概率
recall_scores = []
for i in gg:
y_pre=(a>=i).astype(int)#获取大于数组里概率的新矩阵
recall_scores.append(metrics.recall_score(y_test,y_pre))#对真实值与新的预测值计算召回率
print(recall_scores[np.argmax(recall_scores)])#打印召回率最大那阈值