【问题标题】:Python - fuzzy string matching - TypeError: expected string or bytes-like objectPython - 模糊字符串匹配 - TypeError:预期的字符串或类似字节的对象
【发布时间】:2020-05-20 08:10:51
【问题描述】:

我正在尝试使用以下代码在 Python 中模糊合并两个数据帧:

import pandas as pd
from fuzzywuzzy import fuzz
from fuzzywuzzy import process
    prospectus_data_file = 'file1.xlsx'
    filings_data_file = 'file2.xlsx'
    prospectus = pd.read_excel(prospectus_data_file)
    filings = pd.read_excel(filings_data_file)
    #all_data_st = pd.merge(prospectus, filings, on='NamePeriod')   
    filings['key']=filings.NamePeriod.apply(lambda x : [process.extract(x, prospectus.NamePeriod, limit=1)][0][0][0])
    all_data_st = filings.merge(prospectus,left_on='key',right_on='NamePeriod')
    all_data_st.to_excel('merged_file_fuzzy.xlsx')

这个想法是基于每个数据框的两列名称和年份进行模糊合并。我尝试将这两个组合在一个字段(NamePeriod)中,然后在其上合并,但出现以下错误:

TypeError: expected string or bytes-like object

知道如何执行这种模糊合并吗?以下是这些列在数据框中的外观:

print(filings[['Name', 'Period','NamePeriod']])
print(prospectus[['prospectus_issuer_name', 'fyear','NamePeriod']])



print(filings[['Name', 'Period','NamePeriod']])
print(prospectus[['prospectus_issuer_name', 'fyear','NamePeriod']])
                                               Name  ...                  NamePeriod
0                                               NaN  ...                         NaN
1                             NAM TAI PROPERTY INC.  ...  NAM TAI PROPERTY INC. 2019
2                             NAM TAI PROPERTY INC.  ...  NAM TAI PROPERTY INC. 2018
3                             NAM TAI PROPERTY INC.  ...  NAM TAI PROPERTY INC. 2017
4                             NAM TAI PROPERTY INC.  ...  NAM TAI PROPERTY INC. 2016
                                            ...  ...                         ...
15922                   Huitao Technology Co., Ltd.  ...                         NaN
15923                       Leaping Group Co., Ltd.  ...                         NaN
15924                                    PUYI, INC.  ...                         NaN
15925  Puhui Wealth Investment Management Co., Ltd.  ...                         NaN
15926                           Tidal Royalty Corp.  ...                         NaN

[15927 rows x 3 columns]
           prospectus_issuer_name  fyear                        NamePeriod
0                  ALCAN ALUM LTD   1990               ALCAN ALUM LTD 1990
1                  ALCAN ALUM LTD   1991               ALCAN ALUM LTD 1991
2                  ALCAN ALUM LTD   1992               ALCAN ALUM LTD 1992
3               AMOCO CDA PETE CO   1992            AMOCO CDA PETE CO 1992
4               AMOCO CDA PETE CO   1992            AMOCO CDA PETE CO 1992
                          ...    ...                               ...
1798               KOREA GAS CORP   2016               KOREA GAS CORP 2016
1799               KOREA GAS CORP   2016               KOREA GAS CORP 2016
1800          PETROLEOS MEXICANOS   2016          PETROLEOS MEXICANOS 2016
1801          PETROLEOS MEXICANOS   2016          PETROLEOS MEXICANOS 2016
1802  BOC AVIATION PTE LTD GLOBAL   2016  BOC AVIATION PTE LTD GLOBAL 2016

[1803 rows x 3 columns]

这是我尝试运行的完整代码:

import pandas as pd
from rapidfuzz import process, utils
prospectus_data_file = 'file1.xlsx'
filings_data_file = 'file2.xlsx'


prospectus = pd.read_excel(prospectus_data_file)
filings = pd.read_excel(filings_data_file)



filings.rename(columns={'Name': 'name', 'Period': 'year'}, inplace=True)
prospectus.rename(columns={'prospectus_issuer_name': 'name', 'fyear': 'year'}, inplace=True)
df3 = pd.concat([filings, prospectus], ignore_index=True)





from rapidfuzz import fuzz, utils

df3.dropna(subset = ["name"], inplace=True)
names = [utils.default_process(x) for x in df3['name']]
for i1, row1 in df3.iterrows():
    for i2 in df3.loc[(df3['year'] == row1['year']) & (df3.index > i1)].index:
        if fuzz.WRatio(names[i1], names[i2], processor=None, score_cutoff=90):
            df3.drop(i2, inplace=True)

df3.reset_index(inplace=True)

给我一​​个错误IndexError: list index out of range

【问题讨论】:

    标签: python fuzzy-search


    【解决方案1】:

    总结问题:

    • 有两个 DataFrame,它们都有名称和年份的键

    • 您想合并两个 DataFrame 并删除所有重复元素,其中重复元素是具有相同年份和非常相似名称的元素

    我正在使用以下两个示例 DataFrame:

    import pandas as pd
    
    df1 = pd.DataFrame({
        'Name': ['NAM PROPERTY INC.', 'NAM PROPERTY INC.', 'ALCAN ALUM LTD'],
        'Period': [2019, 2019, 2018]})
    
    df2 = pd.DataFrame({
        'prospectus_issuer_name': ['NAM TAI PROPERTY INC.', 'ALCAN ALUM LTD', 'AMOCO CDA PETE CO'],
        'fyear': [2019, 2019, 1992]})
    

    我解决这个问题的方法是从连接两个数据框开始

    df1.rename(columns={'Name': 'name', 'Period': 'year'}, inplace=True)
    df2.rename(columns={'prospectus_issuer_name': 'name', 'fyear': 'year'}, inplace=True)
    df3 = pd.concat([df1, df2], ignore_index=True)
    

    之后可以遍历这个新的 DataFrame 并删除所有重复的行。我在这里使用RapidFuzz,因为它比 FuzzyWuzzy 快(我是作者)。以下代码提前创建了一个预处理名称列表,因为这些条目可能会被多次使用,并且预处理会占用运行时的大量时间。之后,它遍历行并始终将其与所有具有较高索引的行进行比较(具有较低索引的行已经比较,因为 ratio(a,b) == ratio(b,a))并且具有正确的年份。过滤正确的年份可以减少运行慢速字符串匹配算法的频率。对于具有相似年份和非常相似名称的所有行,保留第一行,删除其他行。您可能必须使用 score_cutoff 和匹配算法来查看哪个最适合您的需求。

    from rapidfuzz import fuzz, utils
    
    names = [utils.default_process(x) for x in df3['name']]
    for i1, row1 in df3.iterrows():
        for i2 in df3.loc[(df3['year'] == row1['year']) & (df3.index > i1)].index:
            if fuzz.WRatio(names[i1], names[i2], processor=None, score_cutoff=90):
                df3.drop(i2, inplace=True)
    
    df3.reset_index(inplace=True)
    

    【讨论】:

    • 我收到一个错误AttributeError: module 'rapidfuzz.utils' has no attribute 'full_process' 我该如何摆脱它?
    • 我也收到错误TypeError: argument 1 must be str, not float
    • 哦,对不起,这是 default_process 我修复了代码;)同样的函数在fuzzywuzzy中称为full_process
    • 第二个错误意味着那里有一些浮点值。我更改了示例以执行字符串转换。所以它现在应该可以工作了
    • 嗨 Max,我编辑了最初的帖子并粘贴了我的代码。它给了我一个错误TypeError: argument 1 must be str, not float 任何想法如何解决它还是我做错了什么?
    猜你喜欢
    • 1970-01-01
    • 2017-08-29
    • 1970-01-01
    • 2019-10-31
    • 1970-01-01
    • 2018-10-17
    • 2020-07-08
    • 2018-05-04
    • 1970-01-01
    相关资源
    最近更新 更多