【问题标题】:Algorithm for almost similar values search几乎相似值搜索的算法
【发布时间】:2011-03-13 04:38:14
【问题描述】:

我在 SQL Server 2008 中有 Persons 表。

我的目标是找到地址几乎相似的人。

地址用statetownstreethouseapartmentpostcodephone列描述。

由于某些州(不是美国)和人为因素(地址错误等)的某些特定差异,地址没有以相同的模式填写。

地址中最常见的错误

  1. 区分大小写
  2. 有人写了“apt.”,另一个人写了“apartment”或“ap”。 (虽然地址不是用英文写的)
  3. 空格、点、逗号
  4. 街道名称的书写差异,例如“Dr. Jones str.”或“Doctor Jones street”或“D.乔恩。 st.”或“Dr Jones st”等。

主要问题是数据的模式不同,因此很难找到相似的地址。

这种问题有什么算法吗?

提前致谢。

更新

  1. 正如我提到的,地址被分成不同的列。我应该生成一个连接列的字符串还是为每列执行您的步骤? 我假设我不应该连接列,但是如果我要分别比较列,我应该如何组织它?我是否应该为每列找到相似之处,将它们合并或相交或其他任何内容?
  2. 我应该收集一些统计数据还是某种教育算法?

【问题讨论】:

  • 我不知道这样的算法。您可以使用输入验证,至少在街道上输入正确的地址。如果您有一个单独的街道输入字段,您可以避免来自用户的“街道”之类的词,并从程序内部附加它。我不知道,但希望这会对你有所帮助。
  • 关于验证之类的东西你当然是对的,但是已经输入了大量的数据,我需要一个搜索算法。
  • 这真的取决于你想要完成什么。您是否有一个用户,输入姓名和地址,然后您将向他显示所有相似的地址以让他手动选择一个,或者您是否要将具有相似地址的所有人员自动分组在一起?
  • 我只是在给一个机会,看看他输入一个人的地址时是否有类似地址的人。如果该算法可以正常工作,它还可以用于自动建议正确的街道名称或其他任何内容,但这不是我目前的目标。
  • 我不确定您是否已经解释了您要解决的确切问题。除非有根本原因,否则“地址几乎相似”的人似乎并不是特别有用。重新考虑为什么要尝试获取此信息可能会导致一种完全不同的方法,这种方法可以证明要简单得多。例如,如果您想避免同居的人重复的群发邮件目的地:您可以从按姓氏对地址进行分组开始;那么更粗略和基本的地址比较技术可能就足够了。 另外,我怀疑 SQL 是否是正确的工具。 ;)

标签: sql sql-server algorithm string-comparison


【解决方案1】:

建议这样接近它:

  1. 从各种条目创建单词级别的 n-gram(一个 trigram/4-gram 可能会这样做)

  2. 对字符串比较进行多 x 多比较,并按字符串距离对它们进行聚类。有人建议Levenshtein;这类任务有更好的方法,Jaro-Winkler Distance 和 Smith-Waterman 效果更好。 SimMetrics 这样的库会让生活变得更轻松

  3. 一旦有了 n-gram 簇,就可以使用组成子图解析整个字符串,即 D.Jones St => Davy Jones St. => DJones St.

应该不会太难,这是一个太常见的问题。

更新:根据您上面的更新,以下是建议的步骤

  1. 将您的列连接成一个字符串,也许创建一个 db "view" 。例如,

    创建视图 vwAddress 作为 选择前 10000 州镇,街道,房屋,公寓,邮政编码, 州+镇+街道+房屋+公寓+邮政编码作为地址 来自...

  2. 编写一个单独的应用程序(例如在 Java 或 C#/VB.NET 中)并使用 JaroWinkler 之类的算法来估计组合地址的字符串距离,以创建多 x 多比较。并写入一个单独的表 地址1 |地址 n |相似度

您可以使用 Simmetrics 来获得相似度:

 JaroWinnkler objJw = new JaroWinkler()
double sim =  objJw.GetSimilarity (address1, addres n);
  1. 您还可以对它进行三元化处理,使诸如“1 Jones Street, Sometown, SomeCountry”之类的地址变为“1 Jones Street”、“Jones Street Sometown”等等...... 并比较三元组。 (甚至 4 克)以获得更高的准确度。

  2. 最后,您可以按相似度排序以获得最相似地址的集群并确定适当的阈值。不知道为什么会卡住

【讨论】:

  • 最有趣的答案,也是最难的答案。能否请您提供一些示例或任何其他链接、文章或任何内容?:)
  • @hgulyan - 你具体遇到了什么问题?谷歌搜索 n-grams,你应该会看到很多材料。一旦你(比如说)对你的条目进行了三元化,就把它们放在一个临时文件中。表,现在对行进行很多 x 很多比较。瞧。
  • SimMetrics 提供了一个庞大的字符串比较算法库,因此您可以专注于实现。只需用 Java 或 .NET 编写一些代码就可以了。
【解决方案2】:

我会尝试执行以下操作:

  • 将地址拆分为多个单词,同时去掉标点符号
  • 检查所有单词中通常以不同方式书写的模式并将它们替换为通用名称(例如,将公寓、ap.、...替换为 apt,将 Doctor 替换为 Dr.、...)
  • 将所有单词按字母顺序放回一个字符串中
  • 使用模糊字符串比较算法比较所有地址,例如文体
  • 调整 Levenshtein 算法的参数(例如,您希望在较长的字符串上允许更多差异)
  • 最后手动检查字符串

当然,保持数据“正常”的解决方案是为数据库中的每个特征设置明确的字段。否则,您最终将每隔几个月进行一次此练习。

【讨论】:

  • 主要问题是我无法删除常用名称。这样的事情太多了。一个写了“Jones”,另一个写了“Jon.”、“Jo.”、“Jone”。或者如果有人写了“D. Jones”,我不能只删除点和空格,在这种情况下我会有 DJones。如果有街头 DJones 怎么办?
  • @Patrick 是的。它不会很好用。 :) 请记住:FJones 和 DJones 在 char 级别上非常相似,但他们显然是不同的人。(或者不是......错字?) DoktorJones 和 DJones 可能是同一个人 - 但 levenshtein 会告诉 FJones 更有可能一个你想要的。替换常见的缩写是绝对必要的,以找到一个可行的解决方案。
  • 看看上面提到的 Levenshtien 算法——它不仅仅是一个简单的字符串组合!
  • 你已经把街道、城镇很好地分开了,不要把它们挤在一起。
  • @hgulyan, @InsertNickHere,如果您想允许一些差异(例如 Jones 与 Jon.),但没有其他差异(例如 DJones 和 FJones),这并不奇怪。假设某个 William Jones 将他的名字缩短为 Bill Jones,而不是突然间 WJones 和 BJones 相同。不要指望这种算法会带来奇迹。只是给你一点帮助,而不是让一切自动化。
【解决方案3】:

我在这里看到的主要问题是准确定义平等。 即使有人写乔恩。和另一个琼斯。 - 你永远无法说它们是否相同。 (Jon-Jonethan、Joneson、Jonedoe 什么的;)

我在一家公司工作,我们必须准确地处理这个问题 - 恐怕我不得不告诉你,这种检查导航系统地址列表的方式大部分时间都是“手动”完成的。缩写有时取决于上下文,还有其他一些事情使这变得困难。 Ofc 替换字符串等是用 python 完成的 - 但会告诉你这样一个缩写的含义。在少数情况下只能通过脚本完成。 (“St.” -> 可以是“Saint”和“Street”。如何决定?不可能……这是人类的工作。)。

另一个大问题是,正如你所说“是街道上的“DJones”还是一个人?还是两者兼而有之?这里是哪一个?这个 DJones 是和 Dr Jones 一样还是和 Don Jones 一样?无法确定!

您可以使用此处另一个答案提供的列表进行一些工作 - 但它会给您足够的“误报”左右。

【讨论】:

  • 你说得对,我们不知道“乔恩”是哪条街。是,但比较所有其他数据,如公寓、房屋、电话号码,我们可以找到最相似的线路。不可能有绝对正确的相似发现,这就是我写“几乎相似”的原因 :) 请注意,有些情况下您不能只用另一个字符串替换一个字符串,但您可以尝试每种情况。
  • 我不搜索一个人的名字,我只搜索一个人的地址。是否有一个有街道名称的人并不重要。我的意思是,如果删除点、逗号、空格等,你会从“D. Jones”中得到“DJones”,如果有同名的街道“DJones”,它可能类似于街道上的“DJones”。
  • @hgulyan 嗯。我试着跟着你。 :) 你的地址都是美国人?德国地址总是有一个“PLZ”“街道名称”和“编号”。也许如果开始在美国地址中找到这种相似之处会很好吗?一开始你可以只取“门牌号”和“国家身份证”(如果有的话)。但这需要所有地址都包含这些键。
  • 我的地址是亚美尼亚语,用亚美尼亚字母书写。我的列是分开的,我没有一个地址字段。它是房子,公寓,街道等,但他们把“str”。或“圣”。等在街道名称之前,如果街道名称很长,他们只写前 5-6 个字母。
【解决方案4】:

你有一个邮政编码字段!!!

那么,你为什么不为你的国家买一张邮政编码表 并用它来清理您的街道/城镇/地区/省信息?

【讨论】:

  • 不幸的是人为因素输入了 0 而不是真正的邮政编码 :(
  • 邮政编码为零或不在您的邮政编码表中的邮政编码,应手动检查。但是您的大多数邮政编码都是有效的。如果没有,那么您应该开始解雇您的交叉眼数据输入工作人员。您还应该将邮政编码表集成到您的应用中,这样用户就不必输入任何地址。
  • 这是一个很好的建议,谢谢,我会尝试为亚美尼亚找到类似的东西。还有一个问题,大多数人不知道或不记得他们的邮政编码。别笑,这是真的:)
  • 我假设人们确实知道他们住在哪个省/镇/街道:D 根据该信息,您可以检索该人的邮政编码。搜索邮政编码表时,使用街道字段中最长的单词。示例:在“Dr. Jones Str.”中,最长的单词是“Jones”。因此,只需在邮政编码表上执行类似的 '%Jones%' 即可。除了省/镇信息,您很可能会获得正确的邮政编码。获得所有邮政编码后,您可以根据邮政编码字段进行全面清理。
  • 让我们希望亚美尼亚有一个良好的邮政服务,因为他们主要跟踪/创建邮政编码表。
【解决方案5】:

我在上个世纪做过一个这样的项目。基本上,这是合并后两个客户文件的合并,涉及来自三个不同来源的名称和地址。

首先,正如许多海报所建议的那样,将所有常见的单词、缩写和拼写错误转换为常见的形式“Apt”。 “Apatment”等改为“Apt”。

然后查看姓名并确定名字的第一个字母,加上第一个姓氏。 (考虑“医学博士。亨利·德·巴斯克维尔·斯迈思爵士”并不那么容易)但不要担心哪里有歧义,两者兼而有之!所以如果你幸运的话,你会得到 HBASKERVILLE 和 HSMYTHE。现在去掉所有的元音,因为这是大多数拼写变化发生的地方,所以现在你有了 HBSKRVLL HSMTH。

您还可以从“H. Baskerville”、“Sir Henry Baskerville Smith”和不幸的是“Harold Smith”中获得这些字符串,但我们在这里讨论的是模糊匹配!

在街道、公寓和邮政编码字段中执行类似的练习。但不要丢弃原始数据!

您现在来到有趣的地方,首先比较每个原始字符串,并为每个完全匹配的字符串打 50 分。然后检查你的“标准化”字符串,并为每个完全匹配的字符串给出 20 分。然后遍历所有字符串,并为它们共有的每个四个字符或更多子字符串打 5 分。对于比较的每一对,您最终会得到一些分数 > 150 的结果,您可以将其视为某个匹配,一些分数低于 50 的部分您可以认为不匹配,而介于两者之间的一些则有一定的匹配概率。

您需要进行更多调整以通过添加各种规则来改善这一点,例如“为姓氏 'smith' 减去 20 分”。您确实必须继续运行和调整,直到您对结果匹配感到满意,但是,一旦您查看结果,您就会很好地感觉到哪个分数可以考虑为“匹配”,哪些是您需要摆脱的误报的。

【讨论】:

    【解决方案6】:

    我认为数据量可能会影响哪种方法最适合您。
    在索引来自不同艺术家的合辑中的音乐时,我遇到了类似的问题。有时是艺术家排在第一位,有时是歌曲名称排在前面,有各种分隔符样式。

    我所做的是计算具有相同值的其他条目的出现次数,以便有根据地猜测它是歌曲名称还是艺术家。

    也许您可以使用soundex 或类似的算法来查找类似的东西。

    编辑:(也许我应该澄清一下,我认为艺术家姓名比歌曲名称更容易出现。)

    【讨论】:

    • 你是如何做到“教育猜测”的? soundex 算法非常有趣,但我不需要找到发音相似的字母。这不是我的目标。
    • 我认为 soundex 是一种潜在的哈希算法,用于减少要比较的数据量。很可能 DJones 和 Dr.Jones 散列到相同(或相似)的值。您的问题标题是关于几乎相似的值。有根据的猜测:如果我的收藏中有 76 个 The Chemical Brothers,而只有 2 个 Galvanize,我只是假设出现频率最高的是艺术家的名字。
    【解决方案7】:

    您在 cmets 中提到的一件重要事情是您将以交互方式执行此操作。

    这允许解析用户输入,同时验证对任何缩写的猜测并纠正许多错误(例如电话号码输入的方​​式适用于某些联系人管理系统 - 系统尽最大努力解析和更正国家代码、地区代码和数字,但最终会向用户展示猜测并有机会更正输入)

    如果您想做得非常好,那么保留邮政编码、城镇、街道、缩写及其变体的数据库/字典可以改进数据验证和预处理。

    所以,至少你会有完全合格的地址。如果您可以对所有输入执行此操作,您将对所有数据进行分类,然后可以在某些字段上严格匹配,对其他字段不那么严格,并根据您分配的权重计算匹配分数。

    在您始终如一地对输入进行预处理之后,n-gram 应该能够找到相似的地址。

    【讨论】:

    • 你当然是对的,我们要改进数据,但是有超过一百万行,很难进行所有这些更改,但我想到了一种自动化的方法变化。
    • 我主要是在评论添加新数据。要清理现有数据,您还应该查看 stackoverflow.com/questions/682093/address-validation-api
    【解决方案8】:

    您是否为此查看过 SQL Server 集成服务? Fuzzy Lookup 组件允许您查找“接近匹配项”:http://msdn.microsoft.com/en-us/library/ms137786.aspx

    对于新输入,您可以从 .Net 代码中调用包,将要检查的值行作为一组参数传递,您可能需要保留令牌索引,以使其足够快以进行用户交互.

    这里有一个地址匹配的例子:http://msdn.microsoft.com/en-us/magazine/cc163731.aspx

    【讨论】:

      【解决方案9】:

      我假设响应时间并不重要,问题在于在数据库中查找现有地址,而不是合并重复项。我还假设数据库包含大量地址(例如 300 万个),而不是可以手动或通过 Amazon's Mechanical Turk 经济地清理的数字。

      预计算 - 识别信息含量高的地址片段。

      1. 识别每个数据库字段中使用的所有唯一词并计算它们的出现次数。
      2. 消除非常常见的单词和缩写。 (Street、st.、appt、apt 等)

      当出现输入地址时,

      1. 识别最独特的单词并搜索 (Street LIKE '%Jones%') 以查找包含这些单词的现有地址。
      2. 使用预先计算的统计信息来估计结果集中将有多少地址
      3. 如果估计的结果集太大,请选择第二个最独特的词并将其组合在搜索中(Street LIKE '%Jones%' AND Town LIKE '%Anytown%')
      4. 如果估计的结果集太小,请选择第二个最独特的词并将其组合在搜索中(Street LIKE '%Aardvark%' OR Town LIKE '%Anytown')
      5. 如果 实际 结果集太大/太小,请像以前一样重复查询添加更多术语。

      我们的想法是在地址中找到足够多的具有高信息含量的片段,这些片段可以被搜索到以给出合理数量的替代方案,而不是找到最佳匹配。为了更好地容忍拼写错误,可以使用 trigrams、tetra-grams 或 soundex 代码来代替单词。

      显然,如果您有实际的州/城镇/街道列表,那么可以在数据库和搜索地址中进行一些数据清理。 (我很惊讶Armenian postal service 没有提供这样的列表,但我知道一些邮政服务对这些信息收取过高的费用。)

      实际上,我在使用中看到的大多数系统都会尽可能通过电话号码来查找人们的帐户:显然,这是否是一种实用的解决方案取决于数据的性质及其准确性。

      (也可以考虑横向思维的方法:您能找到一家邮购邮件列表代理公司来为您清理数据库吗?他们甚至可能愿意为使用地址向您付费。)

      【讨论】:

        【解决方案10】:

        我发现了一篇很棒的文章。

        添加一些 dll 作为 sql 用户定义函数,我们可以使用 SimMetrics 库使用字符串比较算法。

        检查一下

        http://anastasiosyal.com/archive/2009/01/11/18.aspx

        【讨论】:

          【解决方案11】:

          这种变化的可能性是无数的,即使存在这样的算法,它也永远不会是万无一失的。毕竟你不能有名词拼写检查器。 您可以做的是提供先前输入的字段值的下拉列表,以便他们可以选择一个,如果特定名称已经存在。 最好为每个值(例如公寓等)设置单独的字段。

          【讨论】:

          • google 的“你的意思是”如何运作。这不是搜索相似性的算法吗?
          【解决方案12】:

          你可以把所有地址扔到像谷歌地图这样的网络服务上(我不知道这个是否合适),看看它们是否提供相同的 GPS 坐标。

          【讨论】:

          • 它们是用亚美尼亚语写的。它不会起作用,无论如何我不认为在每次搜索时以某种方式从 Windows 应用程序连接到谷歌地图是一个不错的选择。大多数用户只能访问本地网络。
          【解决方案13】:

          一种方法是将Levenshtein distance 算法应用于地址字段。这将允许您比较字符串的相似性。

          编辑 在查看了您正在处理的地址差异类型之后,这可能没有帮助。

          【讨论】:

          • 无论如何谢谢你。非常感谢任何帮助:)
          【解决方案14】:

          另一个想法是使用学习。例如,您可以了解每个缩写词及其在句子中的位置,缩写词的含义。

          3 Jane Dr. -> Dr (in 3rd position (or last)) means Drive
          Dr. Jones St -> Dr (in 1st position) means Doctor
          

          例如,您可以使用决策树并让用户训练系统。可能每个使用的几个例子就足够了。您不会对可能是 David Jones 或 Dr. Jones 的 D.Jones 之类的单字母缩写进行分类。但是在第一级翻译之后,您可以查找该镇的街道索引,看看您是否可以将 D. 扩展为街道名称。

          同样,您将在存储之前通过决策树运行每个地址。​​

          感觉应该有一些商业产品可以做到这一点。

          【讨论】:

            【解决方案15】:

            一种的可能性是在数据库中有一个字典表,将所有变体映射到单词的“正确”版本:

            *Value* | *Meaning*
            Apt.    | Apartment
            Ap.     | Apartment
            St.     | Street
            

            然后你在比较之前遍历字典中的每个单词。

            编辑:这个单独太天真了,不实用(见评论)。

            【讨论】:

            • 如果有人决定用街道名称来做这件事怎么办。我举了一个“琼斯博士”的例子?这对于公寓、街道和这类名称来说是一个很好的解决方案,但对于任何其他键来说都不是。
            • 不幼稚——只是一个非常复杂的过程中的第一步!
            猜你喜欢
            • 2021-05-03
            • 2010-11-02
            • 2012-11-15
            • 2011-05-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-10-14
            相关资源
            最近更新 更多