我的代码中有两个大型矩阵,它们具有相同的列数和不同的行数。与A(20000X4000)
和B(30000X4000)
一样。两者都是0-1稀疏。
我应该用A的所有行检查A的每一行,并计算公共1的数量。例如,如果A(1,:)=[0 1 0 1 1]
和B([1 2],:)=[1 1 1 1 1;0 0 0 1 1]
,我需要将结果设为3
和2
。
假设有一个大的0-1矩阵C(50000X4000)
,其行被标记为类型A
或类型B
。我应该将A
和B
的所有行进行比较并枚举1。如果A和B的每一行中的1的数量大于某些边界,那么我在剩下的计算中使用了A和B的那些行。所以,我甚至不需要存储A
和B
,我只需要一系列行索引列表。类似[(3,2),(3,5),...]
的内容显示我应该使用A
的第三行和B
的第二行,A
的第三行和B
的第五行等等。
我想到的第一件事是A*B'
,它给出了正确的结果,但实际上它是非常昂贵的,在某些情况下不可能进行这种乘法。
我将矩阵转换为单一数据类型,它变得更快一点。稀疏没有帮助。
任务看起来很简单,只计算每行A
的常见1和B
的所有行,但不容易实现。考虑到代码应该执行1000次这样的任务,那么实际上是不可能的。
任何想法如何在没有乘法的情况下枚举常见的? (顺便说一句,循环也没有用)。
感谢。
答案 0 :(得分:2)
我不知道这是否真的比你拥有的更好,因为它仍然有一个for循环,但如果有人能弄清楚如何删除for循环你应该很高兴。
% create temp data
A = rand(20000,4000) < 0.5;
B = rand(30000,4000) < 0.5;
counts = zeros(size(A,1),size(B,1),'uint8');
for i = 1:size(A,1)
counts(i,:) = sum(bsxfun(@eq,A(i,:),B),2);
end
无论哪种方式,该过程都需要很长时间,因为您要比较30000行,每行4000个元素,20000次或大约2.4e+12
个比较。这是一项艰巨的任务,肯定需要很长时间。如果你需要更快的话,可能会尝试使用并行计算。
答案 1 :(得分:1)
我做了一些基准测试;在我的机器上(i7-3770 @ 3.40GHz),无论内容如何,将大小为30000 x 4000和4000 x 20000的完整矩阵相乘大约需要55秒,与Dennis Jaheruddin发现的相同。但是使用稀疏矩阵可以使计算更快,具体取决于稀疏性。如果我将稀疏程度r
定义为1
s与矩阵元素之间的比率,我得到以下结果:
r time / s
0.001 0.07
0.002 0.3
0.005 2.1
0.01 8.3
0.02 25
以下是用于确定这些数字的代码:
m = 20000;
n = 4000;
o = 30000;
r = 0.001;
N = round(r * m * n);
A = sparse(randi(m, N, 1), randi(n, N, 1), 1, m, n);
N = round(r * n * o);
B = sparse(randi(o, N, 1), randi(n, N, 1), 1, o, n);
tic
C = A * B';
toc
答案 2 :(得分:0)
如果不能完成整个矩阵的乘法,一个想法是一次处理一个垂直条纹。对于每个条带,您计算所需的结果,并将其与前面的条带累加:
A = double(rand(5,300)<.5); %// random data
B = double(rand(4,300)<.5); %// random data
S = 10; %// stripe size
result = zeros(size(A,1),size(B,1)); %// initialize to 0
for s = 1:10:size(A,2) %// each vertical stripe, of width S
ind = s+(0:S-1);
result = result + A(:,ind)*(B(:,ind)).';
end
检查:
>> result
result =
73 72 62 72
84 70 79 71
83 84 76 77
77 80 77 74
71 71 70 74
>> A*B.'
ans =
73 72 62 72
84 70 79 71
83 84 76 77
77 80 77 74
71 71 70 74
答案 3 :(得分:0)
您尝试的解决方案是最佳或接近最佳的。
当我尝试这个时,需要不到一分钟的时间:
A = round(rand(30000,4000));
B = round(rand(20000,4000));
tic,A*B';toc;
如果你真的需要这样做几千次,我只能想象两种情景:
如果您发现此样本乘法超过一分钟(例如超过10分钟),则可能无法有效地使用内存。在这种情况下,尝试获得更多的ram。