嗯,我实在忍不住要玩一玩。我创建了一个Matlab.mex C 文件 http://www.mathworks.com/help/matlab/programming-interfaces-for-c-c-fortran-com.html called pdistc http://biorobots.cwru.edu/personnel/adh/stackoverflow/01/pdistc.c它实现了单精度和双精度的成对欧几里得距离。在我使用 Matlab R2012b 和 R2015a 的机器上,速度比pdist http://www.mathworks.com/help/stats/pdist.html(以及底层的pdistmex
辅助函数)用于大型输入(例如 60,000×300)。
正如已经指出的,这个问题从根本上来说是受内存限制的,而且你需要很多内存。我的 mex C 代码使用的内存超出了输出所需的内存。将其内存使用情况与pdist
,看起来两者几乎是一样的。换句话说,pdist
没有使用大量额外内存。你的内存问题很可能是在调用前内存用完pdist
(你能用clear
删除任何大型数组?)或者只是因为您试图在小型硬件上解决大型计算问题。
So, my pdistc
函数可能无法总体上节省内存,但您也许可以使用我内置的另一个功能。您可以计算整个成对距离向量的块。像这样的东西:
m = 6e3;
n = 3e2;
X = rand(m,n);
sz = m*(m-1)/2;
for i = 1:m:sz-m
D = pdistc(X', i, i+m); % mex C function, X is transposed relative to pdist
... % Process chunk of pairwise distances
end
这要慢得多(10 倍左右),而且我的 C 代码的这一部分没有得到很好的优化,但它将允许更少的内存使用——假设您不需要一次需要整个数组。请注意,您可以更有效地执行相同的操作pdist
(or pdistc
)通过创建一个循环,在其中传递以下子集X
直接,而不是全部。
如果您有 64 位 Intel Mac,则无需编译,因为我已经包含了.mexmaci64
二进制文件,但否则您需要弄清楚如何为您的机器编译代码。我无法帮助你。您可能无法编译它,或者存在兼容性问题,您需要自己编辑代码来解决。也有可能存在错误并且代码会导致 Matlab 崩溃。另请注意,您可能会得到与以下内容略有不同的输出:pdist
两者之间的差异在于机器 epsilon 的范围(eps http://www.mathworks.com/help/matlab/ref/eps.html). pdist
可能会或可能不会做一些花哨的事情来避免大输入和其他数字问题的溢出,但请注意我的代码没有。
另外,我创建了一个简单的纯Matlab实现 http://biorobots.cwru.edu/personnel/adh/stackoverflow/01/pdistq.m。它比 mex 代码慢得多,但仍然比简单的实现或中找到的代码快pdist
.
所有文件可以在这里找到 http://biorobots.cwru.edu/personnel/adh/stackoverflow/01/。 ZIP 存档包含所有文件。它是 BSD 许可的。请随意优化(我在 C 代码中尝试了 BLAS 调用和 OpenMP,但没有成功——也许一些指针魔法或 GPU/OpenCL 可以进一步加快速度)。我希望它对您或其他人有帮助。