如何解决来自两个不同的csv文件的Python模糊查找模糊匹配
在两个不同的CSV文件(包含公司信息)之间进行FuzzyLookup帮助。
CSV#1 data1.csv也具有两列(五千行)
名称,ID
CSV#2 data2.csv具有两列(105万行)
LegalName,AcctNumber
目标是对LegalNames进行名称的模糊查找
(最好根据准确度的百分比显示两个匹配的LegalNames)
我看到有以下库: https://github.com/seatgeek/fuzzywuzzy
此外,以下GitHub展示了我想要做的事情的类似想法
https://github.com/Cheukting/fuzzy-match-company-name
使用Pandas和fuzzywuzzy
她非常有帮助,因为她还尝试过滤公司名称中最常用的名称(例如“ a”,“ the”,“ LLC”,“ Ltd”,“ and”等)
根据我的理解,唯一的是,她会比较同一列表中是否有重复项,而不是两个不同的重复项。因此,最好在data1.csv和data2.csv中具有相同的概念
此外,请随时为使用其他库的方法做出贡献!欢迎任何帮助:)
下面是她的代码:
我们使用的数据位于http://download.companieshouse.gov.uk/en_output.html上,它是一个公开许可的公共可用数据集,其中包含英国的注册(有限责任)公司列表。 (此处显示的版本是2018年5月的快照)
import pandas as pd
pd.set_option('display.max_columns',1000)
df = pd.read_csv("BasicCompanyDataAsOneFile-2020-10-01.csv")
df.head()
这是一个巨大的表,其中包含许多行,可能需要一段时间才能加载
df.columns
df['RegAddress.PostTown'].value_counts().head(30)
词频
由于我们有很多公司,因此我们仅以剑桥的公司为例。
首先,我们在所有公司名称中找到30个最常用的词。由于我们期望即使在不同的公司中它们也会重复很多,因此我们无法使用它们来匹配公司名称。我们的做法是,如果名称中存在任何关键字,我们将扣除一对匹配分数。
from collections import Counter
all_names = df['CompanyName'][df['RegAddress.PostTown']=='CAMBRIDGE'].unique()
names_freq = Counter()
for name in all_names:
names_freq.update(str(name).split(" "))
key_words = [word for (word,_) in names_freq.most_common(30)]
print(key_words)
显示长度
len(all_names)
按分组匹配
然后,我们将名称按其第一个字符分组。由于列表太长,一次要全部匹配它们(需要考虑15889 x 15889对)。解决方法是按组匹配它们,假设如果第一个字符的名称不匹配,则它们不太可能是相同的名称。
all_main_name = pd.DataFrame(columns=['sort_gp','names','alias','score'])
all_names.sort()
all_main_name['names'] = all_names
all_main_name['sort_gp'] = all_main_name['names'].apply(lambda x: x[0])
模糊匹配
在这里,对于每个组,我们使用fuzzywuzzy.token_sort_ratio来匹配名称。基本形式的fuzzywuzzy.ratio不同,它使用Levenshtein距离来计算差异,它允许名称中的标记(单词)交换顺序,并且仍然给出“完美”匹配。 (参考:https://github.com/seatgeek/fuzzywuzzy)
from fuzzywuzzy import fuzz
all_sort_gp = all_main_name['sort_gp'].unique()
def no_key_word(name):
"""check if the name contain the keywords in travel company"""
output = True
for key in key_words:
if key in name:
output = False
return output
for sortgp in all_sort_gp:
this_gp = all_main_name.groupby(['sort_gp']).get_group(sortgp)
gp_start = this_gp.index.min()
gp_end = this_gp.index.max()
for i in range(gp_start,gp_end+1):
# if self has not got alias,asign to be alias of itself
if pd.isna(all_main_name['alias'].iloc[i]):
all_main_name['alias'].iloc[i] = all_main_name['names'].iloc[i]
all_main_name['score'].iloc[i] = 100
# if the following has not got alias and fuzzy match,asign to be alias of this one
for j in range(i+1,gp_end+1):
if pd.isna(all_main_name['alias'].iloc[j]):
fuzz_socre = fuzz.token_sort_ratio(all_main_name['names'].iloc[i],all_main_name['names'].iloc[j])
if not no_key_word(all_main_name['names'].iloc[j]):
fuzz_socre -= 10
if (fuzz_socre > 85):
all_main_name['alias'].iloc[j] = all_main_name['alias'].iloc[i]
all_main_name['score'].iloc[j] = fuzz_socre
if i % (len(all_names)//10) == 0:
print("progress: %.2f" % (100*i/len(all_names)) + "%")
all_main_name.to_csv('company_in_cambridge.csv')
预览
all_main_name[(all_main_name['names']!=all_main_name['alias']) & (all_main_name['alias'].notna())]
谢谢!
预期答案:
all_main_name[(all_main_name['names']!=all_main_name['alias']) & (all_main_name['alias'].notna())]
sort_gp,名称,别名,分数
955,A,AMADEUS EII LP,AMADEUS EI LP,96
956,A,AMADEUS EIII LP,AMADEUS EI LP,93
957,A,AMADEUS GI LP,AMADEUS EI LP,92
958,A,AMADEUS HI LP,AMADEUS EI LP,92
960,A,AMADEUS II'A',AMADEUS I,86
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。