python - 如何缩短搜索列表而不是另一个列表的时间?

标签 python

我试图为数据框的特定成员更改数据框上“名称”列的值。我试图通过用相同的名称标记相似的名称来减少 len(names),这是通过 fuzzywuzzy 完成的。我试图找出一种使用嵌套循环来完成此操作的方法:

for name in names:    
    for index in df_faces['Nombre'].index:
        name2 = df_faces.loc[index,'Nombre']
        try:            
            if fuzz.ratio(name, name2) >90:                
                df_faces.loc[index,'Nombre'] = name      
        except:
            pass

其中 names 是一个列表,df_faces 是一个类似 nxm-table 的数据框,这需要很长时间,因为数据框大约有 120 万个条目,而 names 大约有 1k。

编辑:当我删除异常时会发生什么?好吧,我猜有些名字是 float 类型的,我收到了这个错误并且在 fuzzywuzzy 中,我应该转换数据类型以删除异常吗?

edit2:当我使用 check_name(x) 函数时出现此错误,实际上我不知道哪里出了问题

---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-14-6ce51e3e0802> in <module>
      3     return next(gen) if any(gen) else x
      4 
----> 5 df_faces.Nombre = df_faces.Nombre.apply(lambda x: check_name(x))

~/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/pandas/core/series.py in apply(self, func, convert_dtype, args, **kwds)
   4040             else:
   4041                 values = self.astype(object).values
-> 4042                 mapped = lib.map_infer(values, f, convert=convert_dtype)
   4043 
   4044         if len(mapped) and isinstance(mapped[0], Series):

pandas/_libs/lib.pyx in pandas._libs.lib.map_infer()

<ipython-input-14-6ce51e3e0802> in <lambda>(x)
      3     return next(gen) if any(gen) else x
      4 
----> 5 df_faces.Nombre = df_faces.Nombre.apply(lambda x: check_name(x))

<ipython-input-14-6ce51e3e0802> in check_name(x)
      1 def check_name(x):
      2     gen = (name for name in names if fuzz.ratio(name, x) > 90)
----> 3     return next(gen) if any(gen) else x
      4 
      5 df_faces.Nombre = df_faces.Nombre.apply(lambda x: check_name(x))

StopIteration: 

最佳答案

试试这段代码:

def check_name(x):
    return next((name for name in names if fuzz.ratio(name, x) > 90), x)

df_faces.Nombre = df_faces.Nombre.apply(lambda x: check_name(x))

check_name() 函数利用生成器并迭代到第一个满足条件 fuzz.ratio(name, x) > 90 的值并返回它,如果没有匹配项,则返回 x

通过DataFrame.apply函数,我们将数据帧上的计算矢量化并有效地获得所需的结果。

我对数万个数据框元素和名称列表中的数百个元素的实例进行了测试,我发布的解决方案比您在应用程序中提出的代码快大约 6 倍。

说明

你算法的瓶颈肯定是非向量化造成的。迭代和 pandas 赋值操作非常慢,这就是为什么最好尽可能对代码进行矢量化。

矢量化 是对整个数组执行操作的过程。矢量化计算的全部要点是通过将计算移至高度优化的 C 代码并利用连续的内存块来避免 Python 级循环。

其他建议: 您可以保留最常见名称的映射(字典或您认为最合适的名称){key:name_from_df, value:name_from_list}。这样您就可以在计算模糊率之前搜索 map 。如果名称在 map 上,您将有时间 O(log m),其中 m 是 map 的大小。您可以根据自己的问题选择合适的 m。

关于python - 如何缩短搜索列表而不是另一个列表的时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58566621/

相关文章:

python - 需要使用两列纬度和经度合并两个 Pandas 数据框

Python Socket(如何将文件名与文件内容分开)

python - 只要按下键,如何让游戏对象连续移动?

python - 如何匹配模式并向其添加字符

python - Pandas Dataframe 按列分组

python按排序顺序递归合并2个列表

Python:在 sqlite3 或 mysql 中存储字符串列表的正确方法

python - flask 教程 - "Attribute Error"

python - 在 Celery/Django : cannot find reference 'control' in celery. 任务.control

python - 无法访问 python 3 中的(嵌套)枚举类型(proto3)