假设我得到了一组结构化数据。已知数据存在问题,我需要以某种方式对它们的一致性进行“评分”。例如,我有如下所示的数据:
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
) 建议。
此外,在数据集的其他部分,还有另一种组合相对更常见(lorem
、ipsum
、dolor
)。所以后面记录的问题和前面提到的一样,只是值的组合不同而已。
我最初将所有内容转储到 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。
最佳答案
我刚刚阅读了您的问题,发现它很有趣。我使用 ntlk 做了类似的事情(python 自然语言工具包)。 无论如何,在这种情况下,我认为您不需要复杂的 string comparison algorithms .
所以我尝试了一种使用 python difflib 的方法.标题听起来很有前途:difflib — Helpers for computing deltas¶
difflib.SequenceMatcher 类说:
这是一个灵活的类,用于比较任何类型的序列对,只要序列元素是可散列的即可。
顺便说一句,我认为如果你想节省时间,你可以在内存中轻松保存和处理 2.000.000 个三元组(相对较短)的字符串。 (请参阅下面的测试运行和内存使用情况)
所以我写了一个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 个三元组: - 比较时间:417 毫秒 = 0,417 秒 - 内存使用:594 KiB
200.000 个三元组: - 比较时间:5360 毫秒 = 5.3 秒 - 内存使用:58 MiB
2.000.000 三元组: - 比较时间:462241 毫秒 = 462 秒 - 内存使用:580 MiB
因此它在时间和内存使用方面呈线性扩展。它(仅)需要 462 秒来比较 2.000.000 个三元组字符串。
结果如下所示:(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) .
关于python - 数据集中的评分一致性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36643618/