【问题标题】:Create distance matrix for all string pairs with pandas使用 pandas 为所有字符串对创建距离矩阵
【发布时间】:2020-09-04 03:28:38
【问题描述】:

我有一个列表想要转换成距离矩阵

from pylev3 import Levenshtein
from itertools import combinations

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

以下从列表中生成所有可能的对,需要计算矩阵

list(combinations(mylist,2))

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

然后可以通过以下方式计算每对的距离:

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


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

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

       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

【问题讨论】:

  • 您的mylist 有重复条目。这是故意的吗?
  • 是的,这是故意的

标签: python pandas string matrix distance


【解决方案1】:

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

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

【讨论】:

  • 我收到NameError: name 'dist' is not defined
  • 抱歉,复制/粘贴时遗漏了一个单元格。查看更新的答案。
【解决方案2】:

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

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[:, np.newaxis], lst[np.newaxis, :]) 是一个 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

【讨论】:

    最近更新 更多