我必须根据他们的名字将一些酒店归入同一类别。我正在使用levenshtein进行分组,但是我尝试了多少,一些酒店被留在他们应该的类别之外,或者在另一类别中。
例如:所有这些酒店应属于同一类别:
=============================
Best Western Bercy Rive Gauche
Best Western Colisee
Best Western Ducs De Bourgogne
Best Western Folkestone Opera
Best Western France Europe
悉尼歌剧院贝斯特韦斯特酒店
Best Western Paris Louvre Opera
Best Western Hotel De Neuville
=============================
我有一个包含所有酒店名称(如1000行)的列表。我也有他们应该如何分组。 任何想法如何优化levenshtein,使其对我的情况更灵活?
$inserted = false;
foreach($hotelList as $key => $value){
if (levenshtein($key, $hotelName, 2, 5, 1) <= abs(strlen($key) - strlen($hotelName))){
array_push($hotelList[$key], trim($line));
$inserted = true;
}
}
// if no match was found add another entry
if (!$inserted){
$hotelList[$hotelName] = array(
trim($line)
);
}
答案 0 :(得分:2)
我会用我的想法跋涉。首先,对这样的数据进行分组或“聚类”是一个非常大的话题,我不会特别关注它,但也许可以指出理想的方向。
你通过对Levenshtein的字符串长度进行标准化来做一件很棒的事情 - 这是完全正确的,因为你避免了在很多情况下字符串的长度会过度确定相似性的问题。
但算法没有解决问题。首先,我们想要比较单词。 “Bent Eastern French Hotels”显然与“Best Western French Hotels”截然不同,但它的得分会比“Best Western Paris Bed and Breakfasts”更好。这里要掌握的是你的令牌不应该是字符而是字。
我喜欢@saury的答案,但我不确定开头的假设。相反,让我们从通常被称为“bag of words”的好事和简单开始。然后我们实现一个hashing技巧,这将允许您根据最少使用的单词包含最多信息的直觉来识别关键短语。
如果您认为酒店品牌名称接近开头,您可能总是倾向于接近字符串的开头。事实是,你的团队很可能最终成为“最佳”/“西部”的“法国”(但不是“酒店” - 为什么?)。
您希望结果更准确吗?
从现在开始,我们将不得不采取一些严肃的算法 - 享受冲浪许多堆栈溢出主题。我的直觉是我打赌许多酒店名称根本没有品牌,所以你也需要不同的类别。我的直觉也,酒店名称中重复的单词数量相对较少 - 有些单词会成为酒店名称的常客。这些事实将成为上述问题。在这种情况下,有一个非常受欢迎的(如果是陈词滥调的)技术称为k-means,这是一个有趣的介绍,可以扩展像this这样的算法(非常用php编写)将您选择的 n 关键短语作为群集的 n 维度,然后将群集中心点的大多数组成部分作为分类标记。 (这会消除“法国”,因为“法国”的命中率会非常均匀地分布在n维空间中。)
对于看起来像是一个小问题的事情,这可能有点多了 - 但我想强调的是,如果你的数据没有结构化,那么确实没有任何捷径可以做得正确
答案 1 :(得分:0)
levenshtein距离值是什么作为被视为同一组的一部分的单词之间的差异?似乎你倾向于根据最初的几个单词对酒店进行分组,这将需要一个完全不同的方法(如字典排序,比较当前字符串与下一个字符串等)。但是,如果您的用例仍然需要计算levenshtein距离,那么我建议您根据长度对字符串进行排序,然后开始将每个字符串与其他类似长度的字符串进行比较(将您自己的启发式应用于您认为的'类似'就像你可能会说isSimilar = Math.abs(str1.length - str2.length)&lt; SOME_LOWEST_DELTA_VALUE之类的东西)
答案 2 :(得分:0)