2

我正在使用 difflib 比率来计算 2 个字符串之间的相似性:

ratio = difflib.SequenceMatcher(None, 'string1', 'string2').ratio()

输出是从 0-1 的单个浮点值,可以解释为匹配分数。

我要做的是创建一个列,其中包含基于max(ratio)值和其他值列表之间的最佳匹配。

因此,如果:

df.col1 = 'maria','fred','john'

和:

df2.col1 = 'mary','orange','maria'

df.bestmatch'maria', 'fred' and 'john'将包含基于df2.col1值的最佳匹配。

我觉得使用该.apply方法可以做到这一点,但我无法理解如何计算df.col1反对中的每个值df2.col1

更新: difflib.get_close_matches 方法能够更好地处理大型数组,并给了我想要的一切,除了比率分数(没什么大不了的)。下面汤姆的回答适用于较小的数据集,但当每列约为 19,000 个值时会出现 MemoryError。

4

1 回答 1

1

编辑以回应您的评论:

In [164]: df = pd.DataFrame({'col1': ['maria','fred','john'], 'col2': ['mary','orange','maria']})

使所有组合(玛丽亚,玛丽),(玛丽亚,橙色),(玛丽亚,玛丽亚),(弗雷德......)

In [165]: combos = itertools.product(df.col1, df.col2)

combos将是一个扁平的元组列表,总共有('maria', 'mary') ...,9 个。由于我们需要每个名称的最佳匹配,我们需要按名称对元组进行分组col1

In [166]: groups = [list(g) for k, g in itertools.groupby(combos, lambda x: x[0])]

现在我们有一个包含三个列表的列表:[[('maria', 'mary'), ('maria', 'orange'), ('maria', 'maria')], [...]]. 第二个参数groupby是分解组的键。查看itertools 文档

In [167]: groups
Out[167]: 
[[('maria', 'mary'), ('maria', 'orange'), ('maria', 'maria')],
 [('fred', 'mary'), ('fred', 'orange'), ('fred', 'maria')],
 [('john', 'mary'), ('john', 'orange'), ('john', 'maria')]]

定义一个辅助函数:

def get_best(group):
    k = group[0][0]
    ratios = {x[1]: difflib.SequenceMatcher(None, *x).ratio() for x in group}
    winner = max(ratios.iteritems(), key=lambda x: x[1])
    return winner[1] # mess with this to return original name, mathcihng name, ratio

这是您将应用于groups. 就像我们之前的手对SequenceMatcher来获得比率一样。只是现在我们需要保留这个名字。所以在那个函数x中有一个像('maria', 'mary'). 我们需要知道最佳匹配中的名称和最佳匹配的比例,因此我将它们放入带有{name: ratio}. 这里的另一件事是max需要第二个参数。这次只是说要最大化的是x[1],比率。

并获得最佳匹配:

In [173]: best = [get_best(group) for group in groups]

In [175]: df['best_match'] = best

In [176]: df
Out[176]: 
    col1    col2 best_match
0  maria    mary      maria
1   fred  orange     orange
2   john   maria     orange

[3 rows x 3 columns]

这应该是相当有效的。

于 2014-01-25T15:14:58.917 回答