使用 matlab / octave 制作 for 循环和 if 语句并提高速度
Making for loop and if statment and increasing speed using matlab / octave
我正在尝试看看是否可以提高 for 循环和 if 条件语句的速度。基本上它会在数组中查找非重复键值并从另一列获取值。
如果我 运行 100000 个值大约需要 13 秒 请参阅下面的代码。有没有办法提高效率? Ps 我正在使用可与 matlab 配合使用的 Octave 3.8.1
%test if lookup statment
clear all, clc, tic, clf;
num_to_test=100000 %amount of numbers to test
a1=(1:1:num_to_test)';
a2=(a1.*num_to_test);
array=[a1,a2]; %array where values are stored
lookupval=(randperm(num_to_test,num_to_test/2)/4)'; %lookup these random values of non repeating integers and floats and get another value
amp=[];
freq=[];
found_array=[];
notfound_array=[];
for ii=1:1:rows(lookupval)
if (find(lookupval(ii)==array(:,1))) %if you find a lookup value in array
%disp('found');
[row,col] = find(lookupval(ii) == array(:,1));
amp=[amp;array(row,2)];
freq=[freq;array(row,1)];
found_array=[freq,amp];
else %add lookup value to another array and make amp value zero
notfound_arraytmp=[lookupval(ii),0];
notfound_array=[notfound_array;notfound_arraytmp];
endif
end
comb_array=[found_array;notfound_array];
sort_comb_array=sortrows(comb_array,1); %sort array by first col incrementing
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
有几个问题,但最主要的可能是您没有预先分配 - 像这样附加:amp=[amp;array(row,2)];
在 MATLAB 中通常很慢。不过这里不需要循环。
让我们从一个简单的数组开始,A:
1 500
2 700
3 900
7 1000
9 800
我们的查找值是 [2 6 3 9 7];
我们希望我们的输出显示这些查找值,排序,在第一列中,第二列是 A 的第二列中的值(它们在其中存在)或零。
lookup = sort(lookup);
output = zeros(length(lookup),2);
output(:,1) = lookup;
[c a b ] = intersect(A(:,1),lookup);
output(b,2) = A(a,2);
输出为:
2 700
3 900
6 0
7 1000
9 800
纯粹从效率的角度来看,我会重写 for
循环如下:
m = 0; % number of omitted values
n = 0; % number of found values
for ii=1:1:rows(lookupval)
[row,col] = find(lookupval(ii) == array(:,1));
if ~isempty(row) %if you find a lookup value in array
%disp('found');
n=n+1;
amp(n)=array(row,2);
freq(n)=;array(row,1);
found_array=[freq,amp];
else %add lookup value to another array and make amp value zero
m=m+1;
notfound_array(2*m-1:2*m)=[lookupval(ii);0];
endif
end
这通过直接使用其输出而不是在 find
returns 一个位置时重新计算它来为您节省 find
调用,并以更有效的方式增长数组(如图所示在 this question).
方法 #1
使用 ismember
-
可能会非常有效
lookupval = sort(lookupval); %// Do sorting at the start
sort_comb_array = [lookupval zeros(size(lookupval))]; %// Setup output array
[idA,idB] = ismember(array(:,1),lookupval); %// Get matching IDs
sort_comb_array(idB(idA),2) = array(idA,2); %// Index into second column
%// of array and get corresponding values
方法 #2
我也会把我最喜欢的 bsxfun
扔进去,但是对于 100,000
这么大的数据量,它的内存效率低下可能会使它变慢 -
lookupval = sort(lookupval);
sort_comb_array = [lookupval zeros(size(lookupval))];
[idA,idB] = find(bsxfun(@eq,array(:,1),lookupval(:).')); %//'# Get matching IDs
sort_comb_array(idB,2) = array(idA,2);
这是 Divakar 建议我做的一项测试,以查看从八度 3.8.1 到 运行 所需的速度。结果与代码一起在下面。
1) 将 ismember 与 2,000,000 一起使用速度更快但占用更多内存
-经过时间 -0.2306sec- 或 -0.0038mins-
总共是 15000001 个元素,使用 106000008 个字节
2) 使用与 2,000,000 相交的速度较慢,但使用的内存较少。
-经过时间 -0.3057sec- 或 -0.0051mins-
总共是 11749047 个元素,使用 93992376 个字节
3) 将 bskfun 与 100,000 一起使用会产生错误:内存不足或尺寸对于 Octave 的索引类型而言太大
第一次测试结果:
clear all, clc, tic, clf;
num_to_test=2000000 %amount of numbers to test
a1=(1:1:num_to_test)';
a2=(a1.*num_to_test);
array=[a1,a2]; %array where values are stored
lookupval=(randperm(num_to_test,num_to_test/2)/4)'; %lookup these random vaules of intergers and floats and get another value
lookupval = sort(lookupval);
sort_comb_array = [lookupval zeros(size(lookupval))];
[idA1,idB1] = ismember(array(:,1),lookupval);
sort_comb_array(idB1(idA1),2) = array(idA1,2);
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
whos
>>>num_to_test = 2000000
>>>
finally Done-elapsed time -0.2306sec- or -0.0038mins- or -0.0001hours-
>>>Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a1 2000000x1 16000000 double
a2 2000000x1 16000000 double
array 2000000x2 32000000 double
idA1 2000000x1 2000000 logical
idB1 2000000x1 16000000 double
lookupval 1000000x1 8000000 double
num_to_test 1x1 8 double
sort_comb_array 1000000x2 16000000 double
Total is 15000001 elements using 106000008 bytes
========================================================================
二测结果:
clear all, clc, tic, clf;
num_to_test=2000000 %amount of numbers to test
a1=(1:1:num_to_test)';
a2=(a1.*num_to_test);
array=[a1,a2]; %array where values are stored
lookupval=(randperm(num_to_test,num_to_test/2)/4)'; %lookup these random vaules of intergers and floats and get another value
lookupval = sort(lookupval);
output = zeros(length(lookupval),2);
output(:,1) = lookupval;
[c a b ] = intersect(array(:,1),lookupval);
output(b,2) =array(a,2);
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
whos
>>>num_to_test = 2000000
>>>
finally Done-elapsed time -0.3057sec- or -0.0051mins- or -0.0001hours-
>>>Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 250005x1 2000040 double
a1 2000000x1 16000000 double
a2 2000000x1 16000000 double
array 2000000x2 32000000 double
b 250005x1 2000040 double
c 250005x1 2000040 double
lookupval 1000000x1 8000000 double
num_to_test 1x1 8 double
output 1000000x2 16000000 double
Total is 11750016 elements using 94000128 bytes
=======================================================================
我正在尝试看看是否可以提高 for 循环和 if 条件语句的速度。基本上它会在数组中查找非重复键值并从另一列获取值。
如果我 运行 100000 个值大约需要 13 秒 请参阅下面的代码。有没有办法提高效率? Ps 我正在使用可与 matlab 配合使用的 Octave 3.8.1
%test if lookup statment
clear all, clc, tic, clf;
num_to_test=100000 %amount of numbers to test
a1=(1:1:num_to_test)';
a2=(a1.*num_to_test);
array=[a1,a2]; %array where values are stored
lookupval=(randperm(num_to_test,num_to_test/2)/4)'; %lookup these random values of non repeating integers and floats and get another value
amp=[];
freq=[];
found_array=[];
notfound_array=[];
for ii=1:1:rows(lookupval)
if (find(lookupval(ii)==array(:,1))) %if you find a lookup value in array
%disp('found');
[row,col] = find(lookupval(ii) == array(:,1));
amp=[amp;array(row,2)];
freq=[freq;array(row,1)];
found_array=[freq,amp];
else %add lookup value to another array and make amp value zero
notfound_arraytmp=[lookupval(ii),0];
notfound_array=[notfound_array;notfound_arraytmp];
endif
end
comb_array=[found_array;notfound_array];
sort_comb_array=sortrows(comb_array,1); %sort array by first col incrementing
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
有几个问题,但最主要的可能是您没有预先分配 - 像这样附加:amp=[amp;array(row,2)];
在 MATLAB 中通常很慢。不过这里不需要循环。
让我们从一个简单的数组开始,A:
1 500
2 700
3 900
7 1000
9 800
我们的查找值是 [2 6 3 9 7];
我们希望我们的输出显示这些查找值,排序,在第一列中,第二列是 A 的第二列中的值(它们在其中存在)或零。
lookup = sort(lookup);
output = zeros(length(lookup),2);
output(:,1) = lookup;
[c a b ] = intersect(A(:,1),lookup);
output(b,2) = A(a,2);
输出为:
2 700
3 900
6 0
7 1000
9 800
纯粹从效率的角度来看,我会重写 for
循环如下:
m = 0; % number of omitted values
n = 0; % number of found values
for ii=1:1:rows(lookupval)
[row,col] = find(lookupval(ii) == array(:,1));
if ~isempty(row) %if you find a lookup value in array
%disp('found');
n=n+1;
amp(n)=array(row,2);
freq(n)=;array(row,1);
found_array=[freq,amp];
else %add lookup value to another array and make amp value zero
m=m+1;
notfound_array(2*m-1:2*m)=[lookupval(ii);0];
endif
end
这通过直接使用其输出而不是在 find
returns 一个位置时重新计算它来为您节省 find
调用,并以更有效的方式增长数组(如图所示在 this question).
方法 #1
使用 ismember
-
lookupval = sort(lookupval); %// Do sorting at the start
sort_comb_array = [lookupval zeros(size(lookupval))]; %// Setup output array
[idA,idB] = ismember(array(:,1),lookupval); %// Get matching IDs
sort_comb_array(idB(idA),2) = array(idA,2); %// Index into second column
%// of array and get corresponding values
方法 #2
我也会把我最喜欢的 bsxfun
扔进去,但是对于 100,000
这么大的数据量,它的内存效率低下可能会使它变慢 -
lookupval = sort(lookupval);
sort_comb_array = [lookupval zeros(size(lookupval))];
[idA,idB] = find(bsxfun(@eq,array(:,1),lookupval(:).')); %//'# Get matching IDs
sort_comb_array(idB,2) = array(idA,2);
这是 Divakar 建议我做的一项测试,以查看从八度 3.8.1 到 运行 所需的速度。结果与代码一起在下面。
1) 将 ismember 与 2,000,000 一起使用速度更快但占用更多内存
-经过时间 -0.2306sec- 或 -0.0038mins-
总共是 15000001 个元素,使用 106000008 个字节
2) 使用与 2,000,000 相交的速度较慢,但使用的内存较少。
-经过时间 -0.3057sec- 或 -0.0051mins-
总共是 11749047 个元素,使用 93992376 个字节
3) 将 bskfun 与 100,000 一起使用会产生错误:内存不足或尺寸对于 Octave 的索引类型而言太大
第一次测试结果:
clear all, clc, tic, clf;
num_to_test=2000000 %amount of numbers to test
a1=(1:1:num_to_test)';
a2=(a1.*num_to_test);
array=[a1,a2]; %array where values are stored
lookupval=(randperm(num_to_test,num_to_test/2)/4)'; %lookup these random vaules of intergers and floats and get another value
lookupval = sort(lookupval);
sort_comb_array = [lookupval zeros(size(lookupval))];
[idA1,idB1] = ismember(array(:,1),lookupval);
sort_comb_array(idB1(idA1),2) = array(idA1,2);
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
whos
>>>num_to_test = 2000000
>>>
finally Done-elapsed time -0.2306sec- or -0.0038mins- or -0.0001hours-
>>>Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a1 2000000x1 16000000 double
a2 2000000x1 16000000 double
array 2000000x2 32000000 double
idA1 2000000x1 2000000 logical
idB1 2000000x1 16000000 double
lookupval 1000000x1 8000000 double
num_to_test 1x1 8 double
sort_comb_array 1000000x2 16000000 double
Total is 15000001 elements using 106000008 bytes
========================================================================
二测结果:
clear all, clc, tic, clf;
num_to_test=2000000 %amount of numbers to test
a1=(1:1:num_to_test)';
a2=(a1.*num_to_test);
array=[a1,a2]; %array where values are stored
lookupval=(randperm(num_to_test,num_to_test/2)/4)'; %lookup these random vaules of intergers and floats and get another value
lookupval = sort(lookupval);
output = zeros(length(lookupval),2);
output(:,1) = lookupval;
[c a b ] = intersect(array(:,1),lookupval);
output(b,2) =array(a,2);
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
whos
>>>num_to_test = 2000000
>>>
finally Done-elapsed time -0.3057sec- or -0.0051mins- or -0.0001hours-
>>>Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 250005x1 2000040 double
a1 2000000x1 16000000 double
a2 2000000x1 16000000 double
array 2000000x2 32000000 double
b 250005x1 2000040 double
c 250005x1 2000040 double
lookupval 1000000x1 8000000 double
num_to_test 1x1 8 double
output 1000000x2 16000000 double
Total is 11750016 elements using 94000128 bytes
=======================================================================