我使用Levensteins距离算法来比较产品名称和产品名称列表,以找到最接近的匹配.但是,我需要稍微调整一下.我正在使用dotnetperls.com的例子.
假设我有一个来自我自己的数据库的2000个产品名称的列表A.我自己卖掉所有这些产品.
然后我突然从我的一个供应商处获得了一个清单B,其中包含产品名称和每种产品的新价格.这可能每年发生一次以上,所以我想开发软件来手动完成工作.
问题是这个供应商不是很擅长一致性.所以他时不时地对名字做些小改动,这意味着我不能做一个简单的字符串比较.
我已经实现了距离算法,但它并不能满足我的需求. – 还是!
在浏览我的供应商列表时,我遇到了一个名为的产品
American Crew Anti Dandruff Shampoo 250 ml
该产品与我自己的产品成功匹配
American Crew Anti-Dandruff 250 ml.
距离为10.
问题
我还遇到了一个名为的产品
American Crew 3-In-1 Shampoo 450 ml.
这是错误的匹配
American Crew Daily Shampoo 450 ml.
而不是我的
American Crew 3 in 1 450 ml.
我明白为什么!但我不确定如何从这里改变算法.
有任何想法吗?
顺便说一句,我对算法并不是很好,但我相信某种称量可以帮助我在这里.
编辑:
计算时间并不是真正的问题.即使需要十个小时才能完成,它仍然比手动完成要好得多:P
解决方法
double levWeight = 1.0; // adjust these weights as you see fit double matchWeight = 1.0; // add whatever to here you'd like var splitOn = new[] { ' ','!','"','#','$','%','&','\'','(',')','-' }; Func<string,string[]> split = s => s.Split(splitOn,StringSplitOptions.RemoveEmptyEntries); var matches = from xx in mine let xp = split(xx.Name) select new { Item = xx,Matches = (from yy in theirs let yp = split(yy.Name) /* found how many name components match */ let mm = xp.Intersect(yp,StringComparer.OrdinalIgnoreCase).Count() /* find the Levenshtein distance of the two names */ let ld = LevDist(xx,yy) /* weight our two criteria */ let ww = (matchWeight * mm) + (levWeight / ld) /* should match on at least ONE name component */ where mm > 0 orderby ww descending select yy) };
当您对数据语料库运行时,我收到以下输出:
>美国船员Anti Dandruff洗发水250毫升
>美国船员抗头皮屑250毫升
>美国船员每日洗发水450毫升
>美国船员3合1 450毫升
>美国船员3合1洗发水450毫升
>美国船员3合1 450毫升
>美国船员每日洗发水450毫升
>美国船员抗头皮屑250毫升
如果您有更多条件,则只需将它们添加到查询中(与其他let子句一起内联)并对其结果应用一些权重.
其他可能的应用程序是“相同顺序的名称组件”:
let or = xp.Zip(yp,(a,b) => String.Compare(a,b,true)) .TakeWhile(c => c == 0) .Count()