1.问题引入

平常我们在训练模型时对数据集是如何处理的呢,我们是这样做的,引入sklearn中的train_test_split模块,将数据集划分为训练集和测试集,再用训练集的数据拟合模型,最后用测试集验证模型的性能,根据返回的指标判断这个模型够不够好,不够好的情况下调试模型的参数,再去验证,如此多试几次得到一个较好的模型。可这样问题就出现了,你是怎么得到这个较好的模型的,你这个调试参数的行为是不是相当于把测试集也当作训练集放进去训练了吗?显然这样是不对的。测试集不参与模型的训练。

2.K折交叉验证

K折交叉验证是机器学习中最常用、最经典的模型评估方法。它解决了传统“训练集/测试集”划分中评估结果波动大、对数据利用不充分的问题。

原理:不将训练集一次性都给模型训练,而是分成K份,轮流把其中一份当作验证集,其余K-1份当作训练集,重复K次,最后取平均。

用此方法得到了哪些好处?

        1.方差降低(稳定性高):单次切分如果恰好把难样本分进测试集,模型分数会极低。K折取平均,评估结果几乎不受“运气”影响,更能代表模型在未知数据上的真实泛化能力。

        2.数据利用率极高:每一轮中,90%(K=10时)的数据都用于训练,这对于小样本数据集尤为珍贵。

       3. 防止过拟合:模型在略微不同的训练集上训练多次,能有效检验模型是否过于依赖某一部分数据的特定模式。

K值怎么选?

        1.K=5 或 K=10(行业黄金标准):经验表明,5 或 10 折能在计算成本和评估稳定性之间取得最佳平衡。绝大多数论文和比赛默认采用 10折。

        2.K 较小(如 K=2):训练集只有一半数据,偏差较大,评估结果容易低估模型真实能力。

        3.K 较大(如 K=20 或 留一法 LOO):训练集几乎接近全量数据,偏差小,但折数多导致计算开销巨大;且各折训练集高度相似,评估结果方差反而可能变大,且耗时极长。

3.代码实现

下面是银行贷款识别老赖的项目部分代码,这里用到的模型是逻辑回归查找二分类问题

# 执行交叉验证
from sklearn.model_selection import cross_val_score

# 交叉验证选择较优的惩罚因子
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, train_X, train_y, cv = 8, scoring = 'recall' )
    score_mean = sum(score)/len(score)
    scores.append(score_mean)
    print(score_mean)

第一步导入我们需要的包from sklearn.model_selection import cross_val_score

scores = []定义一个空列表用来保存每个惩罚因子下的模型经过8折交叉验证后得到的平均召回率。

c_param_range = [0.01,0.1,1,10,100]这里做了个惩罚因子的列表,惩罚因子是模型的参数,在逻辑回归中,它是惩罚系数\lambda的倒数。

for i in c_param_range:
    lr = LogisticRegression(C=i , penalty='l2', solver='lbfgs', max_iter=1000)

遍历列表,创立模型对象lr,参数C是惩罚因子,penalty是正则化项,‘l2’代表用l2正则化,参数solver=‘lbfgs’代表用梯度下降算法,max_iter代表模型最大的迭代次数。

score = cross_val_score(lr, train_X, train_y, cv = 8, scoring = 'recall' )
    score_mean = sum(score)/len(score)
    scores.append(score_mean)
    print(score_mean)

使用交叉验证,参入的参数分别是lr(所用模型),train_X(训练集特征),train_y(训练集标签),cv(交叉验证的折数),scoring(返回的指标,这里返回的是召回率)

然后取平均值加到列表里面,最后打印这个平均值。

再往下就是比较哪个值更好,选择对应的C值构建模型。

更多推荐