[英]Fuzzy matching in python/pandas
python 的新手,需要一些帮助。 我有两个数据集(df1 和 df2),我需要对“名称”列进行模糊匹配以从另一个文件中提取数据。 在进行模糊匹配之前,我想清理“name”列以获得更好的模糊匹配结果,因此我创建了一个新的名称列“name2”,并将该列中的一些特定单词条带化。 我正在为两个数据集“名称”列执行此操作。 然后我有一些代码在“name2”列上进行模糊匹配,但是我很难拉入原始的“name”列,而不是“name2”列。 我怎样才能做到这一点? 此外,如何根据匹配从 df2 中提取另一个字段?
from fuzzywuzzy import process, fuzz
import pandas as pd
import numpy as np
df1 = pd.DataFrame({
'Name': ['Testing and information 1', 'Categories and information 2', 'Money and information 3', 'Time and information 4'],
'Category': ['Category 1', 'Category 2', 'Category 3', 'Category 4']
})
df2 = pd.DataFrame({
'Name': ['Testing and information example', 'Categories and information example', 'Money and information example'],
'Type': ['Type 1', 'Type 2', 'Type 3']
})
#Create Name2 and remove certain words
df1['Name2'] = df1['Name'].str.replace('example|and|information', "")
df2['Name2'] = df2['Name'].str.replace('example|and|information', "")
# empty lists for storing the matches later
match1 = []
match2 = []
k = []
# converting dataframe column to list of elements for fuzzy matching
myList1 = df1['Name2'].tolist()
myList2 = df2['Name2'].tolist()
threshold = 80
# iterating myList1 to extract closest match from myList2
for i in myList1:
match1.append(process.extractOne(i, myList2, scorer=fuzz.ratio))
df1['Name from df2 Identified'] = match1
for j in df1['Name2']:
if j[1] >= threshold:
k.append(j[0])
match2.append(",".join(k))
k = []
# saving matches to df1
df1['Name from df2 Identified'] = match2
print("\nName from df2 Identified...")
print(df1)
希望我明白你想要完成什么,否则随时问。 这是我基于您的代码中的df1
和df2
的尝试:
fuzzy_matrix = pd.DataFrame(index=df1.Name2, columns=df2.Name2)
fuzzy_matrix = fuzzy_matrix.apply(lambda row: [fuzz.ratio(row.name, name2) for name2 in row.index], axis=1, result_type='broadcast')
fuzzy_matrix = fuzzy_matrix.astype('int')
THRESHOLD = 80
translations = fuzzy_matrix.where(lambda x: x > THRESHOLD, np.nan).idxmax(axis=1)
max_values = fuzzy_matrix.max(axis=1)
df1['identified_name'] = df1.Name2.apply(lambda name1: translations.loc[name1])
df1['identified_score'] = df1.Name2.apply(lambda name1: max_values.loc[name1])
df1['Type'] = df1['identified_name'].apply(lambda name2: df2.set_index('Name2').loc[name2, 'Type'] if not pd.isna(name2) else np.nan)
解释:fuzzywuzzy 的process.extractOne
没有任何问题,但我发现生成一个模糊匹配矩阵很有趣,该矩阵将df1
中的每个Name2
与df2
中的每个其他Name2
进行比较。 生成的fuzzy_matrix
表如下所示:
名字2 | 测试 | 类别 | 钱 |
---|---|---|---|
测试 1 | 95 | 42 | 42 |
类别 2 | 42 | 96 | 45 |
钱 3 | 42 | 45 | 94 |
时间 4 | 56 | 48 | 50 |
从这里,我们将低于给定THRESHOLD
值的任何值设置为NaN
,然后找出上表中哪些索引/列对具有最高值。 生成的translations
如下所示:
名字2 | 0 |
---|---|
测试 1 | 测试 |
类别 2 | 类别 |
钱 3 | 钱 |
时间 4 | 楠 |
来自df1
的Time 4
Name2
与df2
的Name2
在阈值以上没有足够准确的匹配,因此它被设置为NaN
。
代码的 rest 只是在df1
中添加了 2 列,以存储匹配的Name2
。 为了提供一个示例,说明如何根据最匹配的Name2
将值从df2
获取到df1
,我添加了Type
列。 生成的df1
如下所示:
名称 | 类别 | 名字2 | 从 df2 识别的名称 | identified_name | 识别分数 | 类型 | |
---|---|---|---|---|---|---|---|
0 | 测试和信息 1 | 类别 1 | 测试 1 | (“测试”,78) | 测试 | 95 | 类型 1 |
1个 | 类别和信息 2 | 第 2 类 | 类别 2 | ('类别', 83) | 类别 | 96 | 类型 2 |
2个 | 钱和信息 3 | 第 3 类 | 钱 3 | (“金钱”,71) | 钱 | 94 | 类型 3 |
3个 | 时间和信息 4 | 第 4 类 | 时间 4 | ('类别', 33) | 楠 | 56 | 楠 |
如果您想摆脱df2
中不匹配的任何行,只需使用df1.dropna(subset=['identified_name'])
(这将删除第 3 行)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.