对于长度大于1E8的两个逻辑向量x和y,计算2x2交叉表最快的方法是什么?
我猜想答案是用C/C++编写,但我想知道R是否已经对这个问题有了相当聪明的解决方法,因为这并不罕见。
以下是示例代码,用于300M条目(如果3E8太大,可以将N设置为1E8;我选择了总大小略小于2.5GB(2.4GB)。我针对的密度为0.02,只是为了增加一些趣味性(如果有帮助,可以使用稀疏向量,但类型转换可能需要时间)。
一些明显的方法:
我发现
向量乘法通常不是一个好主意,但当向量是稀疏的时候,将其存储为稀疏向量,然后使用向量乘法可能会有优势。
为什么要使用这么多数据,当一个子样本可能足以用于创建交叉表呢?数据来自于两个变量中真实观测非常罕见的情况。其中一个是数据异常的结果,另一个可能是代码中的一个错误(可能是因为我们只看到了计算结果 - 将变量x视为“垃圾输入”,变量y视为“垃圾输出”)。因此,问题是输出中由代码引起的问题是否仅限于数据异常的情况,还是还有其他一些良好数据变坏的情况?(这就是为什么我问了一个关于遇到NaN、NA或Inf时停止的问题的原因。)
这也解释了为什么我的示例中
这是否暗示了一条不同的解决方案路径?是的:它暗示我们可以使用两个索引(即每个集合中
那么我该如何在R中实现呢?
我猜想答案是用C/C++编写,但我想知道R是否已经对这个问题有了相当聪明的解决方法,因为这并不罕见。
以下是示例代码,用于300M条目(如果3E8太大,可以将N设置为1E8;我选择了总大小略小于2.5GB(2.4GB)。我针对的密度为0.02,只是为了增加一些趣味性(如果有帮助,可以使用稀疏向量,但类型转换可能需要时间)。
set.seed(0)
N = 3E8
p = 0.02
x = sample(c(TRUE, FALSE), N, prob = c(p, 1-p), replace = TRUE)
y = sample(c(TRUE, FALSE), N, prob = c(p, 1-p), replace = TRUE)
一些明显的方法:
table
bigtabulate
- 简单的逻辑操作(例如
sum(x & y)
) - 向量乘法(不推荐)
data.table
- 上述方法之一,结合
multicore
包中的parallel
(或新的parallel
包)
我发现
table
的速度非常慢。对于一对逻辑向量来说,bigtabulate
似乎有点过头了。最后,使用普通的逻辑操作似乎有点笨拙,并且它对每个向量进行了太多次的操作(3倍?7倍?),更不用说在处理过程中填充了大量的额外内存,这是一个巨大的时间浪费。向量乘法通常不是一个好主意,但当向量是稀疏的时候,将其存储为稀疏向量,然后使用向量乘法可能会有优势。
为什么要使用这么多数据,当一个子样本可能足以用于创建交叉表呢?数据来自于两个变量中真实观测非常罕见的情况。其中一个是数据异常的结果,另一个可能是代码中的一个错误(可能是因为我们只看到了计算结果 - 将变量x视为“垃圾输入”,变量y视为“垃圾输出”)。因此,问题是输出中由代码引起的问题是否仅限于数据异常的情况,还是还有其他一些良好数据变坏的情况?(这就是为什么我问了一个关于遇到NaN、NA或Inf时停止的问题的原因。)
这也解释了为什么我的示例中
TRUE
值的概率很低;这些情况真正发生的时间少于0.1%。这是否暗示了一条不同的解决方案路径?是的:它暗示我们可以使用两个索引(即每个集合中
TRUE
的位置)并计算集合的交集。我避免使用集合的交集,是因为我之前在Matlab中遇到过问题,它在执行交集操作之前会先对集合元素进行排序。(我模糊地记得复杂度甚至更令人尴尬:像O(n^2)
而不是O(n log n)
。)那么我该如何在R中实现呢?
table
在你看来速度很慢。在我使用它时,它总是很快的。(尽管在你的任务上花费了5分钟时间。) - IRTFMtable(sample(x,3e6),sample(y,3e6))
这样的东西。 - Brandon Bertelsen