繁体   English   中英

python/pandas 中的模糊匹配

[英]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)

在此处输入图像描述

希望我明白你想要完成什么,否则随时问。 这是我基于您的代码中的df1df2的尝试:

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中的每个Name2df2中的每个其他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

来自df1Time 4 Name2df2Name2在阈值以上没有足够准确的匹配,因此它被设置为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM