我的matlab计算速度有点问题。我能够在matlab中编写一个代码来运行小矩阵的计算,但它使用嵌套的for循环,并且对于我正在使用的大型数据集,matlab无法完成计算。
注意:我对Matlab并不十分熟悉,所以虽然该程序有效但效率极低。
简而言之,我正在尝试创建一个矩阵,其条目描述了一组唯一位置之间的关系。作为一个具体的例子,我们从这个矩阵开始:
B =
5873 4 1
5873 7 1
5873 1 1
2819 8 2
2819 1 2
9771 4 3
9771 2 3
9771 5 3
9771 6 3
5548 7 4
第三列是唯一的位置标识符,第二列是恰好位于该位置的“段”的编号。请注意,多个细分可以分为不同的位置。
我想要的是创建一个描述不同位置之间关系的矩阵。具体来说,对于位置i& j,我希望新矩阵的(i,j)条目是i&的分段数。 j的共同点除以i&的段总数。 j合并。
目前我的代码如下:
C = zeros(max(B.data(:,3)), max(B.data(:,3)));
for i = 1:max(B.data(:,3))
for j = 1:max(B.data(:,3))
vi = B.data(:,3) == i;
vj = B.data(:,3) == j;
C(i,j) = numel(intersect(B.data(vi,2), B.data(vj,2))) / numel(union(B.data(vi,2), B.data(vj,2)));
end
end
但它非常慢。有没有人有加快计算的建议?
非常感谢!!
答案 0 :(得分:2)
groups
)对位置进行分组。具有自定义功能的accumarray
用于该任务。C
初始化为零。对于每个组,属于该组的所有位置对都使其C
中的条目增加1
。C
已标准化。代码:
groups = accumarray(B.data(:,2), B.data(:,3), [], @(x) {x}); %// step 1
C = zeros(max(B.data(:,3))); %// step 2
for n = 1:numel(groups);
ind = groups{n};
C(ind,ind) = C(ind,ind)+1;
end
d = diag(C); %// step 3
C = C./(bsxfun(@plus,d,d.')-C);
这种方法很耗费内存;根据@Divakar在下面的评论,对于非常大的数据集,它并不比循环方法快:
logical
数组T
,T(m,n,s)
1
当且仅当地点m
和n
共享细分{ {1}}。这可以通过bsxfun
高效完成。s
会产生与上一个方法相同的T
。C
的标准化方式与之前相同。代码:
C
以下基准测试和解释将归功于@Divakar:
以下是一些将T = full(sparse(B.data(:,3), B.data(:,2), 1)); %// step 1
T = bsxfun(@and, permute(T, [1 3 2]), permute(T, [3 1 2]));
C = sum(T, 3); %// step 2
d = diag(C); %// step 3
C = C./(bsxfun(@plus,d,d.')-C);
方法与后者loop-based
方法进行比较的运行时 -
vectorized
可以注意到,对于***** Parameters: No. of rows in B ~= 10000 and No. of groups = 10 *****
---------------------------------- With loopy approach
Elapsed time is 0.242635 seconds.
---------------------------------- With vectorized approach
Elapsed time is 0.022174 seconds.
***** Parameters: No. of rows in B ~= 10000 and No. of groups = 100 *****
---------------------------------- With loopy approach
Elapsed time is 0.318268 seconds.
---------------------------------- With vectorized approach
Elapsed time is 0.451242 seconds.
***** Parameters: No. of rows in B ~= 100000 and No. of groups = 100 *****
---------------------------------- With loopy approach
Elapsed time is 1.173182 seconds.
---------------------------------- With vectorized approach
Elapsed time is 0.464339 seconds.
***** Parameters: No. of rows in B ~= 100000 and No. of groups = 1000 *****
---------------------------------- With loopy approach
Elapsed time is 10.310780 seconds.
---------------------------------- With vectorized approach
Elapsed time is 54.216923 seconds.
中相同的行数,组数的增加意味着向量化方法的性能大幅下降。
因此,在为问题案例选择适当的方法时,请记住这一点。
答案 1 :(得分:1)
这可能是一种使用单循环的方法 -
%// Store column-2 and 3 values in separate variables for easy access
col2 = B(:,2);
col3 = B(:,3);
%// Start and end indices of the groups w.r.t column-3 of B
ends = [find(diff(col3)) ; numel(col3)];
starts = [1 ; ends(1:end-1)+1];
ngrp = max(col3); %// number of groups
intersectM = zeros(ngrp); %// initialize 2D matrix to store intersect counts
for k = 1:ngrp-1
%// Matches for each group with respect to each other group
%// but one less after each iteration
matches = ismember(col2(starts(k+1):end),col2(starts(k):ends(k)));
%// OR matches =
%// any(bsxfun(@eq,col2(starts(k):ends(k)),col2(starts(k+1):end).'),1)'
%// Store intersect counts
intersectM(k,k+1:end) = accumarray(col3(starts(k+1):end)-k,matches,[]);
end
grp_counts = histc(col3,1:ngrp); %// counts of group elements
%// Peform numel(intersect)/numel(union)
C = intersectM./(bsxfun(@plus,grp_counts,grp_counts') - intersectM); %//'
%// Since the output is diagonal symmetric, so just copy over the upper
%// diagonal elements into the lower diagonal places
C = triu(C)' + C; %//'
C(1:ngrp+1:end) = 1; %// Set diagonal elements as ones