The "Did you mean..." routine
Show older comments
Is there a way to access the routine that looks for approximate string matches? I have an n x 1 cell array. I know how to search for exact matches, or case-insensitive matches, or matches of the first few characters, but my list has tens of thousands of entries and sometimes the user does not know exactly what phrase to search for. I'd like my script to be robust enough to allow the user to search the list below for a phrase like "algebra 2" and offer a list of close matches or, "Did you mean algebra II?"
math
science
reading
chemistry
algebra I
algebra II
gym
Ideas?
Accepted Answer
More Answers (3)
See EDIT 2 and 3 below for a better version of the initial answer.
Here is another idea, just for the fun of it:
classNames = {'math', 'science', 'reading', 'chemistry', 'algebra I', ...
'algebra II', 'gym'} ;
aClass = 'algebra 1' ;
% - Define a "spectrum" function based on letter freq.
spec = @(name) accumarray(upper(name.')-31, ones(size(name)), [60 1]) ;
% - Compute spec of chosen class, compare (norm based) with other class
% names, and find order of names based on min norm.
spec_aClass = spec(aClass) ;
spec_dist = arrayfun(@(k) norm(spec(classNames{k})-spec_aClass), ...
1:numel(classNames)) ;
[~,idx] = sort(spec_dist) ;
Then propose as many ordered names as you want; for example, having run the code above..
>> nearbyNames = classNames(idx(1:4))
nearbyNames =
'algebra I' 'algebra II' 'reading' 'math'
Of course, the method for computing a "spectrum" is a bit too simplistic, and we should filter aClass and classNames first to ensure that no character is outside of ASCII range 32-90 when "uppered" (which could be done by eliminating them =[] or by replacing them with spaces).
Note that you could also try to see how LIKE is implemented in SQL servers.
EDIT 1: just had another idea .. if aClass is not found in classNames, you could just define buffer = sort([classNames, aClass]), then look for aClass in buffer and propose +/-1 or 2 elements around the matching position. This would be less robust than what I first proposed though, in the sense that if aClass were defined as 'lagebra II' (permuted first two letters), it would not be close to 'algebra II' at all.
EDIT 2: just made a function out of it, with a simple character filtering mechanism.
EDIT 3: corrected a few small mistakes which didn't alter the functioning.
function nearbyNames = getNearbyNames(classNames, aClass, n)
persistent P__clean ;
if isempty(P__clean)
P__clean = 32 + zeros(256, 1) ;
P__clean(48:90) = 48:90 ;
end
spec = @(name) accumarray(P__clean(upper(name))-31, ones(size(name)), [59 1]) ;
spec_aClass = spec(aClass) ;
spec_dist = cellfun(@(name) norm(spec(name)-spec_aClass), classNames) ;
[~,idx] = sort(spec_dist) ;
nearbyNames = classNames(idx(1:min(n,length(idx)))) ;
end
With that ..
>> getNearbyNames(classNames, aClass, 4)
ans =
'algebra I' 'algebra II' 'reading' 'math'
Note that instead of n for the size of nearbyNames to return, you could pass a float (threshold) which characterizes a maximal norm for being defined as nearby, and have something like:
[sds,idx] = sort(spec_dist) ;
nearbyNames = classNames(idx(sds<=threshold)) ;
3 Comments
Chad Greene
on 7 Aug 2014
Joseph Cheng
on 7 Aug 2014
Edited: Joseph Cheng
on 7 Aug 2014
wouldn't ismember() work out for this as well?
Y = cellfun(@(x) sum(ismember(lower(x),lower('algebra I')))/((length(x)+length('algebra I'))/2),X)
where the above x is the cell list of your classes/subject. then if you get a value of 1 there is an exact match. if there are no result of 1 then put a threshold say 80% match or highest match would be the suggested result.
here looking at the average of the input string and the comparison string you could put in a partial string for the input and look for the highest matches.
Additional conditions could be used when there are more than 1 match (since above method would allow for misspelled words). then look for which one has the similar order or direct string compare (one to one and pad if necessary.) And hope not too many anagrams are in your list.
Chad Greene
on 16 Aug 2014
Nikolay S.
on 26 Nov 2013
1 vote
Having asked the same question I find those functions promising: http://www.mathworks.com/matlabcentral/fileexchange/36981-find-nearest-matching-string-from-a-set http://www.mathworks.com/matlabcentral/fileexchange/17585-calculation-of-distance-between-strings
Image Analyst
on 15 Aug 2013
0 votes
Perhaps drilling down into the citations in this might lead somewhere: http://infolab.stanford.edu/~backrub/google.html
2 Comments
Chad Greene
on 15 Aug 2013
Image Analyst
on 15 Aug 2013
I didn't think it would be easy. I'm sure web sites have whole teams of people working on parsing inputs and trying to figure out what people really meant, or figure out similar terms, when they typed in something.
Categories
Find more on Programming in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!