我在MATLAB中编写程序(必须使用MATLAB,不能真正使用MEX)来过滤非常大量的数据。
我需要实现的其中一个过滤器要求我将时间戳向量与已知“坏”时间列表进行比较,而不会出现其他时间戳。
一个典型的时间戳矢量有大约2,000,000个条目,我有一个大约300,000个“坏时间”的列表。
以下是一个工作示例,如果TIME=[1, 2.3, 5.5, 9.1, 10];
和BAD_TIMES=[5.2, 9.3];
,我们有一个容差tolerance=0.25;
,则TIME
和4.95 and 5.45
之间的所有时间戳都在9.05 and 9.55
和TIME_CLEAN
之间必须删除{1}}。这意味着已清理的向量TIME_CLEAN=[1, 2.3, 5.5, 10];
应等于bsxfun()
。
这个问题很容易解决,我已经用大约4或5种不同方式解决了这个问题。但是,对于1,000,000个时间戳作业,此问题可能需要一个小时才能计算出来。
我希望在典型的Core-i7工作站上在2分钟内解决这类问题,这个过滤器可以通过这么多时间条目来实现。
我已经包含了此代码的工作版本。我理解代码矢量化和诸如NO_OF_TIMESTAMPS
之类的函数可以提供帮助,但相对于我对此滤波器所需的效率类型而言,改进是微不足道的。
有没有非常聪明的方法以非常有效的方式解决这个问题?任何帮助将不胜感激。
P.S。以下代码已完成;它生成设置问题所需的所有数据并解决它(虽然非常慢!)。将clear all %% CLEAR WORKSPACE
close all %% CLOSE FIGURES
clc %% CLEAR COMMAND WINDOW
NO_OF_TIMESTAMPS=10000; %% NUMBER OF TIMESTAMPS IN ORIGINAL DATA
TOLERANCE=2; %% TOLERANCE AROUND TIMESTAMP
A=sort(randi(NO_OF_TIMESTAMPS/10,NO_OF_TIMESTAMPS,1)); %% GENERATE ARTIFICIAL TIMESTAMPS
B=unique(sort(round(randi([NO_OF_TIMESTAMPS/2,NO_OF_TIMESTAMPS*5],[NO_OF_TIMESTAMPS/10,1])/10))); %% GENERATE ARTIFICIAL LIST OF BAD TIMESTAMPS
B_LB=B-TOLERANCE; %% CREATE A LIST OF LOWERBOUND BAD TIMESTAMPS
B_UB=B+TOLERANCE; %% CREATE A LIST OF UPPERBPUND BAD TIMESTAMPS
B_RANGE=[B_LB B_UB]; %% AUGMENTED MATRIX COMPOSED OF VECTORS B_LB and B_UB
A_ROWS=size(A,1); %% SIZE OF A;
B_ROWS=size(B,1); %% SIZE OF B;
tic; %% START TIMER
A_TO_CLEAN=ones(A_ROWS,1); %% BOOLEAN VECTOR TO BE USED IN FILTERING
for ii=1:A_ROWS
for jj=1:B_ROWS
if A(ii)>=B_RANGE(jj,1) && A(ii)<=B_RANGE(jj,2) %% CHECK EACH MEMBER OF A VERSUS EACH MEMBER OF B_RANGE
A_TO_CLEAN(ii)=0; %% SET INDEX VECTOR A_TO_CLEAN = 0 SO THAT WE CAN DELETE LATER
break; %% A(ii) CAN ONLY BE ERASED ONCE, SO BREAK jj LOOP AND GO TO NEXT ii
end
end
end
CLEAN=A(~~A_TO_CLEAN); %% DELETE A VIA LOGICAL INDEXING
toc; %% END TIMER
clearvars -except A B_RANGE CLEAN %% ONLY SHOW RELEVANT VARIABLES
变量更改为更大的值(例如1,000,000)以观察其爬行!
{{1}}
答案 0 :(得分:4)
使这种效率首先对两个向量进行排序的技巧。然后通过其中一个向量创建一个简单的循环,同时保持索引到描述最近元素的第二个向量。也就是说,你会有像
这样的东西for ix1 = 1:length(timestamps)
while (badTimes(ix2) < timestamps(ix1)
ix2 = ix2+1;
end
%check timestamp(ix1) against badTimes(ix2), and maybe badTimes(ix2 + 1) and badTimes(ix2 - 1)
end
排序相对有效,尤其是使用内置插件。现在你只需要一个循环。
这现在具有a merge sort算法的相似部分。
答案 1 :(得分:3)
在我的计算机上,1e6'时间步长'需要0.025秒。该方法线性地通过A,在逐步通过B_RANGE时更新索引。 “阵列结束”案件需要特别小心。
BR=B_RANGE';
C=logical(ones(size(A)));
j=1;
i=1;
tic;
while i<=A_ROWS && j<=B_ROWS
if A(i)==99
i=1;
end
% find start of bad signal
while A(i)<BR(1,j) && i<A_ROWS
i=i+1;
end
% finish at the end of A
if i==A_ROWS
break;
end
ii=i;
% find end of bad signal
while A(ii)<=BR(2,j) && ii<A_ROWS
ii=ii+1;
end
% special case for end of array
if A(ii)==A(ii-1)
ii=ii+1;
end
% mark bad signal entries
C(i:ii-1)=false;
i=ii;
j=j+1;
end
AM=A(C);
toc
答案 2 :(得分:0)
这需要0.3秒:
%% generate random measured and bad time samples
t = sort(1e4 * rand(2e6, 1));
t_bad = sort(1e4 * rand(3e5, 1));
%% find bad indexes
tolerance = 0.01;
idx_bad = ismember(round(t / tolerance), round(t_bad / tolerance));