【问题标题】:Scoring consistency within dataset数据集中的评分一致性
【发布时间】:2016-04-19 15:54:13
【问题描述】:

假设给定一组结构化数据。已知数据存在问题,我需要以某种方式对它们的一致性进行“评分”。比如我有如下数据:

fieldA | fieldB | fieldC
-------+--------+-------
foo    | bar    | baz
fooo   | bar    | baz
foo    | bar    | lorem
..     | ..     | ..
lorem  | ipsum  | dolor
lorem  | upsum  | dolor
lorem  | ipsum  | baz

因此假设第一行被认为是正确的条目,因为与第二行和第三行中的记录相比,该组合中的数据相对更多。在第二行中,fieldA 的值应为foo(由于拼写错误导致不一致)。然后在第三行中,fieldC 的值应为 baz,因为数据集中的其他条目与 fieldA (foo) 和 fieldB (bar) 的值相似。

此外,在数据集的其他部分,还有另一种相对更常见的组合(loremipsumdolor)。所以下面记录中的问题和前面提到的一样,只是值组合不同。

我最初将所有内容转储到 SQL 数据库,并使用带有 GROUP BY 的语句来检查字段值的一致性。因此,对于我要检查一致性的每个字段以及每条记录,都会有 1 个查询。

SELECT    fieldA, count(fieldA)
FROM      cache
WHERE     fieldB = 'bar' and fieldC = 'baz'
GROUP BY  fieldA

然后我可以通过将记录引用到下面的对象(上一个SQL查询的处理结果)来检查记录的fieldA的值是否与其余的一致。

{'foo': {'consistency': 0.99, 'count': 99, 'total': 100}
 'fooo': {'consistency': 0.01, 'count': 1, 'total': 100}}

但是它非常慢(数据集有大约 220 万条记录,我正在检查 4 个字段,因此进行了大约 900 万次查询),并且需要半天才能完成。然后我把SQL存储换成了elasticsearch,处理时间缩到5小时左右,能不能快点?

也只是出于好奇,我是不是在这里重新发明了一个轮子?有现成的工具吗?目前它是在 Python3 中实现的,带有 elasticsearch。

【问题讨论】:

    标签: python python-3.x data-integrity data-cleaning


    【解决方案1】:

    我刚刚阅读了您的问题,发现它很有趣。我使用ntlk(python 自然语言工具包)做了类似的事情。 无论如何,在这种情况下,我认为您不需要复杂的string comparison algorithms

    所以我尝试了一种使用 python difflib 的方法。标题听起来很有希望:difflib — 计算增量的助手

    difflib.SequenceMatcher 类说:

    这是一个灵活的类,用于比较任何类型的序列对,只要序列元素是可散列的。

    顺便说一句,我认为如果你想节省时间,你可以在内存中轻松地保存和处理 2.000.000 个(相对较短的)字符串的 3 元组。 (请参阅下面的测试运行和内存使用)

    所以我写了一个demo App,它产生了 2.000.000 个(你可以改变它)3 元组的随机稍微洗牌的字符串。改组后的字符串基于并与您的默认模式进行比较:['foofoo', 'bar', 'lorem']。然后使用 difflib.SequenceMatcher 比较它们。一切尽在记忆中。

    这是比较代码:

    def compare(intuple, pattern_list):
        """
        compare two strings with difflib
        intuple: in this case a n-tuple of strings
        pattern_list: a given pattern list.
        n-tuple and list must be of the same lenght.
    
        return a dict (Ordered) with the tuple and the score
        """
        d = collections.OrderedDict()
        d["tuple"] = intuple
        #d["pattern"] = pattern_list
        scorelist = []
        for counter in range(0,len(pattern_list)):
            score = difflib.SequenceMatcher(None,intuple[counter].lower(),pattern_list[counter].lower()).ratio()
            scorelist.append(score)
        d["score"] = scorelist
        return d
    

    以下是运行时和内存使用结果:

    2000 个 3 元组: - 比较时间:417 毫秒 = 0,417 秒 - 内存使用量:594 KiB

    200.000 个三元组: - 比较时间:5360 毫秒 = 5.3 秒 - 内存使用量:58 MiB

    2.000.000 个三元组: - 比较时间:462241 毫秒 = 462 秒 - 内存使用量:580 MiB

    因此它在时间和内存使用量上呈线性关系。它(仅)需要 462 秒来比较 2.000.000 个 3 元组字符串。

    结果如下所示:(以 200.000 行为例)

    [ TIMIMG ]
    build                function took 53304.028034 ms
    [ TIMIMG ]
    compare_all          function took 462241.254807 ms
    [ INFO ]
    
    num rows: 2000000
    pattern: ['foofoo', 'bar', 'lorem']
    [ SHOWING 10 random results ]
    0: {"tuple": ["foofoo", "bar", "ewrem"], "score": [1.0, 1.0, 0.6]}
    1: {"tuple": ["hoofoo", "kar", "lorem"], "score": [0.8333333333333334, 0.6666666666666666, 1.0]}
    2: {"tuple": ["imofoo", "bar", "lorem"], "score": [0.6666666666666666, 1.0, 1.0]}
    3: {"tuple": ["foofoo", "bar", "lorem"], "score": [1.0, 1.0, 1.0]}
    ....
    

    如您所见,您会根据字符串与模式的相似度获得分数。 1.0 表示相等,分数越低越差。

    difflib 被认为不是最快的算法,但我认为 7 分钟对半天或 5 小时来说是相当大的改进。

    我希望这对您有所帮助(并且不是完全的误解),但是昨天编写这个程序很有趣。我学到了很多东西。 ;) 例如,使用tracemalloc 跟踪内存使用情况。以前从未这样做过。

    我把代码放到github (as a one file gist)

    【讨论】:

    • 我没有时间查看解决方案,我可以用它来为包含多个术语的条目“评分”吗?例如“foo bar”与“fooz bar”
    • 应该也可以。 difflib 使用哈希进行比较。所以任何可散列的东西都会起作用。
    • 大声笑,看起来不像我需要的工具。因为我没有事先为每个字段提供所有可能(相对)正确的规范值和组合。
    • 您可以在数据库中进行比较运行时准确地进行比较。就像你在问题中所说的那样。据我了解,您有 2.2 Mio 数据集和比较模式。没关系。只需将任何内容读入 Mem 并运行比较功能。没有必要事先准备任何东西。
    • 不确定是否相关,但我已经用另一个示例更新了问题
    猜你喜欢
    • 2016-07-13
    • 2017-09-26
    • 2022-08-06
    • 2017-09-02
    • 1970-01-01
    • 2016-04-03
    • 1970-01-01
    • 2015-01-09
    • 2020-11-18
    相关资源
    最近更新 更多