使用MATLAB对Indian Pines数据集进行PCA分类

1. 数据加载和预处理

% 清除环境
clear; close all; clc;

% 加载Indian Pines数据集
load('Indian_pines.mat'); % 加载高光谱数据
load('Indian_pines_gt.mat'); % 加载地面真实标签

% 查看数据信息
disp('数据信息:');
disp(['高光谱数据大小: ', num2str(size(indian_pines))]);
disp(['标签数据大小: ', num2str(size(indian_pines_gt))]);

% 将3D高光谱数据转换为2D矩阵 (像素数 × 波段数)
[num_rows, num_cols, num_bands] = size(indian_pines);
X = reshape(indian_pines, num_rows * num_cols, num_bands);
y = indian_pines_gt(:);

% 移除背景像素 (标签为0)
non_background = y ~= 0;
X_clean = X(non_background, :);
y_clean = y(non_background);

disp(['有效像素数量: ', num2str(length(y_clean))]);
disp(['波段数量: ', num2str(num_bands)]);
disp(['类别数量: ', num2str(length(unique(y_clean)))]);

2. 数据标准化和PCA分析

% 数据标准化
X_scaled = zscore(X_clean); % 标准化数据

% 计算协方差矩阵和特征值
cov_matrix = cov(X_scaled);
[eigenvectors, eigenvalues] = eig(cov_matrix);

% 按特征值大小排序
eigenvalues = diag(eigenvalues);
[eigenvalues, idx] = sort(eigenvalues, 'descend');
eigenvectors = eigenvectors(:, idx);

% 计算方差解释率
explained_variance = eigenvalues / sum(eigenvalues);
cumulative_variance = cumsum(explained_variance);

% 绘制方差解释率图
figure('Position', [100, 100, 1200, 500]);

subplot(1,2,1);
plot(explained_variance(1:50), 'b-o', 'LineWidth', 1.5, 'MarkerSize', 4);
xlabel('主成分序号');
ylabel('方差解释率');
title('各主成分方差解释率');
grid on;

subplot(1,2,2);
plot(cumulative_variance(1:50), 'r-o', 'LineWidth', 1.5, 'MarkerSize', 4);
hold on;
plot([1, 50], [0.95, 0.95], 'k--', 'LineWidth', 1.5);
xlabel('主成分数量');
ylabel('累计方差解释率');
title('累计方差解释率');
legend('累计方差', '95%阈值', 'Location', 'southeast');
grid on;

% 找到达到95%方差所需的主成分数量
n_components_95 = find(cumulative_variance >= 0.95, 1);
disp(['达到95%方差解释率所需的主成分数量: ', num2str(n_components_95)]);

3. PCA变换和特征提取

% 选择主成分数量
n_components_list = [5, 10, 15, 20, 30, 50];
results = struct();

for i = 1:length(n_components_list)
    n_comp = n_components_list(i);
    fprintf('\n使用 %d 个主成分进行处理...\n', n_comp);
    
    % 选择前n_comp个主成分
    selected_eigenvectors = eigenvectors(:, 1:n_comp);
    
    % 进行PCA变换
    X_pca = X_scaled * selected_eigenvectors;
    
    % 保存结果
    results(i).n_components = n_comp;
    results(i).X_pca = X_pca;
    results(i).eigenvectors = selected_eigenvectors;
    results(i).explained_variance = cumulative_variance(n_comp);
end

4. 使用分类器进行分类

% 设置随机种子确保结果可重现
rng(42);

% 准备不同数量的主成分数据进行分类
accuracy_results = zeros(length(n_components_list), 3); % [n_comp, SVM_acc, Tree_acc]

for i = 1:length(n_components_list)
    n_comp = results(i).n_components;
    X_pca = results(i).X_pca;
    
    fprintf('\n=== 使用 %d 个主成分进行分类 ===\n', n_comp);
    
    % 分割数据集 (70%训练, 30%测试)
    cv = cvpartition(y_clean, 'HoldOut', 0.3);
    idx_train = training(cv);
    idx_test = test(cv);
    
    X_train = X_pca(idx_train, :);
    X_test = X_pca(idx_test, :);
    y_train = y_clean(idx_train);
    y_test = y_clean(idx_test);
    
    % 方法1: 使用SVM分类器
    fprintf('训练SVM分类器...\n');
    svm_model = fitcecoc(X_train, y_train, ...
                        'Learners', 'svm', ...
                        'Coding', 'onevsone', ...
                        'Verbose', 0);
    
    % 预测
    y_pred_svm = predict(svm_model, X_test);
    accuracy_svm = sum(y_pred_svm == y_test) / length(y_test);
    
    % 方法2: 使用决策树分类器
    fprintf('训练决策树分类器...\n');
    tree_model = fitctree(X_train, y_train);
    
    % 预测
    y_pred_tree = predict(tree_model, X_test);
    accuracy_tree = sum(y_pred_tree == y_test) / length(y_test);
    
    % 保存结果
    accuracy_results(i, :) = [n_comp, accuracy_svm, accuracy_tree];
    
    fprintf('SVM准确率: %.4f\n', accuracy_svm);
    fprintf('决策树准确率: %.4f\n', accuracy_tree);
    
    % 保存每个结果的详细预测
    results(i).y_test = y_test;
    results(i).y_pred_svm = y_pred_svm;
    results(i).y_pred_tree = y_pred_tree;
    results(i).accuracy_svm = accuracy_svm;
    results(i).accuracy_tree = accuracy_tree;
end

5. 结果可视化和分析

% 绘制分类准确率随主成分数量的变化
figure('Position', [100, 100, 1000, 600]);

subplot(2,2,1);
plot(accuracy_results(:,1), accuracy_results(:,2), 'o-', 'LineWidth', 2, 'MarkerSize', 8);
hold on;
plot(accuracy_results(:,1), accuracy_results(:,3), 's-', 'LineWidth', 2, 'MarkerSize', 8);
xlabel('主成分数量');
ylabel('分类准确率');
title('分类准确率 vs 主成分数量');
legend('SVM', '决策树', 'Location', 'southeast');
grid on;

% 找到最佳结果
[best_svm_acc, best_svm_idx] = max(accuracy_results(:,2));
[best_tree_acc, best_tree_idx] = max(accuracy_results(:,3));

best_n_comp_svm = accuracy_results(best_svm_idx, 1);
best_n_comp_tree = accuracy_results(best_tree_idx, 1);

fprintf('\n=== 最佳结果总结 ===\n');
fprintf('SVM最佳准确率: %.4f (使用 %d 个主成分)\n', best_svm_acc, best_n_comp_svm);
fprintf('决策树最佳准确率: %.4f (使用 %d 个主成分)\n', best_tree_acc, best_n_comp_tree);

% 绘制最佳结果的混淆矩阵
subplot(2,2,2);
best_result = results(best_svm_idx);
cm = confusionmat(best_result.y_test, best_result.y_pred_svm);
imagesc(cm);
colorbar;
xlabel('预测标签');
ylabel('真实标签');
title(sprintf('SVM混淆矩阵 (%d个主成分)', best_n_comp_svm));

% 绘制特征空间前2个主成分的散点图
subplot(2,2,3);
if size(results(1).X_pca, 2) >= 2
    scatter(results(1).X_pca(:,1), results(1).X_pca(:,2), 20, y_clean, 'filled');
    xlabel('第一主成分');
    ylabel('第二主成分');
    title('前两个主成分的特征空间');
    colorbar;
end

% 绘制计算效率比较
subplot(2,2,4);
training_time = zeros(length(n_components_list), 2);
for i = 1:length(n_components_list)
    n_comp = results(i).n_components;
    X_pca = results(i).X_pca;
    
    % SVM训练时间
    tic;
    svm_model = fitcecoc(X_pca(training(cv), :), y_clean(training(cv)), 'Verbose', 0);
    training_time(i, 1) = toc;
    
    % 决策树训练时间
    tic;
    tree_model = fitctree(X_pca(training(cv), :), y_clean(training(cv)));
    training_time(i, 2) = toc;
end

plot(accuracy_results(:,1), training_time(:,1), 'o-', 'LineWidth', 2);
hold on;
plot(accuracy_results(:,1), training_time(:,2), 's-', 'LineWidth', 2);
xlabel('主成分数量');
ylabel('训练时间(秒)');
title('训练时间比较');
legend('SVM', '决策树');
grid on;

% 保存重要结果
save('pca_classification_results.mat', 'results', 'accuracy_results', 'n_components_list');

6. 高级分析:不同分类器比较

% 使用最佳主成分数量进行更详细的分类器比较
fprintf('\n=== 详细分类器比较 ===\n');

best_n_comp = best_n_comp_svm;
best_idx = find([results.n_components] == best_n_comp);
X_pca_best = results(best_idx).X_pca;

% 准备多种分类器
classifiers = {
    'SVM (线性)', @(X,y) fitcecoc(X, y, 'Learners', 'linear', 'Verbose', 0);
    'SVM (RBF)', @(X,y) fitcecoc(X, y, 'Learners', 'svm', 'Verbose', 0);
    '决策树', @fitctree;
    'k-NN (k=5)', @(X,y) fitcknn(X, y, 'NumNeighbors', 5);
    '随机森林', @(X,y) TreeBagger(50, X, y, 'Method', 'classification');
};

classifier_names = classifiers(:,1);
classifier_funcs = classifiers(:,2);

classifier_results = cell(length(classifier_names), 3);

for i = 1:length(classifier_names)
    fprintf('训练 %s...\n', classifier_names{i});
    
    try
        % 训练分类器
        if i == 5 % 随机森林特殊处理
            model = classifier_funcs{i}(X_pca_best(idx_train, :), y_train);
            y_pred = predict(model, X_pca_best(idx_test, :));
            y_pred = str2double(y_pred);
        else
            model = classifier_funcs{i}(X_pca_best(idx_train, :), y_train);
            y_pred = predict(model, X_pca_best(idx_test, :));
        end
        
        accuracy = sum(y_pred == y_test) / length(y_test);
        classifier_results{i, 1} = classifier_names{i};
        classifier_results{i, 2} = accuracy;
        classifier_results{i, 3} = y_pred;
        
        fprintf('%s 准确率: %.4f\n', classifier_names{i}, accuracy);
    catch ME
        fprintf('训练 %s 时出错: %s\n', classifier_names{i}, ME.message);
        classifier_results{i, 1} = classifier_names{i};
        classifier_results{i, 2} = NaN;
        classifier_results{i, 3} = [];
    end
end

% 显示最终结果表格
fprintf('\n=== 最终结果总结 ===\n');
fprintf('%-15s %-10s\n', '分类器', '准确率');
fprintf('%-15s %-10s\n', '-------', '------');
for i = 1:size(classifier_results, 1)
    if ~isnan(classifier_results{i, 2})
        fprintf('%-15s %.4f\n', classifier_results{i, 1}, classifier_results{i, 2});
    end
end

参考代码 PCA_进行indian_pines数据集合分类 www.3dddown.com/cna/59763.html

使用

  1. 数据准备:确保Indian_pines.matIndian_pines_gt.mat文件在当前工作目录中
  2. 运行顺序:按顺序执行各个代码段
  3. 参数调整:可以修改n_components_list来测试不同的主成分数量
  4. 分类器选择:代码提供了多种分类器供比较
posted @ 2025-12-16 09:54  yijg9998  阅读(3)  评论(0)    收藏  举报