2个Pandas数据帧列之间的矢量化/矩阵计算

时间:2014-01-24 21:20:02

标签: python string pandas difflib

我正在使用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方法能够更好地处理大型数组,并且除了比率得分(不是很重要)之外,还给了我想要的一切。 Tom的答案适用于较小的数据集,但是当每列的值为~19,000时,得到了一个MemoryError。

1 个答案:

答案 0 :(得分: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 docs

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]

这应该相当有效。