为所有带熊猫的字符串对创建距离矩阵

问题描述

我有一个列表想转化为距离矩阵

from pylev3 import Levenshtein
from itertools import combinations

mylist = ['foo','bar','baz','foo','foo']

以下内容从列表中产生所有可能的对,这些对是计算矩阵所需的

list(combinations(mylist,2))

[('foo','bar'),('foo','baz'),'foo'),('bar',('baz','foo')]

然后使用以下方法完成每一对的距离:

def ld(a):
  return [Levenshtein.classic(*b) for b in combinations(a,2)]


ld(mylist)
[3,3,1,0]

但是,我坚持在熊猫中创建类似矩阵的数据框-在熊猫中是否有雄辩的解决方案?

       foo    bar   baz  foo   foo
1 foo   0     3     3    0     0
2 bar   3     0     1    3     3
3 baz   3     1     0    3     3
4 foo   0     3     3    0     0
5 foo   0     3     3    0     0

解决方法

让我们尝试稍微修改一下函数,以便我们消除重复条目的计算:

from itertools import combinations,product

def ld(a):
    u = set(a)
    return {b:Levenshtein.classic(*b) for b in product(u,u)}

dist = ld(mylist)

(pd.Series(list(dist.values()),pd.MultiIndex.from_tuples(dist.keys()))
   .unstack()
   .reindex(mylist)
   .reindex(mylist,axis=1)
)

输出:

     foo  bar  baz  foo  foo
foo    0    3    3    0    0
bar    3    0    1    3    3
baz    3    1    0    3    3
foo    0    3    3    0    0
foo    0    3    3    0    0
,

要计算Levenshtein距离,我使用了 Levenshtein 模块 (需要 pip install python-Levenshtein ),与 fuzzywuzzy

import Levenshtein as lv

然后,当我们使用 Numpy 函数时,必须转换 mylist Numpy 数组:

lst = np.array(mylist)

要计算整个结果,请运行:

result = pd.DataFrame(np.vectorize(lv.distance)(lst[:,np.newaxis],lst[np.newaxis,:]),index=lst,columns=lst)

详细信息:

  • np.vectorize(lv.distance) lv.distance 的矢量版本 功能。
  • (lst[:,:]) numpythonic 惯用语- 连续的 lst 数组中的参数列表 以上功能的调用。
  • 由于 Numpy 向量化,整个计算运行很快, 在大型阵列上可以看到什么。
  • pd.DataFrame(...)转换以上结果(一个 Numpy 数组) 到具有正确索引和列名称的DataFrame。
  • 如果需要,请使用原始函数代替 lv.distance

结果是:

     foo  bar  baz  foo  foo
foo    0    3    3    0    0
bar    3    0    1    3    3
baz    3    1    0    3    3
foo    0    3    3    0    0
foo    0    3    3    0    0