【问题标题】:Python fuzzywuzzy error string or buffer expectPython的fuzzywuzzy错误字符串或缓冲区期望
【发布时间】:2015-06-03 22:26:51
【问题描述】:

我正在使用fuzzywuzzy 在公司名称的csv 中查找近似匹配项。我正在将手动匹配的字符串与不匹配的字符串进行比较,希望能找到一些有用的邻近匹配,但是,我在fuzzywuzzy 中遇到了字符串或缓冲区错误。我的代码是:

from fuzzywuzzy import process
from pandas import read_csv

if __name__ == '__main__':
    df = read_csv("usm_clean.csv", encoding = "ISO-8859-1")
    df_false = df[df['match_manual'].isnull()]  
    df_true = df[df['match_manual'].notnull()]
    sss_false = df_false['sss'].values.tolist()
    sss_true = df_true['sss'].values.tolist()


    for sssf in sss_false:
        mmm = process.extractOne(sssf, sss_true) # find best choice
        print sssf + str(tuple(mmm))

这会产生以下错误:

Traceback (most recent call last):
File "fuzzywuzzy_usm2_csv_test.py", line 21, in <module>
mmm = process.extractOne(sssf, sss_true) # find best choice
File "/usr/local/lib/python2.7/site-packages/fuzzywuzzy/process.py", line 123, in extractOne
best_list = extract(query, choices, processor, scorer, limit=1)
File "/usr/local/lib/python2.7/site-packages/fuzzywuzzy/process.py", line 84, in extract
processed = processor(choice)
File "/usr/local/lib/python2.7/site-packages/fuzzywuzzy/utils.py", line 63, in full_process
string_out = StringProcessor.replace_non_letters_non_numbers_with_whitespace(s)
File "/usr/local/lib/python2.7/site-packages/fuzzywuzzy/string_processing.py", line 25, in replace_non_letters_non_numbers_with_whitespace
return cls.regex.sub(u" ", a_string)
TypeError: expected string or buffer

这与导入指定编码的 pandas 的效果有关,我添加它是为了防止 UnicodeDecodeErrors 但具有导致此错误的连锁反应。我尝试使用str(sssf) 强制对象,但这不起作用。

所以,我在这里隔离了导致错误的一行:#N/A,,,,,,(下面粘贴的代码中的第 29 行)。我认为是 # 导致了错误,但奇怪的是它不是,它是导致问题的 A 字符,因为文件在被删除时有效。对我来说奇怪的是,下面两行的字符串是N/A,它解析得很好,但是,当我删除# 符号时,第29行不会解析,即使该字段看起来与下面的字段相同。

sss,sid,match_manual,notes,match_date,source,match_by
N20 KIDS,1095543_cha,,,2014-10-12,,20140429_fuzzy_match.ktr (stream 3)
N21 FESTIVAL,08190588_com,,,2014-10-12,,20140429_fuzzy_match.ktr (stream 3)
N21 LTD,,,,,,
N21 LTD.,04615294_com,true,,2014-12-02,,OpenCorps
N2 CHECK,08105000_com,,,2014-10-12,,20140429_fuzzy_match.ktr (stream 3)
N2 CHECK LIMITED,06139690_com,true,,2014-12-02,,OpenCorps
N2CHECK LIMITED,08184223_com,,,2014-05-05,,20140429_fuzzy_match.ktr (stream 3)
N 2 CHECK LTD,05729595_com,,,2014-05-05,,20140429_fuzzy_match.ktr (stream 2)
N2 CHECK LTD,06139690_com,true,,2014-12-02,,OpenCorps
N2CHECK LTD,05729595_com,,,2014-05-05,,20140429_fuzzy_match.ktr (stream 2)
N2E & BACK LTD,05218805_com,,,2014-05-05,,20140429_fuzzy_match.ktr (stream 2)
N2 GROUP LLC,04627044_com,,,2014-10-12,,20140429_fuzzy_match.ktr (stream 3)
N2 GROUP LTD,04475764_com,true,,2014-05-05,data taken from u_supplier_match,20140429_fuzzy_match.ktr (stream 2)
N2R PRODUCTIONS,SC266951_com,,,2014-10-12,,20140429_fuzzy_match.ktr (stream 3)
N2 VISUAL COMMUNICATIONS LIMITED,,,,,,
N2 VISUAL COMMUNICATIONS LTD,03144224_com,true,,2014-12-02,data taken from u_supplier_match,OpenCorps
N2WEB,07636689_com,,,2014-10-12,,20140429_fuzzy_match.ktr (stream 3)
N3 DISPLAY GRAPHICS LTD,04008480_com,true,,2014-12-02,data taken from u_supplier_match,OpenCorps
N3O LIMITED,06561158_com,true,,2014-12-02,,OpenCorps
N3O LTD,,,,,,
N400138,,,,,,
N400360,,,,,,
N4K LTD,07054740_com,,,2014-05-05,,20140429_fuzzy_match.ktr (stream 2)
N51 LTD,,,,,,
N68 LTD,,,,,,
N8 LTD,,,,,,
N9 DESIGN,07342091_com,true,,2015-02-07,openrefine/opencorporates,IM
#N/A,,,,,,
N A,,,,,,
N/A,red_general_xtr,true,Matches done manually,2015-04-16,manual matching,IM
(N) A & A BUILDERS LTD,,,,,,

【问题讨论】:

  • 你能提供一些示例数据吗?没有任何东西很难工作。
  • 我尝试通过添加isinstance 测试来测试字符串的出现,但没有成功。我的 csv 是 800k 行,所以我将通过拆分 csv 来隔离违规行(叹气)。当我找到它时会发布违规数据。

标签: string python-2.7 fuzzywuzzy


【解决方案1】:

默认情况下,pandas.read_csv 将字符串 'N/A' 解析为 Not a Number (NaN)

在你的情况下,这意味着你最终得到一个 nan 值而不是一个字符串。在您的示例数据集中,这发生在两个地方

从底部算起的第三行(您在问题中突出显示的行)的结果是sss_false[-3] == nan

最后一行的结果是sss_true[-1] == nan


选项 1

如果你想将字符串'N/A'解析为字符串而不是nan,这样做的方法是替换

df = read_csv("usm_clean.csv", encoding = "ISO-8859-1")

df = read_csv("usm_clean.csv", encoding = "ISO-8859-1", keep_default_na=False, na_values='')

pandas docs 中描述了这些额外选项的含义。

na_values类似列表或字典,默认无

识别为 NA/NaN 的附加字符串。如果 dict 通过,特定的每列 NA 值

keep_default_na : bool,默认为真

如果指定了 na_values 并且 keep_default_na 为 False,则默认 NaN 值将被覆盖,否则它们将被附加到

所以,上面的修改告诉pandas将空字符串识别为NA并丢弃默认值'N/A'


选项 2

如果您想丢弃第一列中带有'N/A' 的行,您需要从sss_truesss_false 中删除nan 成员。一种方法是:

sss_true = [x for x in sss_true if type(x) != str]
sss_false = [x for x in sss_false if type(x) != str]

【讨论】:

  • 非常感谢,真的很有帮助。一个问题,为什么#N/A(倒数第三个)会触发错误而N/A 不会触发? (我正在运行相同的代码,并且两行都触发了nan 返回)。
  • '#N/A'nan 放入sss_false 列表中,而底部的'N/A' 将nan 放入sss_true 列表中(由于@987654349 中的值@ 柱子)。因此,两者都会将nan 放入一个列表中,但效果会有所不同,具体取决于它是作为query 传递给extractOne(),还是作为choices。我认为您可能稍微误诊了您的错误。如果我从文件中删除 '#N/A' 行,我仍然会收到错误消息。如果我删除最后一行,我会得到一个不同的错误。如果我同时删除两者,或者按照答案进行修复,它可以正常工作
  • 我希望澄清一些事情 - 如果你愿意,我可以引用 github 代码库 - 选择中的 nan 会导致失败 here 通过 this callquery 中的 nan 仅在您执行 print sssf + str(tuple(mmm)) 时才会导致失败,此时您尝试连接 floatstr。如果可以解决所有问题,将不胜感激 accept :)
  • 不,这是完美的(而且很明显)我忘记了我们在不同的时间以不同的方式处理字符串。
【解决方案2】:

您的 sss_true 变量包含:

[
    u'N21 LTD.',
    u'N2 CHECK LIMITED',
    u'N2 CHECK LTD',
    u'N2 GROUP LTD',
    u'N2 VISUAL COMMUNICATIONS LTD',
    u'N3 DISPLAY GRAPHICS LTD',
    u'N3O LIMITED',
    u'N9 DESIGN',
    nan              # <---- note this
]

一旦你摆脱了 not-a-number 值,一切都会开始按预期工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-18
    • 2016-01-24
    • 2017-12-05
    • 1970-01-01
    • 2016-08-12
    • 2016-07-15
    • 1970-01-01
    相关资源
    最近更新 更多