【问题标题】:How to optimize this code (finding closest string in anther column)如何优化此代码(在另一列中查找最接近的字符串)
【发布时间】:2021-08-27 15:18:47
【问题描述】:

我的锻炼需要帮助。我有两个数据框,我需要为第一个数据框中的名称找到原始拉丁名称。

我已经设法编写了这段代码,如果列表很小,它就可以工作,但是我的原始列表有更多的数据,其中一个列表中有超过 10 000 个项目,另一个列表中有大约 600 个项目,并且代码还在继续并没有给出任何东西。换句话说,它对于更大的数据效率低下且无法使用。

我曾尝试使用 numpy 数组,希望能有所帮助,但没有帮助。我还是个初学者,所以我知道一定有办法把它写得更好,但我一直不知道怎么写。

import numpy as np
import pandas as pd
import textdistance

df1 = pd.DataFrame({'id': [1, 2, 3],
                   'name': ['Peter', 'Victor', 'Claudio']})


df2 = pd.DataFrame({'id': [1, 2, 3],
                   'name_in_latin': ['Claudius', 'Petrus', 'Victor']})

name_list = []


for row in df1.itertuples():
    name_list.append(row.name)


np_sub_list = np.array([v for v in name_list])

lac_list = []

for row in df2.itertuples():
    lac_list.append(row.name_in_latin)

words = []
np_lac_list = np.array([v for v in lac_list])


for s1 in np_sub_list:
    for s2 in np_lac_list:
        if textdistance.levenshtein(s1, s2) <= 3:
            words.append((s1, s2))

for w in words:
    print(w)

#The output is ok:
#('Peter', 'Petrus')
#('Victor', 'Victor')
#('Claudio', 'Claudius')

我想要的是与拉丁语版本配对的名称,但是如何使它适用于更大的列表?

【问题讨论】:

  • 当您仍然需要逐个元素地迭代时,将所有内容包装到 np.array 不会使其更快。加速需要矢量化。也许在两个不同的列中创建一个包含所有可能匹配项的大型数据集,然后进行列对列距离测量

标签: python python-3.x pandas optimization


【解决方案1】:

尝试在轴 1 上交叉 merge 然后 apply,然后使用 sort_values + drop_duplicates 向下过滤:

df3 = df1[['name']].merge(df2[['name_in_latin']], how='cross')
df3['dist'] = df3.apply(lambda r: textdistance.levenshtein(*r), axis=1)
df3 = df3.sort_values('dist').drop_duplicates('name')

df3:

      name name_in_latin  dist
5   Victor        Victor     0
6  Claudio      Claudius     2
1    Peter        Petrus     3

可选转换为元组列表:

words = list(df3[['name', 'name_in_latin']].itertuples(index=False, name=None))

words:

[('Victor', 'Victor'), ('Claudio', 'Claudius'), ('Peter', 'Petrus')]

解释

交叉合并以获取所有值以按行进行比较:

      name name_in_latin
0    Peter      Claudius
1    Peter        Petrus
2    Peter        Victor
3   Victor      Claudius
4   Victor        Petrus
5   Victor        Victor
6  Claudio      Claudius
7  Claudio        Petrus
8  Claudio        Victor

计算距离:

      name name_in_latin  dist
0    Peter      Claudius     8
1    Peter        Petrus     3
2    Peter        Victor     4
3   Victor      Claudius     8
4   Victor        Petrus     6
5   Victor        Victor     0
6  Claudio      Claudius     2
7  Claudio        Petrus     7
8  Claudio        Victor     7

然后排序,使最小的距离在前,并删除重复的名称以仅保留最小的距离。

【讨论】:

    猜你喜欢
    • 2020-02-13
    • 2012-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 2021-09-15
    相关资源
    最近更新 更多