function [r, lab] = mset_segments( pred, ground, varargin ); % [r, lab] = mset_segments( pred, ground, varargin ) % % Categorises each contiguous segment % written by Jamie Ward, 2005 % % input: % pred, ground = [start_time stop_time label] % with all labels mapped contiguously onto % 0*,1,2,3,.. % % Any times which are not explicitly covered by a label (e.g. between % segments) is regarded as NULL. This is automatically assigned the label 0 % * You can specify NULL explicity by using the label 0. % If, however, you wish to use label 1 for NULL then set % varargin='NULL_ONE' % % ( Bug/Feature: the evaluation covers time 0 until the last stop_time in % the ground truth.) %%% % % output: [r, lab] % % r=[seg_start_time seg_end_time error_code] == label to segment mapping % where error_code corresponds to the following error pairings: % 0 = Match % 18 = ID % 20 = IU % 24 = IF % 34 = OD % 36 = OU % 66 = MD % % lab = [pred_label ground_label] for each segment in r % NLL=0; inNLL=0; if ~isempty(varargin) for n=1:length(varargin) if findstr(varargin{n},'NULL_ONE') NLL=1; inNLL=1; % NULL is already 1 end end end if NLL==0 % Shift all labels so that NULL (assumed to be 0) is moved to '1' if ~isempty(pred) pred(:,3)=pred(:,3)+1; end ground(:,3)=ground(:,3)+1; inNLL=0; NLL=1; end MATCH = 0; DEL = 2^1; % 2 UNDER = 2^2; % 4 FRAG = 2^3; % 8 INS = 2^4; % 16 OVER = 2^5; % 32 MERGE = 2^6; % 64 % Divide into segments % 1. merge pred and ground into a single sorted column of event stop times % but preserve combination of associated labels. % Ground % Make segment times into a single column, i.e.[start1 stop1 start2 stop2]' gndT=ground(:,1:2)'; gndT=gndT(:); gndT(:,2)=ones(length(gndT),1); gndT(2:2:end,2) = ground(:,3) ; % add the labels - mark label corresponding to stop time! % Remove zero length segments nonzero = [ 1 ; find( 0~= gndT(2:end,1) - gndT(1:end-1,1) ) + 1]; gndT=gndT(nonzero,:); nGndT=size(gndT,1); % Merge consecutive segments where there is no change keep=[1]; for i=2:nGndT-1 now = gndT(i,2:end); next = gndT(i+1,2:end); if now==next % remove now. else keep = [keep; i]; end end keep=[keep; nGndT]; gndT=gndT(keep,:); nGndT=size(gndT,1); % Predictions if isempty(pred) predT(1,1:2) = [0 NLL]; else predT=pred(:,1:2)'; predT=predT(:); predT(:,2)=ones(length(predT),1); predT(2:2:end,2) = pred(:,3) ; % add the labels end % Remove zero length segments nonzero = [ 1 ; find( 0~= predT(2:end,1) - predT(1:end-1,1) ) + 1]; predT=predT(nonzero,:); nPredT = size(predT,1); % Merge consecutive segments where there is no change keep=[1]; for i=2:nPredT-1 now = predT(i,2:end); next = predT(i+1,2:end); if now==next % remove now. else keep = [keep; i]; end end keep=[keep; nPredT]; predT=predT(keep,:); nPredT=size(predT,1); % Ensure prediction and ground have the same length if gndT(end,1) > predT(end,1) predT = [predT; [gndT(end,1) NLL]]; elseif gndT(end,1) < predT(end,1) %! gndT = [gndT; [predT(end,1) NLL]]; %! Truncate predictions i=length(predT)-1; while gndT(end,1) < predT(i,1), i=i-1; end if predT(i,1)==gndT(end,1) predT = predT(1:i,:); else % Truncate an event predT = predT(1:i+1,:); predT(i+1,1) = gndT(end,1); end else % Ok. end [nGnd, col] = size( gndT ); [nPred, col] = size( predT ); % Change the label columns to represent [stopTime groundL predL] gndT(:,3) = (-1)*ones(nGnd,1); predT(:,3) = predT(:,2); predT(:,2) = (-1)*ones(nPred,1); % Now merge both. segT = [gndT;predT]; [segT(:,1), iSegT] = sort(segT(:,1)); % sort only according to timing segT(:,2:3) = segT(iSegT, 2:3); % Re assign labels nSegT = size(segT,1); % The beginning time is always one (with class null) segT = [0 NLL NLL; segT]; % spread the labelling where necessary - spread backwards from marked % .. because a label is first mentioned at the _end_ of its segment. for idx= nSegT:-1:1 gL = segT(idx+1,2); % Current gnd label pL = segT(idx+1,3); % Current pred label mergeSeg = (segT(idx+1,1)-segT(idx,1) == 0); % Zero length segment if mergeSeg==true % Zero length segment, so merge both entries % to swamp out any '-1's if segT(idx,2) > -1 gL=segT(idx,2); end if segT(idx,3) > -1 pL=segT(idx,3); end segT(idx:idx+1, 2) = gL; segT(idx:idx+1, 3) = pL; end % Usually at the end of the segment file, no more information: set to % null. if gL == -1 segT(idx+1,2) = NLL; end if pL == -1 segT(idx+1,3) = NLL; end % Now set preceeding labels if (segT(idx,2) == -1) segT(idx,2) = gL; end if (segT(idx,3) == -1) segT(idx,3) = pL; end end % Remove zero length segments nonzero = [ 1 ; find( 0~= segT(2:end,1) - segT(1:end-1,1) ) + 1]; segT=segT(nonzero,:); nSegT=size(segT,1); % Re-evaluate length % Merge consecutive segments where there is no change keep=[1]; for i=2:nSegT-1 now = segT(i,[2 3]); next = segT(i+1,[2 3]); if now==next % remove now. else keep = [keep; i]; end end keep=[keep; nSegT]; segT=segT(keep,:); nSegT=size(segT,1); % Re-evaluate length segEtype = zeros(nSegT,1); % Go through all the ground truth events start = 0; for i = 1:nGnd; stop = gndT(i); % Find index of all segments within this event isegs = find( start < segT(:,1) & segT(:,1) <= stop ); % Find index of all matching segments isegsmatch = isegs( segT(isegs,2)==segT(isegs,3) ); if isempty(isegsmatch) % All segments within this event are deletions segEtype(isegs) = segEtype(isegs) + DEL; else % Any segments occurring before the first or after the last match is an underfill iunderfillsegs = [isegs(isegs < isegsmatch(1)); isegs(isegs > isegsmatch(end))]; if ~isempty(iunderfillsegs) segEtype(iunderfillsegs) = segEtype(iunderfillsegs) + UNDER; end % Any segments occurring between correctly matched segments of the % same event is a fragmenting error inonfragsegs = [isegsmatch; iunderfillsegs]; for n=1:length(isegs) if isempty( find(isegs(n)==inonfragsegs) ); segEtype(isegs(n)) = segEtype(isegs(n)) + FRAG; end end end start = stop; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Go through all the prediction events start = 0; for i = 1:nPred; stop = predT(i); % Find index of all segments within this event isegs = find( start < segT(:,1) & segT(:,1) <= stop ); % Find index of all matching segments isegsmatch = isegs( segT(isegs,2)==segT(isegs,3) ); if isempty(isegsmatch) % All segments within this event are insertions segEtype(isegs) = segEtype(isegs) + INS; else % Any segments occurring before the first or after the last match is % an overfill iunderfillsegs = [isegs(isegs < isegsmatch(1)); isegs(isegs > isegsmatch(end))]; if ~isempty(iunderfillsegs) segEtype(iunderfillsegs) = segEtype(iunderfillsegs) + OVER; end % Any segments occurring between correctly matched segments of the % same event is a merger error inonfragsegs = [isegsmatch; iunderfillsegs]; for n=1:length(isegs) if isempty( find(isegs(n)==inonfragsegs) ); segEtype(isegs(n)) = segEtype(isegs(n)) + MERGE; end end end start = stop; end if inNLL==0 % Shift all labels down again segT(:,[2 3])=segT(:,[2 3])-1; end %%%%% % Convert back into standard segment format startT = segT(1:end-1,1); % remove the superfelous first row from 'stopT' segmentResults = [startT segT(2:end,:) segEtype(2:end,:)]; r=segmentResults(:,[1 2 5]); % corresponding ground and prediction labels lab=segmentResults(:,[3 4]);