一、需求描述及实现思路
(一)需求描述
将两个数据表格中有唯一相同的一列值,但该列值内容存有一定差异,有些事全程,有些事简写或者部分名称,现需将两个表格合并在一起。(多表格的模糊匹配)
(二)总体思路
首先,代码使用 pd.read_excel()
函数读取了两个 Excel 表格文件,分别存储在 df_full
和 df_partial
数据框中。其中,df_full
存储了全称的信息,df_partial
存储了简写或部分字符的信息。
然后,代码创建了一个空的结果数据框 df_result
,用于存储匹配结果。接下来,通过遍历 df_partial
数据框中的每一行,获取每个简写或部分字符。
对于每个简写或部分字符,代码使用 process.extract()
函数从 df_full['Full Name']
列中查找与之匹配的全称。process.extract()
函数返回的是一个列表,其中每个元素包含匹配的全称和相似度得分。代码选择第一个匹配项作为最佳匹配,并获取其全称和得分。
如果有多个匹配项且得分相同(即有相同的相似度得分),则会将当前行添加到 df_result
数据框中,并使用 .style.apply()
方法将添加的行背景颜色设置为黄色。
如果只有一个最佳匹配项,则直接将当前行添加到 df_result
数据框中。
接下来,代码使用 pd.merge()
函数将 df_result
和 df_partial
数据框按照 'Partial Name' 列进行合并,生成一个新的数据框 df_merged
。合并后的结果包含了匹配的全称和原始表格中的其他信息。
然后,代码创建一个 Workbook 对象,并为工作表设置名称为 'Merged Data'。接着,使用 dataframe_to_rows()
函数将 df_merged
数据框转换为行的迭代器,然后使用两层循环将数据写入工作表中的单元格。
最后,代码遍历工作表中的每一行,如果发现背景颜色为黄色的单元格,就将整行的单元格背景颜色设置为黄色。最终,将合并结果保存到名为 'merged_table.xlsx' 的 Excel 文件中。
二、实现代码
(一)总体代码
import pandas as pd
from fuzzywuzzy import process
from openpyxl import Workbook
from openpyxl.styles import PatternFill
from openpyxl.utils.dataframe import dataframe_to_rows
# 读取两个表格
df_full = pd.read_excel('全称呼.xlsx') # 全称表格
df_partial = pd.read_excel('半称呼.xlsx') # 简写或部分字符表格
# 创建一个空的结果表格用于存储匹配结果
df_result = pd.DataFrame(columns=['Partial Name', 'Full Name'])
# 遍历每个简写或部分字符
for _, row_partial in df_partial.iterrows():
partial_name = row_partial['Partial Name']
# 使用fuzzywuzzy库的process.extract函数查找所有匹配项
matches = process.extract(partial_name, df_full['Full Name'], limit=2)
# 获取匹配得分最高的全称
best_match = matches[0][0]
best_score = matches[0][1]
# 如果有多个匹配项且得分相同,则标记当前行
if len(matches) > 1 and matches[0][1] == matches[1][1]:
df_result = df_result.append({'Partial Name': partial_name, 'Full Name': best_match}, ignore_index=True).style.apply(lambda _: ['background-color: yellow'], subset=pd.IndexSlice[-1:, :])
else:
df_result = df_result.append({'Partial Name': partial_name, 'Full Name': best_match}, ignore_index=True)
# 合并两个表格
df_merged = pd.merge(df_full, df_partial, on='Partial Name', how='outer')
# 创建一个Workbook来保存结果
workbook = Workbook()
worksheet = workbook.active
worksheet.title = 'Merged Data'
# 将DataFrame写入工作表中
rows = dataframe_to_rows(df_merged, index=False, header=True)
for r_idx, row in enumerate(rows, 1):
for c_idx, value in enumerate(row, 1):
worksheet.cell(row=r_idx, column=c_idx, value=value)
# 标记有多个匹配项的行为黄色
yellow_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")
for row in worksheet.iter_rows(min_row=2, max_row=worksheet.max_row):
if row[0].fill.start_color.index == yellow_fill.start_color.index:
for cell in row:
cell.fill = yellow_fill
# 保存合并结果
workbook.save('merged_table.xlsx')
(二)代码讲解
(1)process.extract
函数
process.extract
函数是 fuzzywuzzy 库中的一个功能强大的模糊匹配函数。它的作用是在给定一个待匹配字符串时,在一个字符串列表中查找与之最相似的字符串。
该函数的语法如下:
process.extract(query, choices, scorer=fuzz.ratio, limit=5)
参数解释:
query
:待匹配的字符串。choices
:用于匹配的字符串列表。scorer
:用于计算相似度得分的评分函数,默认使用fuzz.ratio
函数,也可以自定义评分函数。limit
:限制返回的匹配项数量,默认为 5。
函数返回一个结果列表,其中每个元素都是一个包含两个值的元组:匹配的字符串和相似度得分。limit 参数: limit
参数用于限制返回的匹配项数量。默认情况下,它的取值是 5,即返回相似度得分最高的 5 个匹配项。如果你希望返回更少或更多的匹配项,可以根据需要调整这个参数的值。
例如,如果你想返回相似度得分最高的 3 个匹配项,可以将代码改为:
matches = process.extract(query, choices, limit=3)
-
scorer 参数:
scorer
参数用于指定相似度得分的评分函数。默认情况下,它使用fuzz.ratio
函数来计算相似度得分。fuzz.ratio
函数根据字符串的相似程度计算一个得分,得分越高表示两个字符串越相似。除了
fuzz.ratio
函数外,还有其他评分函数可供选择,例如:fuzz.partial_ratio
:部分字符串匹配得分。fuzz.token_sort_ratio
:对字符串进行标记排序后的匹配得分。fuzz.token_set_ratio
:对字符串进行标记集的匹配得分。
通过调整 limit
和 scorer
参数,可以根据具体需求定制模糊匹配的行。process. extract
函数会根据评分函数计算待匹配字符串与列表中每个字符串的相似度得分,并返回相似度得分最高的匹配项列表。如果指定了 limit
参数,则返回相应数量的最佳匹配项。这个函数对于处理模糊匹配问题非常有用,例如在搜索、字符串匹配、数据清洗等任务中经常被使用。
(2)enumerate()
函数
enumerate()
函数是 Python 内置函数之一,用于将一个可迭代对象(如列表、元组、字符串、字典、集合等)组合为一个索引序列,同时列出数据和数据的下标。它的语法如下:
enumerate(iterable, start=0)
iterable
:表示要进行枚举的可迭代对象。start
:可选参数,表示索引起始值,默认为 0。
enumerate()
函数会返回一个迭代器对象,可以使用 list()
、dict()
等函数将其转换成列表、字典等其他形式。