考虑Matlab中的以下例程,在循环中多次调用ismember
。
clear
rng default
%%%% Parameters
XZsup=[1 2; 2 2; 3 2; 1 5; 2 5 ; 3 5];
N=100:100:2000;
%%%% Allocate space
P1=zeros(size(XZsup,1),size(N,2));
P2=zeros(size(XZsup,1),size(N,2));
time=zeros(size(N,2),1);
for l=1:size(N,2)
n=N(l);
%%%% 1) Generate data
X=unidrnd(3,n,1); %nx1
XZmu=[unidrnd(3,n^2,1) unidrnd(5,n^2,1) randi([0 1],n^2,1) randi([0 1],n^2,1) randi([0 1],n^2,1)]; %n^2x5
%%%% 2) Using ismember, compare each row in XZsup with XZmu and X and fill P1 and P2
tic
for h=1:size(XZsup,1)
num=ismember(XZmu, [XZsup(h,:) 1 1 0], 'rows');
den=ismember(XZmu(:,1:2), XZsup(h,:), 'rows');
P1(h,l)=sum(num)/ sum(den);
num=ismember(XZmu, [XZsup(h,:) 0 0 1], 'rows');
den=ismember(X,XZsup(h,1));
P2(h,l)=sum(num)/sum(den);
end
time(l)=toc;
end
对于N
的大值,循环内的代码非常慢。的确,我得到了
time =
0.0373
0.1583
0.3651
0.7003
1.2631
2.0064
2.9665
4.0512
5.4177
7.2097
8.9078
11.0968
13.3023
16.0414
19.0199
22.3131
26.3962
30.1553
34.3927
37.9660
我希望您能帮助我们提高效率。这可能是一个选项
clear
rng default
%%%% Parameters
XZsup=[1 2; 2 2; 3 2; 1 5; 2 5 ; 3 5];
N=100:100:2000;
%%%% Allocate space
P3=zeros(size(XZsup,1),size(N,2));
P4=zeros(size(XZsup,1),size(N,2));
time=zeros(size(N,2),1);
for l=1:size(N,2)
n=N(l);
%%%% 1) Generate data
X=unidrnd(3,n,1); %nx1
XZmu=[unidrnd(3,n^2,1) unidrnd(5,n^2,1) randi([0 1],n^2,1) randi([0 1],n^2,1) randi([0 1],n^2,1)]; %n^2x5
%%%% 2) Using ismember, compare each row in XZsup with XZmu and X and fill P3 and P4
tic
for h=1:size(XZsup,1)
num=(sum(XZmu==[XZsup(h,:) 1 1 0], 2)==5);
den=(sum(XZmu(:,1:2)==XZsup(h,:),2)==2);
P3(h,l)=sum(num)/ sum(den);
num=(sum(XZmu==[XZsup(h,:) 0 0 1], 2)==5);
den=(X==XZsup(h,1));
P4(h,l)=sum(num)/sum(den);
end
time(l)=toc;
end
我得到了
time =
0.0051
0.0047
0.0087
0.0183
0.0277
0.0365
0.0491
0.0714
0.0878
0.1098
0.1426
0.1825
0.2176
0.2440
0.2830
0.3353
0.3783
0.4215
0.4732
0.5399
您有更快的建议吗?
我已经阅读了几个与此相关的问题/答案,例如,
答案 0 :(得分:1)
ismember
很贵。
因此,我们可以尽可能少地使用它来节省时间。
我做了一个函数来比较OP的方法和我的方法。 由于我已经从your previous question知道纯粹存储大型矩阵也很慢,这次我试图避免它。
function [P1,P2] = testf(X,XZmu,XZsup, K)
P1=zeros(size(XZsup,1),1);
P2=zeros(size(XZsup,1),1);
switch K
case 1
for h=1:size(XZsup,1)
num=ismember(XZmu, [XZsup(h,:) 1 1 0], 'rows');
den=ismember(XZmu(:,1:2), XZsup(h,:), 'rows');
P1(h)=sum(num)/ sum(den);
num=ismember(XZmu, [XZsup(h,:) 0 0 1], 'rows');
den=ismember(X,XZsup(h,1));
P2(h)=sum(num)/sum(den);
end
case 2
for h=1:size(XZsup,1)
den = ismember(XZmu(:,1:2), XZsup(h,:), 'rows');
tempNum = (XZmu(:,3)==1) & (XZmu(:,4)==1) & (XZmu(:,5)==0);
num = tempNum & den;
P1(h) = sum(num)/sum(den);
tempNum2 = (XZmu(:,3)==0) & (XZmu(:,4)==0) & (XZmu(:,5)==1);
num2 = tempNum2 & den;
den2 = X==XZsup(h,1);
P2(h) = sum(num2)/sum(den2);
end
end
end
测试代码:
我再次更喜欢多次使用timeit
。
rng default
XZsup=[1 2; 2 2; 3 2; 1 5; 2 5 ; 3 5];
N=[10:20:100-1, 100:200:1000-1, 1000:1000:2000];
Ntrial = 5; % even timeit has variation, so make multiple trials
time=zeros(size(N,2),2);
tempT(Ntrial,2) = 0;
for l=1:size(N,2)
n=N(l);
%%%% 1) Generate data
X=unidrnd(3,n,1); %nx1
XZmu=[unidrnd(3,n^2,1) unidrnd(5,n^2,1) randi([0 1],n^2,1) randi([0 1],n^2,1) randi([0 1],n^2,1)]; %n^2x5
%%%% 2) Using ismember, compare each row in XZsup with XZmu and X and fill P1 and P2
for nn = 1:Ntrial
tempT(nn,:) = [timeit(@() testf(X, XZmu,XZsup, 1), 2), ....
timeit(@() testf(X, XZmu,XZsup, 2), 2)];
end
time(l,:)=mean(tempT,1);
end
plot(N, time(:,1), '--', N, time(:,2), '-')
结果:时间比较图
(我打算跑到N=3000
,但速度太慢......最后看到我的笔记)
在Matlab R2015b,Core i7上运行。
旁注:您的代码非常适合parfor
。
我将for
循环更改为XZsup
到parfor
,这是结果,与案例2相比。
在8-vCPU系统上运行Matlab R2018a。
对于像300x300这样的大型矩阵,parfor
优于for
。
对于较小的矩阵,我的猜测是需要更多时间与工人沟通。
您的里程可能会有所不同。
附注2:此方法对数据有更多限制,令人惊讶的是它不能更快地工作....
case 3
tempNumCol1 = XZmu(:,3)==1;
tempNumCol2 = XZmu(:,4)==1;
tempNumCol3 = XZmu(:,5)==1;
tempNum = (tempNumCol1) & (tempNumCol2) & (~tempNumCol3);
tempNum2 = (~tempNumCol1) & (~tempNumCol2) & (tempNumCol3);
for h=1:size(XZsup,1)
den = ismember(XZmu(:,1:2), XZsup(h,:), 'rows');
num = tempNum & den;
P1(h) = sum(num)/sum(den);
num2 = tempNum2 & den;
den2 = X==XZsup(h,1);
P2(h) = sum(num2)/sum(den2);
end
我的两种方法之间的比较:
编辑:为什么不完全摆脱ismember
......
case 3
tempNum = (XZmu(:,3)==1) & (XZmu(:,4)==1) & (XZmu(:,5)==0);
tempNum2 = (XZmu(:,3)==0) & (XZmu(:,4)==0) & (XZmu(:,5)==1);
for h=1:size(XZsup,1)
tempDen1 = XZmu(:,1)==XZsup(h,1);
tempDen2 = XZmu(:,2)==XZsup(h,2);
den = tempDen1&tempDen2;
num = tempNum & den;
P1(h) = sum(num)/sum(den);
num2 = tempNum2 & den;
den2 = X==XZsup(h,1);
P2(h) = sum(num2)/sum(den2);
end
它已经比在我的机器上生成随机数字更快了。