K均值与PCA的关系

0 投票
2 回答
524 浏览
提问于 2025-04-17 20:21

根据我的理解,模式识别中的PCA(主成分分析)是用来去掉数据集中不必要的数据的。这样,当我们用这个数据集进行K均值聚类时,效果会比没有用PCA处理过的数据集要好。所以,我可以写出类似这样的代码(伪代码):

 assign .csv to var DATA
 PCA_DATA = PCAcompute(DATA)
 result = Kmean(PCA_DATA)
 plotToGraph(result)

我这样理解对吗?

我已经找了快一个月的时间,想找一些示例程序,看看怎么导入一个csv文件,然后用PCA进行聚类。我的目标是比较一下用鸢尾花数据集进行K均值聚类的结果和用PCA处理过的数据集进行K均值聚类的结果。

2 个回答

0

我有点搞不懂你说的话。

首先,PCA是主成分分析的缩写。这是一个处理高维数据的过程,它试图找到一个低维的(超)平面,让这些数据几乎都能落在上面。简单来说,就是把不必要的维度去掉。

你提到的KMean,可能是指k-means聚类。在低维空间中,这种方法运行得快得多,所以用PCA来减少维度是个不错的选择。

(在Stack Overflow上,程序请求是不允许的)

0

我没有使用KMean,而是用PCA来处理我的神经网络训练数据,以减少特征数量。这是在OpenCV的C++接口中实现的。我们先来读取一个csv文件。我的csv文件大概是这样的:

im_path_1;label1  
im_path_2;label2

为了读取这个csv文件,我写了一个函数:

void read_csv(const string& filename, vector& images, vector& labels, char separator = ';') 
{
    std::ifstream file(filename.c_str(), ifstream::in);
    if (!file) 
    {
        string error_message = "No valid input file was given, please check the given filename.";
        CV_Error(1, error_message);
    }
    string line, path, classlabel;
    while (getline(file, line)) 
    {
        stringstream liness(line);

        getline(liness, path, separator);
        getline(liness, classlabel);

        if(!path.empty() && !classlabel.empty()) 
        {
            Mat im = imread(path, 0);

            images.push_back(im);
            labels.push_back(atoi(classlabel.c_str()));
        }
    }
}

这个函数会把数据存储在一个Mat变量的向量中。OpenCV的PCA要求数据以行向量的形式放在Mat变量里。为了做到这一点:

Mat rollVectortoMat(const vector<Mat> &data)
{
   Mat dst(static_cast<int>(data.size()), data[0].rows*data[0].cols, CV_32FC1);
   for(unsigned int i = 0; i < data.size(); i++)
   {
      Mat image_row = data[i].clone().reshape(1,1);
      Mat row_i = dst.row(i);                                       
      image_row.convertTo(row_i,CV_32FC1, 1/255.);
   }
   return dst;
}

这是这个函数的简单用法:

int main()
{

    PCA pca;

    vector<Mat> images_train;
    vector<int> labels_train;

    read_csv("train1k.txt",images_train,labels_train);

    Mat rawTrainData = rollVectortoMat(images_train);   

    int pca_size = 500;

    Mat trainData(rawTrainData.rows, pca_size,rawTrainData.type());
    Mat testData(rawTestData.rows,pca_size,rawTestData.type());


    pca(rawTrainData,Mat(),CV_PCA_DATA_AS_ROW,pca_size);

    for(int i = 0; i < rawTrainData.rows ; i++)
        pca.project(rawTrainData.row(i),trainData.row(i));

    cout<<trainData.size()<<endl;

    return 0;
}

trainData变量是经过处理后的训练集版本。至于pca_size变量,你可以把它设置为0.95,这样可以保留95%的方差,而不是用500。希望这对PCA部分有帮助。我用这个减少后的数据来训练神经网络。

撰写回答