聊聊基于Alink库的主成分分析(PCA)

概述

主成分分析(Principal Component Analysis,PCA)是一种常用的数据降维和特征提取技术,用于将高维数据转换为低维的特征空间。其目标是通过线性变换将原始特征转化为一组新的互相无关的变量,这些新变量称为主成分,它们按照方差递减的顺序排列,以保留尽可能多的原始数据信息。
主成分分析的基本思想可以总结如下:

  1. 寻找新的特征空间:PCA通过线性变换,寻找一组新的特征空间,使得新的特征具有以下性质:
    • 主成分具有最大的方差,尽可能保留原始数据的信息。
    • 不同主成分之间彼此无关,即它们是正交的(互相垂直)。
  2. 降低数据维度:保留方差较大的主成分,舍弃方差较小的主成分,从而实现数据降维。

主成分分析的步骤如下:

  • 中心化数据:将原始数据进行中心化,使得数据的均值为零。
  • 计算协方差矩阵:计算特征之间的协方差矩阵,描述了特征之间的线性关系。
  • 计算特征值和特征向量:对协方差矩阵进行特征值分解,得到特征值和对应的特征向量。
  • 选择主成分:按照特征值的大小选择保留的主成分数量,通常选择方差较大的前几个主成分。
  • 得到新的特征空间:将原始特征投影到选定的主成分上,得到新的特征空间。

主成分分析的应用包括降维、去除数据噪声、数据可视化、特征选择等。通过保留最重要的特征,可以在减少数据维度的同时保持对数据的关键信息进行捕获。
在实际使用中,有时会将各个变量进行标准化,此时的协方差矩阵就相当于原始数据的相关系数矩阵。所以Alink的主成分分析组件提供了两种计算选择,参数CalculationType可以设置为相关系数矩阵(CORR)或者协方差矩阵(COV),默认为相关系数矩阵,即对标准化后的数据计算其主成分。

Alink库中的实现与应用

示例

以美国50个州的7种犯罪率为例,做主成分分析。这7种犯罪分别是:"murder", "rape", "robbery", "assault", "burglary", "larceny", "auto"。从这7个变量出发来评价各州的治安和犯罪情况是很难的,而使用主成分分析可以把这些变量概括为2-3个综合变量(即主成分),便于更简便的分析这些数据。

/**  * 主成分分析  * 1.基于默认的计算方式(CORR),计算主成分  * 2.设置K为4,将原先的7个维度降低到4个维度  * 3.输出向量列,使用VectorToColumnsBatchOp组组件将向量列转为4个数据列,名称分别为"prin1, prin2, prin3, prin4"  * */ static void c_1() throws Exception {      MemSourceBatchOp source = new MemSourceBatchOp(CRIME_ROWS_DATA, CRIME_COL_NAMES);      source.lazyPrint(10, "Origin data");      BatchOperator <?> pca_result = new PCA()         .setK(4)         .setSelectedCols("murder", "rape", "robbery", "assault", "burglary", "larceny", "auto")         .setPredictionCol(VECTOR_COL_NAME)         .enableLazyPrintModelInfo()         .fit(source)         .transform(source)         .link(             new VectorToColumnsBatchOp()                 .setVectorCol(VECTOR_COL_NAME)                 .setSchemaStr("prin1 double, prin2 double, prin3 double, prin4 double")                 .setReservedCols("state")         )         .lazyPrint(10, "state with principle components");      pca_result         .select("state, prin1")         .orderBy("prin1", 100, false)         .lazyPrint(-1, "Order by prin1");      pca_result         .select("state, prin2")         .orderBy("prin2", 100, false)         .lazyPrint(-1, "Order by prin2");      BatchOperator.execute();  } 

当然还可以先将数据标准化后再做主成分分析。如下

/**  * 主成分分析  * 1. 先将数据标准化  * 2. 设置计算方式为协方差计算,设置K为4,将原先的7个维度降低到4个维度  * 3.输出向量列,使用VectorToColumnsBatchOp组组件将向量列转为4个数据列,名称分别为"prin1, prin2, prin3, prin4"  * */ static void c_2() throws Exception {      MemSourceBatchOp source = new MemSourceBatchOp(CRIME_ROWS_DATA, CRIME_COL_NAMES);      Pipeline std_pca = new Pipeline()         .add(             new StandardScaler()                 .setSelectedCols("murder", "rape", "robbery", "assault", "burglary", "larceny", "auto")         )         .add(             new PCA()                 .setCalculationType(CalculationType.COV)                 .setK(4)                 .setSelectedCols("murder", "rape", "robbery", "assault", "burglary", "larceny", "auto")                 .setPredictionCol(VECTOR_COL_NAME)                 .enableLazyPrintModelInfo()         );      std_pca         .fit(source)         .transform(source)         .link(             new VectorToColumnsBatchOp()                 .setVectorCol(VECTOR_COL_NAME)                 .setSchemaStr("prin1 double, prin2 double, prin3 double, prin4 double")                 .setReservedCols("state")         )         .lazyPrint(10, "state with principle components");     BatchOperator.execute();  } 

应用

在聚类方面的应用

主要通过降维来减少特征的维度,从而在聚类过程中降低数据的复杂度和计算成本,同时提高聚类的效果。主要实现过程如下:

  1. 使用 PCA 对数据进行降维,得到新的特征空间。设置降维后的维度,通常选择较小的维度以减少特征数。
  2. 在降维后的特征空间上应用聚类算法,比如 K-means、DBSCAN 等。
  3. 使用适当的聚类评估指标,如轮廓系数等,来评估聚类的效果。

示例代码如下:

/**  * 聚类+主成分分析  * 1. 将数据降维,只使用5%的维度数据  * 2. K-Means聚类:分别将原始数据与主成分分析后的数据做聚类操作  * */ static void c_3() throws Exception {      AkSourceBatchOp source = new AkSourceBatchOp().setFilePath(DATA_DIR + SPARSE_TRAIN_FILE);      source         .link(             new PcaTrainBatchOp()                 .setK(39)                 .setCalculationType(CalculationType.COV)                 .setVectorCol(VECTOR_COL_NAME)                 .lazyPrintModelInfo()         )         .link(             new AkSinkBatchOp()                 .setFilePath(DATA_DIR + PCA_MODEL_FILE)                 .setOverwriteSink(true)         );     BatchOperator.execute();      BatchOperator <?> pca_result = new PcaPredictBatchOp()         .setVectorCol(VECTOR_COL_NAME)         .setPredictionCol(VECTOR_COL_NAME)         .linkFrom(             new AkSourceBatchOp().setFilePath(DATA_DIR + PCA_MODEL_FILE),             source         );      Stopwatch sw = new Stopwatch();      KMeans kmeans = new KMeans()         .setK(10)         .setVectorCol(VECTOR_COL_NAME)         .setPredictionCol(PREDICTION_COL_NAME);      sw.reset();     sw.start();     kmeans         .fit(source)         .transform(source)         .link(             new EvalClusterBatchOp()                 .setVectorCol(VECTOR_COL_NAME)                 .setPredictionCol(PREDICTION_COL_NAME)                 .setLabelCol(LABEL_COL_NAME)                 .lazyPrintMetrics("KMeans")         );     BatchOperator.execute();     sw.stop();     System.out.println(sw.getElapsedTimeSpan());      sw.reset();     sw.start();     kmeans         .fit(pca_result)         .transform(pca_result)         .link(             new EvalClusterBatchOp()                 .setVectorCol(VECTOR_COL_NAME)                 .setPredictionCol(PREDICTION_COL_NAME)                 .setLabelCol(LABEL_COL_NAME)                 .lazyPrintMetrics("KMeans + PCA")         );     BatchOperator.execute();     sw.stop();     System.out.println(sw.getElapsedTimeSpan());  } 

发表评论

评论已关闭。

相关文章