大型数据集(R 或 Python)上的 MDS

机器算法验证 r Python 多维尺度
2022-03-21 05:53:54

我有一个 400000 × 400000 的大型集(相异矩阵),我想对其进行多维缩放。 () 函数后,它只需要最大46340 × 46340 矩阵作为输入。有什么办法可以解决这个问题吗?另外,Python 是否有同样的限制(在 sklearn 包中)?××

我应该补充一点,这里的内存不是问题。

3个回答

仅使用双精度浮点数来存储该大小的密集距离矩阵就需要超过 TB。使用标准的 MDS 算法正面攻击如此大规模的问题可能是不可行的。运行时缩放为O(n3),您甚至可能无法在单台机器上将距离矩阵放入内存中。根据您的情况,您可能可以解决它。如何做到这一点取决于您的具体数据和问题,但这里有几个例子:

1) PCA 等效于使用欧几里得距离度量的经典 MDS。因此,如果这是您要执行的 MDS 类型,您可以改用 PCA。另一个要求是您可以访问作为向量的原始数据点,而不仅仅是距离矩阵。有许多算法可以在庞大的数据集上有效地运行 PCA。

2) 使用 MDS 的近似形式。如果您想执行经典的 MDS,这种方法可能会起作用。它不需要欧几里得距离度量或数据的向量空间表示(只需要访问距离)。Landmark MDS 就是一个很好的例子。第一步是选择一组较小的“地标点”来代表完整的数据集。这些可以简单地通过从数据中随机抽样来获得,或者使用快速、贪婪的算法来进一步优化它们。原则上也可以使用聚类,但它的计算成本很高且没有必要。对地标点执行经典 MDS 以将它们嵌入向量空间中。然后使用地标点的经典 MDS 结果将完整数据集映射到嵌入空间。虽然最初并未如此表述,

3)如果你想执行非经典的MDS,像Landmark MDS这样的方法是行不通的。这是因为 MDS 的非经典变体是使用优化算法迭代求解的,而不是通过求解特征值问题。采用以下方法可能会起作用: a) 选择数据的代表性子样本。b) 使用您选择的 MDS 风格将这些点嵌入向量空间。c) 使用二次采样数据点作为示例,使用非线性回归方法学习到嵌入空间的映射。需要适当注意学习良好的映射,而不是过度拟合等。 d) 使用学习的映射来获得整个数据集的嵌入。我记得看到几篇论文将这种方法描述为一种对非线性降维算法进行样本外泛化的方法。但是,在我看来,它也可以用作一种有效地逼近非经典 MDS 的方法。可能存在更专业的解决方案;如果是这样,我会很高兴听到他们的消息。

4)如果绝对必要,可以使用并行化来解决全部问题。例如,对于经典 MDS,您可以在机器之间分配距离矩阵的块,然后使用并行/分布式矩阵运算和特征求解器来执行 MDS。对于非经典 MDS,可能会想出一些方案。但是,这可能是一项艰巨的任务,而且近似 MDS 很可能运行良好。所以,这是一个更好的起点。

参考:

德席尔瓦和特南鲍姆(2004 年)使用地标点的稀疏多维缩放。

普拉特(2005 年)FastMap、MetricMap 和 Landmark MDS 都是 Nystrom 算法。

如果要在如此大的数据集上执行 MDS,则需要使用 MDS 的并行实现。您可以在 [1] 中找到基于 MPI 的 MDS 并行实现。但是为了运行一个 400000 ×× 400000 的数据集,你需要一个大型集群或一台超级计算机。我已经将它与具有 200000 x 200000 数据矩阵的数据集一起使用(我使用 24 节点超级计算机来运行它,可以用更少但需要更多时间来完成)。还有一个在 spark 上运行的版本,您可以使用 [2]。但是 spark 实现比基于 MPI 的实现慢得多

[1] https://github.com/DSC-SPIDAL/damds

[2] https://github.com/DSC-SPIDAL/damds.spark

我在使用cmdscale()时遇到了严重的性能问题经过一番挖掘,我设法找到了一个名为mdsj ( https://www.inf.uni-konstanz.de/exalgo/software/mdsj/ ) 的 java 库,它可以接收文本文件格式的矩阵并将多维缩放版本输出到文本文件。这一切都可以在 bash 中完成,可以使用 R 的system()函数调用。我会在这里分享我的代码,以防万一有人觉得它有用:

saveMDS = function(daisy.mat){
   write.table(daisy.mat, file=paste("./MDS/data.txt",sep=""), row.names=FALSE, col.names=FALSE)
   system('bash -c "cd MDS; > data-MDS.txt;java -jar mdsj.jar data.txt data-MDS.txt"')
}


loadMDS = function(){

return(as.matrix(read.table("./MDS/data-MDS.txt",header=FALSE,sep=" ")))


}

data <- data.frame(x=runif(10000),y=runif(10000),z=runif(10000))
daisy.mat <- as.matrix(daisy(data[,c(1:3)], metric="gower"))
saveMDS(daisy.mat)
mds.data = loadMDS()

在这种情况下,我的工作目录中有一个名为 MDS 的文件夹,数据文本文件存储到该文件夹​​中。

希望这可以帮助!