问题描述
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