You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨4个Dataframe标准化存在细微差异的足球俱乐部名称

优化多DataFrame足球俱乐部名称匹配方案

我需要一个优雅且计算成本低的解决方案:手上有4个爬虫获取的DataFrame,都包含足球俱乐部名称,其中1-2个DataFrame里的名称存在细微差异,示例如下:

df1 = pd.DataFrame({'Home Team': ['France', 'Italy', 'Spain', 'Palmeiras SE']})

df2 = pd.DataFrame({'Home Team': ['France Woman', 'Italy', 'Spain', 'Palmeiras']})

df3 = pd.DataFrame({'Home Team': ['France', 'Italy', 'Spain Woman', 'Palmeiras SE']})

df4 = pd.DataFrame({'Home Team': ['France', 'Italy', 'Spain Woman', 'Palmeiras']})

实际场景中每个DataFrame有50-100条数据,且每日更新。试过fuzzywuzzy、difflib库,也考虑过引入主数据作为参考,但这些方案计算量都偏高。

已尝试的可行方案

用fuzzymatcher处理两个DataFrame

import fuzzymatcher

result = fuzzymatcher.fuzzy_left_join(whoscored, olbg_data, 'Home Team', 'Home Team')

output = result[['Home Team_left', 'Predicted Result_left', 'Predicted Result_right']]

output.columns = ['Home Team', 'Predicted Result (Whoscored)', 'Predicted Result (OLBG Data)']

这个方案能识别像Talleres与CA Talleres de Cordoba、Germany与Germany Women这类匹配。

处理四个DataFrame时的问题

当扩展到4个DataFrame时,代码如下:

import fuzzymatcher

result = fuzzymatcher.fuzzy_left_join(whoscored, olbg_data, 'Home Team', 'Home Team')
output = result[['Home Team_left', 'Predicted Result_left', 'Predicted Result_right']]
output.columns = ['Home Team', 'Predicted Result (Whoscored)', 'Predicted Result (OLBG Data)']

result_predictz = fuzzymatcher.fuzzy_left_join(whoscored, predictz_output, 'Home Team', 'Home Team')
output = output.copy()
output.loc[:, 'Predicted Result (Predictz)'] = result_predictz['Predicted Result_right']

result_vitibet = fuzzymatcher.fuzzy_left_join(whoscored, vitibet, 'Home Team', 'Home Team')
output = output.copy()
output.loc[:, 'Predicted Result (Vitibet)'] = result_vitibet['Predicted Result_right']

结果勉强可用,但部分存在细微差异的名称匹配后返回NaN,比如Vitibet的Predicted Result列第7行,明明对应名称差异很小却无法匹配。

更优解决方案

1. 先统一名称清洗规则,降低模糊匹配压力

先对所有DataFrame的俱乐部名称做标准化清洗,减少后续匹配的复杂度:

  • 移除后缀/前缀:比如SE、Woman/Women、CA这类常见固定标识
  • 统一大小写:全部转为小写或大写
  • 去除特殊字符/多余空格

示例代码:

import re

def clean_team_name(name):
    # 转小写
    name = name.lower()
    # 移除常见后缀/前缀
    remove_patterns = [' se', ' woman', ' women', ' ca ']
    for pattern in remove_patterns:
        name = name.replace(pattern, '')
    # 去除多余空格和特殊字符
    name = re.sub(r'\s+', ' ', name).strip()
    name = re.sub(r'[^a-z0-9 ]', '', name)
    return name

# 对所有DataFrame应用清洗函数
for df in [df1, df2, df3, df4]:
    df['Cleaned Team'] = df['Home Team'].apply(clean_team_name)

清洗后,大部分细微差异会被抹平,后续匹配可以直接用精确匹配,计算成本大幅降低。

2. 建立轻量级映射字典,处理特殊情况

对于清洗后仍无法匹配的少数特殊名称,手动维护一个小型映射字典(每日更新数据量小,维护成本低):

team_mapping = {
    'talleres': 'ca talleres de cordoba',
    'germany': 'germany women'
    # 可根据每日新增的不匹配项补充
}

# 应用映射
def map_team_name(cleaned_name):
    return team_mapping.get(cleaned_name, cleaned_name)

for df in [df1, df2, df3, df4]:
    df['Mapped Team'] = df['Cleaned Team'].apply(map_team_name)

这种方式比全量模糊匹配效率高很多,仅处理少数特殊案例。

3. 基于清洗后的名称做合并,替代多次模糊连接

当所有DataFrame都有了统一的Mapped Team列后,用精确连接合并所有数据,避免多次模糊匹配的高计算量:

# 给每个DataFrame添加来源标识,方便后续列命名
df1['Source'] = 'Whoscored'
df2['Source'] = 'OLBG'
df3['Source'] = 'Predictz'
df4['Source'] = 'Vitibet'

# 合并所有DataFrame到一个大表
all_data = pd.concat([df1, df2, df3, df4], ignore_index=True)

# 按统一名称 pivot,得到最终结果
final_output = all_data.pivot(
    index='Mapped Team',
    columns='Source',
    values='Predicted Result'
).reset_index()

# 重命名列,还原可读性
final_output.columns = ['Home Team', 'Predicted Result (Whoscored)', 'Predicted Result (OLBG)', 'Predicted Result (Predictz)', 'Predicted Result (Vitibet)']

这种方式计算量极低,且结果更稳定,不会出现模糊匹配的NaN问题。

4. 可选:用快速模糊匹配工具处理剩余不匹配项

如果清洗和映射后仍有极个别不匹配,可选择用rapidfuzz(fuzzywuzzy的更快替代版)处理这部分数据,而非全量模糊匹配:

from rapidfuzz import process, fuzz

# 获取所有唯一的清洗后名称
all_teams = pd.concat([df['Cleaned Team'] for df in [df1, df2, df3, df4]]).unique()

# 为每个找不到匹配的名称找最相似的
def find_best_match(name, team_list):
    match, score, _ = process.extractOne(name, team_list, scorer=fuzz.token_set_ratio)
    return match if score > 80 else name  # 设置匹配阈值,比如80分以上才算匹配

# 仅对有缺失的行应用匹配
final_output['Home Team'] = final_output['Home Team'].apply(lambda x: find_best_match(x, all_teams) if pd.isna(x) else x)

rapidfuzz比传统fuzzywuzzy快很多,且只处理少量数据,计算成本可控。

内容的提问来源于stack exchange,提问作者EscadeSupremo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:25:07