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

如何在Pandas中识别并合并格式差异的相似企业名称?

企业名称标准化解决方案(针对大规模数据集)

一、前置关键:名称预处理

先清洗掉干扰信息,统一格式,减少后续相似性计算的噪声:

  • 统一转为大写(或小写),消除大小写差异影响
  • 移除标点符号(如.、,),解决示例中70/71条的标点差异问题
  • 替换常见缩写(如LTD→LIMITED、CO→COMPANY),统一表述
  • 移除通用企业后缀(如INC、CORP、LLC、AG、KK),聚焦核心名称
  • 调整语序(如将BOSCH GMBH ROBERT改为ROBERT BOSCH GMBH,适配企业名称常见语序)

Pandas实现代码:

import pandas as pd
import re

# 加载数据集为DataFrame
df = pd.DataFrame.from_dict(your_data_dict, orient='index', columns=['company_name'])

# 预处理函数
def clean_company_name(name):
    # 转大写
    name = name.upper()
    # 移除标点
    name = re.sub(r'[.,]', '', name)
    # 替换缩写
    abbreviation_map = {
        'LTD': 'LIMITED',
        'CO': 'COMPANY',
        'CORP': 'CORPORATION',
        'GMBH': 'GMBH'  # 可选择替换为全称或保留缩写,按需调整
    }
    for abbr, full in abbreviation_map.items():
        name = re.sub(rf'\b{abbr}\b', full, name)
    # 移除通用后缀
    suffixes = ['INC', 'LIMITED', 'COMPANY', 'CORPORATION', 'LLC', 'AG', 'KK', 'GMBH']
    for suffix in suffixes:
        name = re.sub(rf'\b{suffix}\b', '', name).strip()
    # 调整语序(针对姓氏/后缀在后的情况,可按需扩展规则)
    parts = name.split()
    if len(parts) >= 2 and parts[-1].isupper() and len(parts[-1]) <= 10:
        name = ' '.join([parts[-1]] + parts[:-1])
    return name

df['cleaned_name'] = df['company_name'].apply(clean_company_name)

二、相似性检测与Louvain聚类(对应你的步骤1)

Pandas本身无内置Louvain算法,可结合scikit-learn、python-louvain实现:

1. 文本向量化

用字符级TF-IDF转换短文本(企业名称)为向量,更适合捕捉字符层面的相似性:

from sklearn.feature_extraction.text import TfidfVectorizer

# 字符n-gram取2-4,适配短文本特征
vectorizer = TfidfVectorizer(analyzer='char', ngram_range=(2,4))
tfidf_matrix = vectorizer.fit_transform(df['cleaned_name'])

2. 近似最近邻查找(解决17万条数据的O(n²)计算瓶颈)

直接两两计算相似度效率极低,用近似最近邻筛选高相似度对:

from sklearn.neighbors import NearestNeighbors

# 余弦相似度,每个样本取Top10相似项
nn = NearestNeighbors(n_neighbors=10, metric='cosine', algorithm='brute')
nn.fit(tfidf_matrix)
distances, indices = nn.kneighbors(tfidf_matrix)

# 构建相似边列表,相似度=1-余弦距离,阈值设为0.8(可按需调整)
edges = []
threshold = 0.8
for i in range(len(df)):
    for j in range(1, len(indices[i])):  # 跳过自身
        sim = 1 - distances[i][j]
        if sim >= threshold:
            edges.append((i, indices[i][j], sim))

3. Louvain社区检测

用社区聚类将相似名称归为同一组:

import community as community_louvain
import networkx as nx

# 构建无向图
G = nx.Graph()
for u, v, sim in edges:
    G.add_edge(u, v, weight=sim)

# 运行Louvain算法,得到每个样本的社区ID
partition = community_louvain.best_partition(G, weight='weight')

# 社区ID映射到DataFrame,无连接的样本设为-1
df['community_id'] = df.index.map(lambda x: partition.get(x, -1))

三、提取统一企业名称

针对每个社区,选择最具代表性的名称,常用方法:

  • 频率优先:选社区中出现次数最多的原始名称
  • 核心词提取:选清洗后名称的最长公共前缀(如从YAMAWA MFG CO LTD提取YAMAWA)
  • 长度优先:选最短/最长的名称作为统一标识

代码示例:

# 方法1:选频率最高的原始名称
def get_unified_name(group):
    name_counts = group['company_name'].value_counts()
    return name_counts.idxmax()

# 方法2:提取最长公共前缀作为核心名称
def get_core_name(group):
    cleaned_names = group['cleaned_name'].tolist()
    if not cleaned_names:
        return ''
    prefix = cleaned_names[0]
    for name in cleaned_names[1:]:
        while not name.startswith(prefix):
            prefix = prefix[:-1]
            if not prefix:
                break
    return prefix.strip()

# 应用到每个社区
df['unified_name'] = df.groupby('community_id')['company_name'].transform(get_unified_name)
# 若用核心名称:
# df['unified_name'] = df.groupby('community_id').apply(get_core_name).reset_index(level=0, drop=True)

四、大规模数据集优化建议

  • 用faiss替代sklearn的近似最近邻,提升百万级数据的检索效率
  • 先归并完全相同的清洗后名称,减少后续聚类计算量
  • 单独处理人名类条目(如示例中的NAGAI TAKAYUKI),适配人名标准化规则
  • 对相似度阈值区间(如0.7-0.8)的社区做人工抽查,调整阈值精度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 04:15:38