我在Google上找不到任何相关内容,所以我希望在这里找到一些帮助:)
我有一个Python列表如下:
[['hoose', 200], ["Bananphone", 10], ['House', 200], ["Bonerphone", 10], ['UniqueValue', 777] ...]
我有一个函数可以返回两个字符串之间的Levenshtein距离,对于House而言它会返回2,等等。
现在我想合并levenshtein得分为f.e的列表元素。 < 5,while(!)添加他们的分数,因此对于结果列表我想要以下内容:
[['hoose', 400], ["Bananaphone", 20], ['UniqueValue', 777], ...]
或
[['House', 400], ["Bonerphone", 20], ['UniqueValue', 777], ...]
等
只要他们的价值被添加就没关系。
列表中只有2个项目非常相似,因此任何一个项目的链式效果与很多其他项目相似都不会出现。
答案 0 :(得分:8)
为了从我的评论中提出要点,我只是从here抓住了距离的实现,并计算了一些距离:
d('House', 'hoose') = 2
d('House', 'trousers') = 4
d('trousers', 'hoose') = 5
现在,假设您的阈值为4.您必须合并House
和hoose
,以及House
和trousers
,但不是 trousers
和hoose
。你确定这样的事情永远不会发生在你的数据上吗?
最后,我认为更多的是聚类问题,因此您可能需要研究聚类算法。 SciPy提供了hierarchical clustering的实现,可以使用自定义距离函数(请注意,对于较大的数据集,这可能非常慢 - 它也会消耗大量内存)。
主要问题是决定群集质量的衡量标准,因为没有一个正确的解决方案可以解决您的问题。 This paper(pdf)为您提供了解问题的起点。
答案 1 :(得分:4)
与其他评论一样,我不确定这样做有多大意义,但我认为这是一个可以做你想要的解决方案。这是非常低效的 - O(n 2 )其中n是列表中的单词数 - 但我不确定是否有更好的方法:
data = [['hoose', 200],
["Bananphone", 10],
['House', 200],
["Bonerphone", 10],
['UniqueValue', 777]]
already_merged = []
for word, score in data:
added_to_existing = False
for merged in already_merged:
for potentially_similar in merged[0]:
if levenshtein(word, potentially_similar) < 5:
merged[0].add(word)
merged[1] += score
added_to_existing = True
break
if added_to_existing:
break
if not added_to_existing:
already_merged.append([set([word]),score])
print already_merged
输出结果为:
[[set(['House', 'hoose']), 400], [set(['Bonerphone', 'Bananphone']), 20], [set(['UniqueValue']), 777]]
这种方法的一个明显问题是,您正在考虑的单词可能与您已经考虑过的许多不同单词集足够接近,但这段代码只会将其归入第一个单词中。它找到了。我已为Space_C0wb0y's answer投票+1;)
答案 2 :(得分:2)
import Levenshtein
import operator
import cluster
class Item(object):
@classmethod
def fromList(cls,lst):
return cls(lst[0][0], lst[0][1], lst[1])
def __init__(self, name, val=0, score=0):
super(Item,self).__init__()
self.name = name
self.val = val
self.score = score
def dist(self, other):
return 100 if other is self else Levenshtein.distance(self.name, other.name)
def __str__(self):
return "('{0}', {1})".format(self.name, self.val)
def main():
myList = [
[['hoose', 5], 200],
[['House', 5], 200],
[["Bananaphone", 5], 10],
[['trousers', 5], 100]
]
items = [Item.fromList(i) for i in myList]
cl = cluster.HierarchicalClustering(items, (lambda x,y: x.dist(y)))
for group in cl.getlevel(5):
groupScore = sum(item.score for item in group)
groupStr = ', '.join(str(item) for item in group)
print "{0}: {1}".format(groupScore, groupStr)
if __name__=="__main__":
main()
返回
10: ('Bananaphone', 5)
500: ('trousers', 5), ('hoose', 5), ('House', 5)
答案 3 :(得分:0)
蓝图:
result = dict()
for item in [[['hoose', 5], 200], [['House', 5], 200], [["Bananaphone", 5], 10], ...]:
key = item[0] # ('hoose', 5)
value = item[1] # 200
if key in result:
result[key] = 0
result[key] += value
可能需要调整用于解压缩内部列表项的代码。
答案 4 :(得分:0)
你没有说清单中的项目数量,但我猜测n ^ 2的复杂性是可以的。
你也没有说你是否想要比较所有可能的对或只是相邻的对。我假设所有配对。
所以这就是这个想法:
答案 5 :(得分:0)
import Levenshtein
data = [['hoose', 200],
["Bananphone", 10],
['House', 200],
["Bonerphone", 10],
['UniqueValue', 777]]
already_merged = []
for word, score in data:
added_to_existing = False
for merged in already_merged:
for potentially_similar in merged[0]:
if Levenshtein.distance(word, potentially_similar) < 5:
merged[0].add(word)
merged[1] += score
added_to_existing = True
break
if added_to_existing:
break
if not added_to_existing:
already_merged.append([set([word]),score])
print (already_merged)
@Mark感谢您提供这种简单的解决方案。