ETJava Beta | Java    注册   登录
  • 搜索:
  • 机器学习(四)——Lasso线性回归预测构建分类模型(matlab)

    发表于      阅读(1)     博客类别:Crawler     转自:https://www.cnblogs.com/Yizhiyingyingguai/p/18278851
    如有侵权 请联系我们删除  (页面底部联系我们)  

    Lasso线性回归(Least Absolute Shrinkage and Selection Operator)是一种能够进行特征选择和正则化的线性回归方法。其重要的思想是L1正则化:其基本原理为在损失函数中加上模型权重系数的绝对值,要想让模型的拟合效果比较好,就要使损失函数尽可能的小,因此这样会使很多权重变为0或者权重值变得尽可能小,这样通过减少权重、降低权重值的方法能够防止模型过拟合,增加模型的泛化能力。其中还有另外一种类似的方法叫做岭回归,其基本原理是在损失函数中加上含有模型权重系数的平方的惩罚项,其他原理基本相同。

    Lasso线性回归的目标是最小化以下损失函数:

    其中:

    理论上来说当模型的损失函数越小时,构建的模型越接近真实分布,但是当模型的参数远远大于用来训练模型的数量的时候,很容易造成过拟合(模型学到的特征不是样本之间的共同特征,而是样本自身的特异性特征)。
    通过L1正则化,可以约束线性模型中的权重系数,而且会减少特征量,保留权重系数有效的特征,同时能够减少系数之间的差距,让模型更具有泛化性。
    当模型的损失函数达到最小的时候,惩罚项λ达到最优,模型的性能达到最优。

    本文同样使用留一交叉验证的方法验证模型的分类性能,具体应用场景可以参考:机器学习(一)——递归特征消除法实现SVM(matlab)。
    本文还提供了均方误差与特征数量的变化关系曲线、λ与均方误差的变化关系曲线以及分类结果的ROC曲线画法,如有需要请选择对应模块进行调整作图。

    matlab实现代码如下:

    labels = res(:, 1);  % 第一列是标签
    features = res(:, 2:end);  % 后面的列是特征
    features = zscore(features);   %归一化处理
    
    
    %% 使用留一法交叉验证选择最优的 Lambda 值及其对应的特征
    numSamples = size(features, 1);
    lambda_values = logspace(-2, 2, 60); % 选择一系列 Lambda 值
    
    mse_values = zeros(size(lambda_values)); % 存储每个 Lambda 值的均方误差
    selected_features_all = cell(length(lambda_values), 1); % 存储每个 Lambda 值选择的特征
    
    for i = 1:length(lambda_values)
        mse_fold = zeros(numSamples, 1);
        selected_feature = []; % 重置选择的特征
        
        for j = 1:numSamples
            % 划分训练集和验证集
            X_train = features([1:j-1, j+1:end], :); % 使用除了当前样本之外的所有样本作为训练集
            y_train = labels([1:j-1, j+1:end]); % 训练集标签
            X_valid = features(j, :); % 当前样本作为验证集
            y_valid = labels(j); % 验证集标签
            
            % 训练 LASSO 模型
            B = lasso(X_train, y_train, 'Lambda', lambda_values(i));
            
            % 在验证集上进行预测
            y_pred = X_valid * B;
            
            % 计算均方误差
            mse_fold(j) = mean((y_pred - y_valid).^2);
            
            % 将选择的特征添加到列表中
            selected_feature = [selected_feature; find(B ~= 0)]; % 使用分号进行垂直串联
    
        end
        
        % 计算当前 Lambda 值的平均均方误差
        mse_values(i) = mean(mse_fold);
       selected_feature= unique(selected_feature);%消除重复的特征
        % 保存每个 Lambda 值选择的特征
        selected_features_all{i} = selected_feature;
    end
    
    % 找到使均方误差最小的 Lambda 值
    
    [min_mse, min_idx] = min(mse_values);
    min_idx=min_idx-2;    %相当于当λ达到最优时,特征数量为0,所以要找最靠近最优λ的λ值来构建模型,此处可调
    min_mse=mse_values(min_idx);
    optimal_lambda = lambda_values(min_idx);
    
    % 找到最优 Lambda 值对应的特征
    selected_features_optimal = selected_features_all{min_idx};
    selected_features_optimal = unique(selected_features_optimal);  %%%%%%%保留不同的特征,防止特征重复出现
    % 显示最优的 Lambda 值及其对应的特征
    disp(['最优的 Lambda 值:', num2str(optimal_lambda)]);
    
    
    
    
    %% 对挑选出来的向量构建模型,并使用留一交叉验证计算其平均准确率
    
    % 初始化变量来存储准确率
    num_samples = size(features, 1);
    accuracies = zeros(num_samples, 1);
    Prediction_probability=zeros(num_samples, 1);%声明一个空数组用于储存预测的概率
    
    % 遍历每个样本
    for i = 1:num_samples
        % 留出第 i 个样本作为验证集,其余样本作为训练集
        X_train = features([1:i-1, i+1:end], selected_features_optimal); % 选择选出来的特征
        y_train = labels([1:i-1, i+1:end]);
        X_valid = features(i, selected_features_optimal);
        y_valid = labels(i);
        
        % 训练逻辑回归模型
        mdl = fitglm(X_train, y_train, 'Distribution', 'binomial', 'Link', 'logit');
        
        % 在验证集上进行预测
        y_pred = predict(mdl, X_valid);
        
        % 将预测概率转换为类别标签
        y_pred_label = round(y_pred);
        
    
        Prediction_probability(i)=y_pred;
        % 计算准确率
        accuracies(i) = (y_pred_label == y_valid);
    end
    
    % 计算平均准确率
    average_accuracy = mean(accuracies);
    
    % 显示平均准确率
    disp(['平均准确率:', num2str(average_accuracy)]);
    
    
    % 计算选取的特征个数
    num_selected_features = cellfun(@length, selected_features_all);
    
    
    
    % 绘制三维图像
    figure;
    plot3(lambda_values, mse_values, num_selected_features, 'b-', 'LineWidth', 2);
    xlabel('λ值');
    ylabel('均方误差');
    zlabel('特征数量');
    title('λ值与均方误差以及特征数量的变化关系');
    grid on;
    
    
    
    % 绘制 λ 和平均误差曲线
    figure;
    semilogx(lambda_values, mse_values, 'b-', 'LineWidth', 2);
    xlabel('λ值');
    ylabel('均方误差');
    title('λ值与均方误差的变化关系');
    grid on;
    
    
    %计算ROC模型的相关参数
    [fpr, tpr, thresholds] = perfcurve(labels, Prediction_probability, 1);
    
    % 绘制 ROC 曲线
    figure;
    plot(fpr, tpr);
    xlabel('假阳性率 (FPR)');
    ylabel('真阳性率 (TPR)');
    title('Lasso回归模型下ROC 曲线');
    
    % 计算曲线下面积(AUC)
    auc = trapz(fpr, tpr);
    legend(['AUC = ' num2str(auc)]);
    
    
    %%    统计每次迭代后选择的特征的,然后出一个排名,迭代过程中出现最多次的特征认为是可靠的特征
    
    % 初始化一个空的结构数组
    unique_elements_struct = struct('value', {}, 'count', {});
    
    % 遍历每个单元格中的数组,统计每个元素出现的次数
    for i = 1:numel(selected_features_all)
        current_array = selected_features_all{i};
        unique_elements = unique(current_array);
        for j = 1:numel(unique_elements)
            element = unique_elements(j);
            idx = find([unique_elements_struct.value] == element);
            if isempty(idx)
                % 如果元素不在结构数组中,则添加它
                unique_elements_struct(end+1).value = element;
                unique_elements_struct(end).count = sum(current_array == element);
            else
                % 否则更新该元素的计数
                unique_elements_struct(idx).count = unique_elements_struct(idx).count + sum(current_array == element);
            end
        end
    end
    
    % 按照出现次数进行降序排序
    [~, sorted_indices] = sort([unique_elements_struct.count], 'descend');
    unique_elements_struct = unique_elements_struct(sorted_indices);
    
    % 显示结果
    for i = 1:numel(unique_elements_struct)
        disp(['Element ', num2str(unique_elements_struct(i).value), ' appeared ', num2str(unique_elements_struct(i).count), ' times.']);
    end