美文网首页模型R语言
数量生态学笔记||线性判别式分析(LDA)

数量生态学笔记||线性判别式分析(LDA)

作者: 周运来就是我 | 来源:发表于2018-10-14 11:01 被阅读296次

    线性判别式分析(linear discriminant analysis , LDA)跟PCA非常相似、唯一不同的是LDA的结果是将数据投影到不同分类、PCA的结果是将数据投影到最高相似分组,而且过程无一例外的都基于特征值与特性向量实现降维处理。PCA变换基于在原数据与调整之后估算降维的数据之间最小均方错误,PCA趋向提取数据最大相同特征、而忽视数据之间微小不同特征、所以如果在OCR识别上使用PCA的方法就很难分辨Q与O个英文字母、而LDA基于最大类间方差与最小类内方差,其目的是减少分类内部之间差异,扩大不同分类之间差异。所以LDA在一些应用场景中有比PCA更好的表现。

    LDA与RDA和CCA的不同之处是其响应变量是样方的分组情况。LDA的目的是确定一套独立的定量解释变量能够能够多大程度上解释当前样方的分组结果。LDA需要从标准化的解释变量计算判别函数。判别函数值用于量化的解释变量对于对象分组的相对贡献。另外,通过原始的解释变量计算的判别函数称为识别函数,目的是判断新的对象应该归于哪一组。

    运行LDA是必须保证解释变量组内协方差矩阵齐性,但生态数据通常无法满足这个条件。

    核心:向最大化类间差异、最小化类内差异的方向线性投影

    线性鉴别分析的基本思想是通过线性投影来最小化同类样本间的差异,最大化不同类样本间的差异。具体做法是寻找一个向低维空间的投影矩阵W,样本的特征向量x经过投影之后得到的新向量:

    y = Wx

    同一类样投影后的结果向量差异尽可能小,不同类的样本差异尽可能大。直观来看,就是经过这个投影之后同一类的样本进来聚集在一起,不同类的样本尽可能离得远。下图是这种投影的示意图:


    上图中特征向量是二维的,我们向一维空间即直线投影,投影后这些点位于直线上。在上面的图中有两类样本,通过向右上方的直线投影,两类样本被有效的分开了。绿色的样本投影之后位于直线的下半部分,红色的样本投影之后位于直线的上半部分。

    训练时的优化目标是类间差异与类内差异的比值:

    最后归结于求解矩阵的特征值与特征向量:

    LDA是有监督的机器学习算法,在计算过程中利用了样本标签值。这是一种判别模型,也是线性模型。LDA也不能直接用于分类和回归问题,要对降维后的向量进行分类还需要借助其他算法,如kNN。

    library(ade4)
    library(vegan)
    #library(packfor)
    rm(list = ls())
    setwd("D:\\Users\\Administrator\\Desktop\\RStudio\\数量生态学\\DATA")
    # 此程序包可以从 https://r-forge.r-project.org/R/?group_id=195 下载
    # 如果是MacOS X系统,packfor程序包内forward.sel函数的运行需要加载
    # gfortran程序包。用户必须从"cran.r-project.org"网站内选择"MacOS X",
    # 然后选择"tools"安装gfortran程序包。
    library(MASS)
    library(ellipse)
    library(FactoMineR)
    # 附加函数
    source("evplot.R")
    source("hcoplot.R")
    # 导入CSV数据文件
    spe <- read.csv("DoubsSpe.csv", row.names=1)
    env <- read.csv("DoubsEnv.csv", row.names=1)
    spa <- read.csv("DoubsSpa.csv", row.names=1)
    # 删除没有数据的样方8
    spe <- spe[-8, ]
    env <- env[-8, ]
    spa <- spa[-8, ]
    # 提取环境变量das(离源头距离)以备用
    das <- env[, 1]
    # 从环境变量矩阵剔除das变量
    env <- env[, -1]
    spe.hel <- decostand(spe, "hellinger")
    
    > # 线性判别式分析(LDA)
    > # *******************
    > # 基于Hellinger转化鱼类数据的样方Ward聚类分析(分4组)
    > gr <- cutree(hclust(vegdist(spe.hel, "euc"), "ward.D"), 4)  #如果之前没有保存gr
    > # 线性判别式分析(LDA)
    > # *******************
    > # 基于Hellinger转化鱼类数据的样方Ward聚类分析(分4组)
    > gr <- cutree(hclust(vegdist(spe.hel, "euc"), "ward.D"), 4)  #如果之前没有保存gr
    > env.pars2 <- as.matrix(env[, c(1, 9, 10)])
    > # 使用函数betadisper()(vegan包)(Marti Anderson检验)验证解释变量组内# 协方差矩阵的齐性
    > env.pars2.d1 <- dist(env.pars2)
    > (env.MHV <- betadisper(env.pars2.d1, gr))
    
        Homogeneity of multivariate dispersions
    
    Call: betadisper(d = env.pars2.d1, group = gr)
    
    No. of Positive Eigenvalues: 3
    No. of Negative Eigenvalues: 0
    
    Average distance to median:
          1       2       3       4 
    197.458 215.135  32.645   5.845 
    
    Eigenvalues for PCoA axes:
           PCoA1        PCoA2        PCoA3         <NA>         <NA>         <NA>         <NA>         <NA> 
    2036227.3390     442.1009      31.4911           NA           NA           NA           NA           NA 
    > anova(env.MHV)
    Analysis of Variance Table
    
    Response: Distances
              Df Sum Sq Mean Sq F value   Pr(>F)   
    Groups     3 226555   75518  4.9758 0.007641 **
    Residuals 25 379427   15177                    
    ---
    Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
    > permutest(env.MHV) #置换检验
    
    Permutation test for homogeneity of multivariate dispersions
    Permutation: free
    Number of permutations: 999
    
    Response: Distances
              Df Sum Sq Mean Sq      F N.Perm Pr(>F)   
    Groups     3 226555   75518 4.9758    999  0.008 **
    Residuals 25 379427   15177                        
    ---
    Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
    > #组内协方差矩阵不齐,需要对alt和dbo两个变量进行对数化
    > env.pars3 <- cbind(log(env$alt), env$oxy, log(env$dbo))
    > colnames(env.pars3) <- c("alt.ln", "oxy", "dbo.ln")
    > row.names(env.pars3) <- row.names(env)
    > env.pars3.d1 <- dist(env.pars3)
    > (env.MHV2 <- betadisper(env.pars3.d1, gr))
    
        Homogeneity of multivariate dispersions
    
    Call: betadisper(d = env.pars3.d1, group = gr)
    
    No. of Positive Eigenvalues: 3
    No. of Negative Eigenvalues: 0
    
    Average distance to median:
         1      2      3      4 
    0.9153 1.1817 1.0133 0.7599 
    
    Eigenvalues for PCoA axes:
       PCoA1    PCoA2    PCoA3     <NA>     <NA>     <NA>     <NA>     <NA> 
    146.6682   6.6185   2.4819       NA       NA       NA       NA       NA 
    > permutest(env.MHV2)
    
    Permutation test for homogeneity of multivariate dispersions
    Permutation: free
    Number of permutations: 999
    
    Response: Distances
              Df  Sum Sq Mean Sq      F N.Perm Pr(>F)
    Groups     3  0.5337 0.17790 0.2795    999  0.836
    Residuals 25 15.9136 0.63654                     
    > #组内协方差矩阵显示齐性,可以继续分析
    > # LDA计算(判别函数)
    > env.pars3.df <- as.data.frame(env.pars3)
    > gr
     1  2  3  4  5  6  7  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 
     1  1  1  2  2  2  1  2  1  1  1  1  1  2  2  2  2  2  3  3  3  4  4  4  3  3  3  3  3 
    > head(env.pars3.df)
        alt.ln  oxy    dbo.ln
    1 6.839476 12.2 0.9932518
    2 6.837333 10.3 0.6418539
    3 6.817831 10.5 1.2527630
    4 6.749931 11.0 0.2623643
    5 6.744059  8.0 1.8245493
    6 6.740519 10.2 1.6677068
    > (spe.lda <- lda(gr ~ alt.ln + oxy + dbo.ln, data=env.pars3.df))
    Call:
    lda(gr ~ alt.ln + oxy + dbo.ln, data = env.pars3.df)
    
    Prior probabilities of groups:
            1         2         3         4 
    0.3103448 0.3103448 0.2758621 0.1034483 
    
    Group means:
        alt.ln       oxy   dbo.ln
    1 6.464881 11.388889 1.048586
    2 6.245151  9.944444 1.209785
    3 5.385688  8.387500 1.557074
    4 5.477515  5.200000 2.707430
    
    Coefficients of linear discriminants:
                  LD1        LD2        LD3
    alt.ln -2.5129208 -1.7224562 -1.0771922
    oxy    -0.7730690 -0.2117976  0.8197343
    dbo.ln -0.3348384 -2.7147468  2.3012850
    
    Proportion of trace:
       LD1    LD2    LD3 
    0.9032 0.0876 0.0092 
    > # 此结果对象内包含大量解读LDA的必要信息
    > summary(spe.lda)
            Length Class  Mode     
    prior    4     -none- numeric  
    counts   4     -none- numeric  
    means   12     -none- numeric  
    scaling  9     -none- numeric  
    lev      4     -none- character
    svd      3     -none- numeric  
    N        1     -none- numeric  
    call     3     -none- call     
    terms    3     terms  call     
    xlevels  0     -none- list     
    > # 显示三个变量分组平均值
    > spe.lda$means
        alt.ln       oxy   dbo.ln
    1 6.464881 11.388889 1.048586
    2 6.245151  9.944444 1.209785
    3 5.385688  8.387500 1.557074
    4 5.477515  5.200000 2.707430
    > #计算范数标准化特征向量(matrix C,eq.11.33),即标准化判别函数系数
    >  (Cs <- spe.lda$scaling)
                  LD1        LD2        LD3
    alt.ln -2.5129208 -1.7224562 -1.0771922
    oxy    -0.7730690 -0.2117976  0.8197343
    dbo.ln -0.3348384 -2.7147468  2.3012850
    > # 计算典范特征根
    > spe.lda$svd^2
    [1] 53.6898562  5.2088449  0.5478896
    > # 计算在典范变量空间内样方的坐标
    > (Fp <- predict(spe.lda)$x)
               LD1         LD2          LD3
    1  -4.08638573 -0.89640510  0.368028660
    2  -2.49450633  0.46365901 -1.995824032
    3  -2.80466835 -1.20357224 -0.404993616
    4  -2.68895361  1.49616437 -2.201175466
    5  -0.87807014 -2.09926524 -1.059020040
    6  -2.51740981 -2.13333526  0.387269196
    7  -2.90386963  0.07319673 -0.891988271
    9   0.10415477 -1.24335518 -1.988893958
    10 -1.49957974 -0.97965055  0.082158618
    11 -1.88806718  0.38774388  0.504579631
    12 -2.43308232 -0.02501061  1.334323268
    13 -2.36655395  0.63877375  1.047520033
    14 -2.35214071 -0.52520225  2.062059098
    15 -1.57722535  1.28900168  0.253631503
    16 -0.32438764  1.07783858 -0.206474231
    17 -0.23770978 -0.21870301  1.018179031
    18 -0.03051363  1.18888940  0.008410463
    19 -0.14515674  0.79740513  0.706294065
    20  0.34427132  1.44578197  0.169066314
    21  1.44181530  0.83677120  0.075460197
    22  1.38965445  0.44108254  0.553586732
    23  3.22326372 -2.24627627  1.120313152
    24  4.22156847 -1.19694492 -0.421313261
    25  5.07604329 -1.72116640 -0.573615673
    26  3.85542329 -0.32572787 -0.218162145
    27  3.29378337  0.46604929 -0.152484763
    28  2.84858565  1.28339090 -0.129929770
    29  2.33552915  1.38947026  0.517474958
    30  3.09418785  1.53939626  0.035520310
    > # 替代方式: Fp <- scale(env.pars3.df, center=TRUE, scale=FALSE) %*% C
    > # 对象的分类
    > (spe.class <- predict(spe.lda)$class)
     [1] 1 2 1 2 2 1 1 2 2 1 1 1 1 2 2 2 2 2 2 3 3 4 4 4 3 3 3 3 3
    Levels: 1 2 3 4
    > # 对象属于分类组的后验概率
    >  (spe.post <- predict(spe.lda)$posterior)
                  1            2            3            4
    1  9.858670e-01 1.413296e-02 8.589109e-10 1.420163e-15
    2  4.940452e-01 5.059487e-01 6.085899e-06 6.418503e-12
    3  8.588135e-01 1.411862e-01 2.982838e-07 1.233446e-11
    4  4.792624e-01 5.207302e-01 7.439251e-06 3.764956e-13
    5  1.881617e-01 8.115272e-01 3.063205e-04 4.798814e-06
    6  8.836761e-01 1.163235e-01 3.978965e-07 2.998536e-10
    7  7.973581e-01 2.026411e-01 7.545732e-07 9.620716e-13
    9  2.171690e-02 9.658988e-01 1.224973e-02 1.345408e-04
    10 4.808279e-01 5.190573e-01 1.147554e-04 2.862482e-08
    11 6.122120e-01 3.876919e-01 9.607204e-05 3.223522e-10
    12 8.718114e-01 1.281831e-01 5.490190e-06 1.869581e-11
    13 8.146431e-01 1.853415e-01 1.540601e-05 1.071606e-11
    14 9.112721e-01 8.872342e-02 4.439650e-06 6.168551e-11
    15 3.980760e-01 6.011260e-01 7.980082e-04 4.615970e-10
    16 6.299642e-02 8.902208e-01 4.678228e-02 4.895917e-07
    17 1.417366e-01 8.258918e-01 3.236084e-02 1.077488e-05
    18 3.993984e-02 8.237538e-01 1.363046e-01 1.813186e-06
    19 7.959866e-02 8.283919e-01 9.200680e-02 2.625695e-06
    20 1.533174e-02 5.625259e-01 4.221367e-01 5.688134e-06
    21 3.189551e-04 6.254116e-02 9.366679e-01 4.720092e-04
    22 6.638353e-04 8.237900e-02 9.158176e-01 1.139555e-03
    23 5.212073e-08 4.643126e-05 2.492989e-02 9.750236e-01
    24 2.218889e-10 3.122087e-06 5.333234e-02 9.466645e-01
    25 3.359000e-13 1.801844e-08 2.924798e-03 9.970752e-01
    26 4.997460e-09 4.293353e-05 5.209165e-01 4.790406e-01
    27 5.899119e-08 2.395345e-04 9.602048e-01 3.955563e-02
    28 2.153179e-07 5.145082e-04 9.973440e-01 2.141263e-03
    29 2.518020e-06 1.857210e-03 9.975367e-01 6.035869e-04
    30 5.013311e-08 1.724659e-04 9.981144e-01 1.713044e-03
    > # 预设分类和预测分类的比较表格
    > (spe.table <- table(gr, spe.class))
       spe.class
    gr  1 2 3 4
      1 7 2 0 0
      2 1 8 0 0
      3 0 1 7 0
      4 0 0 0 3
    > # 正确分类的比例
    > diag(prop.table(spe.table, 1))
            1         2         3         4 
    0.7777778 0.8888889 0.8750000 1.0000000 
    > # 绘制典范变量空间内样方位置图,样方颜色代表不同的组
    > plot(Fp[, 1], Fp[, 2], type="n")
    > text(Fp[, 1], Fp[, 2], row.names(env), col=c(as.numeric(spe.class)+1))
    > abline(v=0, lty="dotted")
    > abline(h=0, lty="dotted")
    > # 绘制95%的椭圆图
    > for(i in 1:length(levels(as.factor(gr)))){
    +   cov <- cov(Fp[gr==i, ])
    +   centre <- apply(Fp[gr==i, ], 2, mean)
    + lines(ellipse(cov, centre= centre, level=0.95))
    + }
    
    > # 新样方的分类(识别) 
    > # 生成一个新的样方(ln(alt)=6.8, oxygen=90 和 ln(dbo)=3.2)
    > newo <- c(6.8, 90, 3.2)
    > newo <- as.data.frame(t(newo)) # 必须在同一行
    > colnames(newo) <- colnames(env.pars3)
    > (predict.new <- predict(spe.lda, newdata=newo))
    $`class`
    [1] 1
    Levels: 1 2 3 4
    
    $posterior
      1            2             3            4
    1 1 7.578586e-65 8.588537e-153 6.08234e-184
    
    $x
            LD1       LD2      LD3
    1 -64.87086 -23.29703 69.26423
    
    > # 基于刀切法(jackknife)分类的LDA(即留一法交叉验证)
    > spe.lda.jac <- lda(gr ~ alt.ln + oxy + dbo.ln, data=env.pars3.df, CV=TRUE)
    > summary(spe.lda.jac)
              Length Class  Mode   
    class      29    factor numeric
    posterior 116    -none- numeric
    terms       3    terms  call   
    call        4    -none- call   
    xlevels     0    -none- list   
    > # 正确分类的数量和比例
    > spe.jac.class <- spe.lda.jac$class
    > spe.jac.table <- table(gr, spe.jac.class)
    > diag(prop.table(spe.jac.table, 1))
            1         2         3         4 
    0.7777778 0.6666667 0.7500000 1.0000000 
    

    参考

    线性判别分析(Linear Discriminant Analysis,LDA)
    lda.pdf
    Linear Discriminant Analysis in R: An Introduction
    lda
    2014_python_lda
    用一句话总结常用的机器学习算法
    PCA与LDA比较

    相关文章

      网友评论

        本文标题:数量生态学笔记||线性判别式分析(LDA)

        本文链接:https://www.haomeiwen.com/subject/ajfvaftx.html