在数据集中评分一致性

时间:2016-04-15 09:41:49

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

假设我获得了一组结构化数据。众所周知,这些数据存在问题,我需要以某种方式“评分”它们的一致性。例如,我有如下所示的数据:

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,因为数据集中的其他条目具有fieldAfoo)和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个字段,所以要查询大约9百万条),并且需要半天才能完成。然后我将SQL存储替换为elasticsearch,并且处理时间缩短到大约5个小时,是否可以以某种方式更快?

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

1 个答案:

答案 0 :(得分:1)

我刚读了你的问题并发现它非常有趣。我使用ntlk(python Natural Language Toolkit)做了类似的事情。 无论如何,在这种情况下,我认为你不需要复杂的string comparison algorithms

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

difflib.SequenceMatcher 类说:

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

顺便说一下,我认为如果你想节省时间,你可以在内存中容易地处理和处理2.000.000个3元组(相对较短的)字符串。 (参见下面的testruns和Mem Usage)

所以我写了一个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 ms = 0,417秒   - Mem用法:594 KiB

200.000 3元组:   - 比较时间:5360毫秒= 5,3秒   - Mem用法:58 MiB

2.000.000 3元组:   - 比较时间:462241毫秒= 462秒   - Mem用法: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)