【问题标题】:Trying to Perform Fuzzy Matching in Python尝试在 Python 中执行模糊匹配
【发布时间】:2019-06-11 05:15:25
【问题描述】:

我正在尝试执行一个模糊的命令来比较数据框中的两列。我想知道一列('Relationship')中的字符串是否存在于另一列('CUST_NAME')中,甚至部分存在。然后在与前一列 ('CUST_NAME') 相同的列上对第二列 ('Dealer_Name') 重复该过程。我目前正在尝试运行以下代码:

这是我的数据框:

RapDF1 = RapDF[['APP_KEY','Relationship','Dealer_Name','CUST_NAME']]

这里是模糊匹配:

from fuzzywuzzy import process, fuzz

RapDF1.assign(dealer_compare=[process.extract(i, RapDF1['Dealer_Name'], limit=3) for i in RapDF1['CUST_NAME']])
RapDF1.assign(broker_compare=[process.extract(i, RapDF1['Relationship'], limit=3) for i in RapDF1['CUST_NAME']])

但是,我收到以下 python 错误:

TypeError                                 Traceback (most recent call last)
<ipython-input-76-2faf28514c26> in <module>()
     52 # Attempt 7
     53 
---> 54 RapDF1.assign(dealer_compare=[process.extract(i, RapDF1['Dealer_Name'], limit=3) for i in RapDF1['CUST_NAME']])
     55 RapDF1.assign(broker_compare=[process.extract(i, RapDF1['Relationship'], limit=3) for i in RapDF1['CUST_NAME']])
     56 

<ipython-input-76-2faf28514c26> in <listcomp>(.0)
     52 # Attempt 7
     53 
---> 54 RapDF1.assign(dealer_compare=[process.extract(i, RapDF1['Dealer_Name'], limit=3) for i in RapDF1['CUST_NAME']])
     55 RapDF1.assign(broker_compare=[process.extract(i, RapDF1['Relationship'], limit=3) for i in RapDF1['CUST_NAME']])
     56 

C:\ProgramData\Anaconda3\lib\site-packages\fuzzywuzzy\process.py in extract(query, choices, processor, scorer, limit)
    166     """
    167     sl = extractWithoutOrder(query, choices, processor, scorer)
--> 168     return heapq.nlargest(limit, sl, key=lambda i: i[1]) if limit is not None else \
    169         sorted(sl, key=lambda i: i[1], reverse=True)
    170 

C:\ProgramData\Anaconda3\lib\heapq.py in nlargest(n, iterable, key)
    567     # General case, slowest method
    568     it = iter(iterable)
--> 569     result = [(key(elem), i, elem) for i, elem in zip(range(0, -n, -1), it)]
    570     if not result:
    571         return result

C:\ProgramData\Anaconda3\lib\heapq.py in <listcomp>(.0)
    567     # General case, slowest method
    568     it = iter(iterable)
--> 569     result = [(key(elem), i, elem) for i, elem in zip(range(0, -n, -1), it)]
    570     if not result:
    571         return result

C:\ProgramData\Anaconda3\lib\site-packages\fuzzywuzzy\process.py in extractWithoutOrder(query, choices, processor, scorer, score_cutoff)
     76 
     77     # Run the processor on the input query.
---> 78     processed_query = processor(query)
     79 
     80     if len(processed_query) == 0:

C:\ProgramData\Anaconda3\lib\site-packages\fuzzywuzzy\utils.py in full_process(s, force_ascii)
     93         s = asciidammit(s)
     94     # Keep only Letters and Numbers (see Unicode docs).
---> 95     string_out = StringProcessor.replace_non_letters_non_numbers_with_whitespace(s)
     96     # Force into lowercase.
     97     string_out = StringProcessor.to_lower_case(string_out)

C:\ProgramData\Anaconda3\lib\site-packages\fuzzywuzzy\string_processing.py in replace_non_letters_non_numbers_with_whitespace(cls, a_string)
     24         numbers with a single white space.
     25         """
---> 26         return cls.regex.sub(" ", a_string)
     27 
     28     strip = staticmethod(string.strip)

TypeError: expected string or bytes-like object

【问题讨论】:

  • 嗨,@NateO!请提供数据示例。猜猜数据集中有非字符串条目,你应该检查一下。你用的是什么版本的python,2.x还是3.x?
  • 您好!我正在使用 Python 3.6。所有字段中只有字符串值,但在未提供条目时确实存在 NaN 值。
  • 提供数据帮助人们摆脱困境的最佳方式是什么?
  • 将数据帧打印到终端(只是打印,而不是 jupyter notebook 的 html 视图)并将其作为代码块发布。 NaN 有一个float 类型,并且在使用fuzzywuzzy 搜索时可能会导致错误,尝试将其删除/替换为空字符串左右。我将其发布为带有简化示例的答案。

标签: python fuzzywuzzy


【解决方案1】:

数据框中可能有nan的值,nan的类型为float并导致错误:

from fuzzywuzzy import process, fuzz
import pandas as pd
import numpy as np

df_nan = pd.DataFrame({'text1': ["quick", "brown", "fox"], "text2": ["hello", np.NaN, "world"]})
df_nan
Out:
   text1  text2
0  quick  hello
1  brown    NaN
2    fox  world

只是导致相同错误的代码示例:

[process.extract(i, df_nan['text1'], limit=3) for i in df_nan['text2']]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
...
/usr/local/lib/python3.6/dist-packages/fuzzywuzzy/string_processing.py in replace_non_letters_non_numbers_with_whitespace(cls, a_string)
     24         numbers with a single white space.
     25         """
---> 26         return cls.regex.sub(" ", a_string)
     27 
     28     strip = staticmethod(string.strip)

TypeError: expected string or bytes-like object

用一些令牌替换nan(选择正确的令牌将是一项困难且依赖数据的任务,可能空字符串是一个不好的选择):

df = df_nan.fillna('##SOME_TOKEN##') 
[process.extract(i, df['text1'], limit=3) for i in df['text2']]
Out:
[[('fox', 36, 2), ('brown', 20, 1), ('quick', 0, 0)],
 [('brown', 36, 1), ('fox', 30, 2), ('quick', 18, 0)],
 [('fox', 30, 2), ('brown', 20, 1), ('quick', 0, 0)]]

我想替换或删除所有非字符串值会有所帮助。

【讨论】:

  • 感谢 Mikhail,我现在正在尝试该代码!错误的原因是有道理的。它现在正在运行,但似乎需要相当长的时间。我正在比较大约 90,000 条记录。取决于记录,fuzzywuzzy 是资源密集型还是耗时?我的进程可能会停止。
  • 它具有O(n squared) 复杂性,其中n 是多行,并且每个字符串都比较-idk 实际上使用了哪种算法-但我猜是O(k squared) 其中k 是字符串的长度,但它是 _al least_ O(k)。此外,python 不是快速语言,因此需要一些时间。尝试在一个小片段上运行此代码,即 df ±2000 个条目,测量执行时间,并将其乘以(90000 / 2000)^2,这样您将得到一个近似的 ETA。
猜你喜欢
  • 1970-01-01
  • 2013-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多