使用 pandas 为所有字符串对创建距离矩阵
Create distance matrix for all string pairs with pandas
我有一个列表,我想将其转换为距离矩阵
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 中是否有 eloquent 解决方案?
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[:, np.newaxis], lst[np.newaxis, :])
是一个 numpythonic 习语 -
来自 lst 数组的参数列表“每个与每个”,连续
上述函数的调用。
- 由于 Numpy 向量化,整个计算 运行s 很快,
特别是在大阵列上可以看到什么。
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
我有一个列表,我想将其转换为距离矩阵
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 中是否有 eloquent 解决方案?
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[:, np.newaxis], lst[np.newaxis, :])
是一个 numpythonic 习语 - 来自 lst 数组的参数列表“每个与每个”,连续 上述函数的调用。- 由于 Numpy 向量化,整个计算 运行s 很快, 特别是在大阵列上可以看到什么。
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