> library(pacman)
> p_load(dplyr, ggplot2, GGally, factoextra)
为何要降维?方便可视化探索;减轻维度诅咒;缓解共线性。
降维方法:PCA, t-SNE, UMAP, SOM, LLE
1、主成分分析PCA
主成分分析(Principal Component Analysis, 简写PCA)是将多个指标化为少数几个综合指标的一种统计分析方法,实质是一种降维技术, 利用正交变换把一系列可能线性相关的变量转换为一组线性不相关的新变量,也称为主成分,从而利用新变量在更小的维度下展示数据的特征。
原理:在诸多变量中,有很多变量是相关的,重新组合成一组新的相互无关的综合指标,并代替原来的指标。
数据:mclust包中的真钞与假钞数据集。
> # 加载数据集
> note <- as_tibble(mclust::banknote)
> # 查看数据结构
> str(note)
## tibble [200 × 7] (S3: tbl_df/tbl/data.frame)
## $ Status : Factor w/ 2 levels "counterfeit",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ Length : num [1:200] 215 215 215 215 215 ...
## $ Left : num [1:200] 131 130 130 130 130 ...
## $ Right : num [1:200] 131 130 130 130 130 ...
## $ Bottom : num [1:200] 9 8.1 8.7 7.5 10.4 9 7.9 7.2 8.2 9.2 ...
## $ Top : num [1:200] 9.7 9.5 9.6 10.4 7.7 10.1 9.6 10.7 11 10 ...
## $ Diagonal: num [1:200] 141 142 142 142 142 ...
> # 检查缺失值
> DataExplorer::profile_missing(note)
## # A tibble: 7 x 3
## feature num_missing pct_missing
## <fct> <int> <dbl>
## 1 Status 0 0
## 2 Length 0 0
## 3 Left 0 0
## 4 Right 0 0
## 5 Bottom 0 0
## 6 Top 0 0
## 7 Diagonal 0 0
各自变量与因变量(Status)之间、各自变量之间的相关性、分布情况。
> ggpairs(note, aes(col = Status), axisLabels = "none",
+ upper = list(continuous = ggally_density, combo = ggally_box_no_facet)) +
+ theme_bw()
PCA降维,是否需要中心话和标准化?
如果关注的是每个变量自身的实际方差对样品分类的贡献,则不应该SCALE;如果关注的是变量的相对大小对样品分类的贡献,则应该SCALE,以防数值高的变量导入的大方差引入的偏见,即消除量纲的影响。
注意:
(https://www.plob.org/article/11869.html)
1,一般说来,在PCA之前原始数据需要中心化(centering,数值减去平均值)。中心化的方法很多,除了平均值中心化(mean-centering)外,还包括其它更稳健的方法,比如中位数中心化等。
2,除了中心化以外,定标 (Scale, 数值除以标准差) 也是数据前处理中需要考虑的一点。如果数据没有定标,则原始数据中方差大的变量对主成分的贡献会很大。数据的方差与其量级成指数关系,比如一组数据(1,2,3,4)的方差是1.67,而(10,20,30,40)的方差就是167,数据变大10倍,方差放大了100倍。
3,但是定标(scale)可能会有一些负面效果,因为定标后变量之间的权重就变得相同。如果变量中有噪音的话,就在无形中把噪音和信息的权重变得相同,但PCA本身无法区分信号和噪音。在这样的情形下,就不必做定标。
4,一般而言,对于度量单位不同的指标或是取值范围彼此差异非常大的指标不直接由其协方差矩阵出发进行主成分分析,而应该考虑对数据的标准化。比如度量单位不同,有万人、万吨、万元、亿元,而数据间的差异性也非常大,小则几十大则几万,因此在用协方差矩阵求解主成分时存在协方差矩阵中数据的差异性很大。在后面提取主成分时发现,只提取了一个主成分,而此时并不能将所有的变量都解释到,这就没有真正起到降维的作用。此时就需要对数据进行定标(scale),这样提取的主成分可以覆盖更多的变量,这就实现主成分分析的最终目的。但是对原始数据进行标准化后更倾向于使得各个指标的作用在主成分分析构成中相等。对于数据取值范围不大或是度量单位相同的指标进行标准化处理后,其主成分分析的结果与仍由协方差矩阵出发求得的结果有较大区别。这是因为对数据标准化的过程实际上就是抹杀原有变量离散程度差异的过程,标准化后方差均为1,而实际上方差是对数据信息的重要概括形式,也就是说,对原始数据进行标准化后抹杀了一部分重要信息,因此才使得标准化后各变量在主成分构成中的作用趋于相等。因此,对同度量或是取值范围在同量级的数据还是直接使用非定标数据求解主成分为宜。
5,中心化和定标都会受数据中离群值(outliers)或者数据不均匀(比如数据被分为若干个小组)的影响,应该用更稳健的中心化和定标方法。
> pca <- note %>%
+ # 去掉因变量
+ select(-Status) %>%
+ # 数据中心化和标准化,消除数据量纲不同的影响
+ prcomp(center = T, scale = T)
>
> pca
## Standard deviations (1, .., p=6):
## [1] 1.7162629 1.1305237 0.9322192 0.6706480 0.5183405 0.4346031
##
## Rotation (n x k) = (6 x 6):
## PC1 PC2 PC3 PC4 PC5 PC6
## Length 0.006987029 -0.81549497 0.01768066 0.5746173 -0.0587961 0.03105698
## Left -0.467758161 -0.34196711 -0.10338286 -0.3949225 0.6394961 -0.29774768
## Right -0.486678705 -0.25245860 -0.12347472 -0.4302783 -0.6140972 0.34915294
## Bottom -0.406758327 0.26622878 -0.58353831 0.4036735 -0.2154756 -0.46235361
## Top -0.367891118 0.09148667 0.78757147 0.1102267 -0.2198494 -0.41896754
## Diagonal 0.493458317 -0.27394074 -0.11387536 -0.3919305 -0.3401601 -0.63179849
> summary(pca)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6
## Standard deviation 1.7163 1.1305 0.9322 0.67065 0.51834 0.43460
## Proportion of Variance 0.4909 0.2130 0.1448 0.07496 0.04478 0.03148
## Cumulative Proportion 0.4909 0.7039 0.8488 0.92374 0.96852 1.00000
经过主成分分析后,六个自变量变为了PC1到PC6,累积方差解释比(Cumulative Proportion)依次为0.4909、0.7039、0.8488、0.92374、0.96852、1.00000,意思是如果只选择PC1到PC4四个变量,但是却能解释整个数据方差的92.374%,从而达到降维的目的。
成功的降维需要保证在前几个为数不多的主成分对数据差异的解释可以达到80-90%。后面的建模直接使用PC1到PC4的数据,而不再使用原始数据。
> # 主成分构成的新矩阵
> pca$rotation
## PC1 PC2 PC3 PC4 PC5 PC6
## Length 0.006987029 -0.81549497 0.01768066 0.5746173 -0.0587961 0.03105698
## Left -0.467758161 -0.34196711 -0.10338286 -0.3949225 0.6394961 -0.29774768
## Right -0.486678705 -0.25245860 -0.12347472 -0.4302783 -0.6140972 0.34915294
## Bottom -0.406758327 0.26622878 -0.58353831 0.4036735 -0.2154756 -0.46235361
## Top -0.367891118 0.09148667 0.78757147 0.1102267 -0.2198494 -0.41896754
## Diagonal 0.493458317 -0.27394074 -0.11387536 -0.3919305 -0.3401601 -0.63179849
> # 每个主成分可以解释的数据差异
> # 特征值eigenvalues = (pca$sdev)^2
> pca$sdev
## [1] 1.7162629 1.1305237 0.9322192 0.6706480 0.5183405 0.4346031
2、可视化
factoextra包可视化:
> # 双标图
> fviz_pca_biplot(pca, label = "var")
在空间上,PCA可以理解为把原始数据投射到一个新的坐标系统,第一主成分为第一坐标轴(Dim1),它的含义代表了原始数据中多个变量经过某种变换得到的新变量的变化区间;第二成分为第二坐标轴(Dim2),代表了原始数据中多个变量经过某种变换得到的第二个新变量的变化区间。这样我们把利用原始数据解释样品的差异转变为利用新变量解释样品的差异。
这种投射方式会有很多,为了最大限度保留对原始数据的解释,一般会用最大方差理论或最小损失理论,使得第一主成分有着最大的方差或变异数 (就是说其能尽量多的解释原始数据的差异);随后的每一个主成分都与前面的主成分正交,且有着仅次于前一主成分的最大方差 (正交简单的理解就是两个主成分空间夹角为90°,两者之间无线性关联,从而完成去冗余操作)。
> # 变量负载图
> fviz_pca_var(pca)
在合并冗余原始变量得到主成分过程中,会发现某些原始变量对同一主成分有着相似的贡献,也就是说这些变量之间存在着某种相关性,为相关变量。同时也可以获得这些变量对主成分的贡献程度。
> # 特征值碎石图,一般选择方差大于1的主成分
> fviz_screeplot(pca, addlabels = T, choice = "eigenvalue")
> # 方差比例碎石图,一般选择总方差大于80%
> fviz_screeplot(pca, addlabels = T, choice = "variance")
前两个主成分与因变量之间的关系:
> notepca <- pca$x %>%
+ # 选择前两个主成分
+ .[, 1:2] %>%
+ # 加入因变量
+ bind_cols(Status = note$Status) %>%
+ # 重新设置列名
+ setNames(c("PCA1", "PCA2", "Status"))
>
> # 画图
> ggplot(notepca, aes(PCA1, PCA2, col = Status)) +
+ geom_point(size = 1) +
+ theme_bw() +
+ theme(legend.position = "top")
红色表示假钞,蓝色表示真钞。
3、应用PCA
如果新来了两张钞票,可以通过可视化辨别是真钞还是假钞。
> newnote <- tibble(
+ Length = c(214, 216),
+ Left = c(130, 128),
+ Right = c(132, 129),
+ Bottom = c(12, 7),
+ Top = c(12, 8),
+ Diagonal = c(138, 142)) %>%
+ # 预测
+ predict(pca, newdata = .) %>%
+ # 转换为tibble
+ as_tibble()
>
> newnote
## # A tibble: 2 x 6
## PC1 PC2 PC3 PC4 PC5 PC6
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 -4.73 2.00 -0.106 -1.66 -3.20 1.62
## 2 6.47 -0.892 -0.821 3.47 -1.84 2.34
> ggplot(notepca, aes(PCA1, PCA2, col = Status)) +
+ geom_point(size = 1) +
+ # 添加椭圆框
+ stat_ellipse(level = 0.9) +
+ # 显示新的数据
+ geom_point(data = newnote, aes(PC1, PC2), col = "black", shape = 2) +
+ theme_bw() +
+ theme(legend.position = "top")
4、PCA的优劣
优势:
1,直接利用原有变量建立新轴;
2,新数据可以直接投影;
3,纯数学变换,计算量不大。
劣势:
1,高维到低维可能非线性;
2,无法处理分类变量;
3,降低维度需要人工判断。