我尝试了解如何使用 MultivariateStats.jl 包在 Julia 中执行简单的探索性 PCA。
\n例如,在 R 中,可以执行以下操作:
\nlibrary(FactoMineR)\ndata(iris)\n\n## PCA model:\nres_pca <- PCA(iris, quali.sup = 5, graph = FALSE)\n## Retrieve coordinates of individuals on all 4 PCs:\nres_pca$ind$coord\n## Simple plots:\nplot(res_pca, choix = "ind", habillage = 5)\nplot(res_pca, choix = "var")\nRun Code Online (Sandbox Code Playgroud)\n我没有设法在 Julia 中获得这些非常基本的操作的任何等效项(我的意思是使用 MultivariateStats.jl 中的“本机”函数)。让我们从以下开始:
\nusing MultivariateStats\nusing RDatasets\n\niris = dataset("datasets", "iris")\n\n## PCA model:\nM = fit(PCA, Array(iris[:, 1:4]); pratio=1, maxoutdim=4)\nRun Code Online (Sandbox Code Playgroud)\n一旦我获得了 PCA“模型” M,我如何轻松检索个人坐标?如何轻松显示相关圈等?
据我了解,从准机器学习的角度来看,PCA 在 Julia 中作为一种“模型”实现,并且基本上无法提供轻松显示探索性 PCA 中通常需要的所有常用图表、统计数据和见解的方法?(我的意思是,cos\xc2\xb2、贡献等)
\n是否还有其他更面向探索性多变量分析的 Julia 包,可以提供与 FactoMineR 或 ade4 等著名 R 包大致相同的功能?
\n谢谢!
\ncbk*_*cbk 14
好的,首先您将数据放入错误的方向。正如您从文档中看到的
\n\n\nfit(PCA, X; ...)
\n
\n对矩阵 X 中给定的数据执行 PCA。X 的每一列都是一个观察值。
您需要将观察值作为列,将变量作为行。考虑到我们通常将变量视为列,这可能看起来令人困惑,但在底层线性代数的背景下,它更有意义。因此,为了做到这一点,让我们从以下开始:
\nusing MultivariateStats, Statistics\nusing RDatasets: dataset\n\niris = dataset("datasets", "iris")\niris_matrix = Array(iris[:, 1:4])\'\n\n## PCA model:\nM = fit(PCA, iris_matrix; pratio=1, maxoutdim=4)\nRun Code Online (Sandbox Code Playgroud)\n正如您所注意到的,这将返回一个类型的对象PCA。事实证明,文档中详细描述了这种类型的可用方法:
\n\n特性
\n设M是PCA的实例,d是观测值的维度,p是输出维度(即主子空间的维度)
\nindim(M)
\n
\n获取输入维度d,即观察空间的维度。outdim(M)
\n
\n获取输出维度 p,即主子空间的维度。Mean(M)
\n
\n获取平均向量(长度为 d)。投影(M)
\n
\n获取投影矩阵(大小为 (d, p))。投影矩阵的每一列对应一个主成分。主成分按相应方差的降序排列。
\nprincipalvars(M)
\n
\n主成分的方差。tprincipalvar(M)
\n
\n主成分的总方差,等于 sum(principalvars(M))。tresidualvar(M)
\n
\n总残差方差。tvar(M)
\n
\n总观测方差,等于 tprincipalvar(M) + tresidualvar(M)。principalratio(M)
\n
\n主子空间中保留的方差之比,等于 tprincipalvar(M) / tvar(M)。
但如果您不知道这一点或者在查找文档时遇到困难,您可以通过使用该函数获得所有可用方法(对于 Julia 中的任何methodswith类型)的完整列表- 在本例中具体为methodswith(PCA)。
其中的关键是projection,它为我们提供了实际的投影矩阵:
julia> proj = projection(M)\n4\xc3\x974 Matrix{Float64}:\n -0.361387 0.656589 -0.58203 0.315487\n 0.0845225 0.730161 0.597911 -0.319723\n -0.856671 -0.173373 0.0762361 -0.479839\n -0.358289 -0.075481 0.545831 0.753657\nRun Code Online (Sandbox Code Playgroud)\n正如文档告诉我们的
\n\n\n投影矩阵的每一列对应一个主成分
\n
因此proj[:,1]包含 PC1 的权重/“载荷”,proj[:,2]包含 PC2 的载荷等。
既然您询问了贡献,我猜您的意思是每个主成分对解释总方差的贡献,文档告诉我们您可以通过以下方式获得principalvars:
julia> principalvars(M)\n4-element Vector{Float64}:\n 4.2282417060348605\n 0.24267074792863352\n 0.07820950004291898\n 0.023835092973449976\nRun Code Online (Sandbox Code Playgroud)\n所以 PC1 确实承担了这里的大部分繁重工作。或者,如果您更喜欢用每个分量解释的总方差的百分比来表示,那么:
\njulia> principalvars(M) ./ tvar(M) * 100\n4-element Vector{Float64}:\n 92.46187232017269\n 5.306648311706788\n 1.7102609807929683\n 0.5212183873275495\nRun Code Online (Sandbox Code Playgroud)\n展望同一文档的“转换”部分
\n\n\n改造建设
\n给定一个 PCA 模型 M,我们可以用它来将观测值转换为主成分,如下所示
\n= \xe1\xb5\x80 ( - )
\n或用它来重建(近似)主成分的观察结果,如
\n\xcc\x83 = +
\n这里, 是投影矩阵。
\n该包提供了执行此操作的方法:
\n变换(M, x)
\n
\n将观测值 x 转换为主成分。这里,x 可以是长度为 d 的向量,也可以是每列都是观测值的矩阵。
\nreconstruct(M, y)
\n
\n根据 y 中给出的主成分近似重建观测值。这里,y 可以是长度为 p 的向量,也可以是每列给出观测值的主成分的矩阵。
\n
我们可以看到将这种转换应用于我们的数据的方法是
\niris_transformed = transform(M, iris_matrix)\nRun Code Online (Sandbox Code Playgroud)\n或者如果你想自己做线性代数
\niris_transformed = projection(M)\' * (iris_matrix .- mean(M))\nRun Code Online (Sandbox Code Playgroud)\n然后,一旦我们有了转换后的数据,我们就可以将前两个主成分相互绘制出来:
\nusing Plots\nh = plot(iris_transformed[1,:], iris_transformed[2,:], seriestype=:scatter, label="")\nplot!(xlabel="PC1", ylabel="PC2", framestyle=:box) # A few formatting options\nRun Code Online (Sandbox Code Playgroud)\n\n最后,如果你想为不同的变量添加箭头,事实证明我们已经拥有了我们需要的一切projection(M),我们已经将其存储为proj
for i=1:4; plot!([0,proj[i,1]], [0,proj[i,2]], arrow=true, label=names(iris)[i], legend=:bottomleft); end\ndisplay(h)\nRun Code Online (Sandbox Code Playgroud)\n\n编辑:我可能还应该提到,虽然(还)没有用于 PCA 类型的 StatsPlots 配方,但有一个用于 MDS 的配方,因此在这种情况下,您可以通过简单地编写来获得与上述等效的图
\nM = fit(MDS, iris_matrix; distances=false)\nusing StatsPlots\nplot(M)\nRun Code Online (Sandbox Code Playgroud)\n(对于此处距离度量是原始(即高维)向量空间中的欧氏距离的情况,PCA 和 MDS 是等效的)
\n| 归档时间: |
|
| 查看次数: |
2389 次 |
| 最近记录: |