Pandas中处理含分隔符列的模糊匹配与数据合并

心靈之曲
发布: 2025-10-15 12:52:06
原创
1015人浏览过

Pandas中处理含分隔符列的模糊匹配与数据合并

本文探讨了在pandas中处理包含分隔符的键列进行数据合并的挑战与解决方案。当一个dataframe的关键列包含以分号等分隔符连接的多个值时,传统的`merge`操作无法直接进行模糊匹配。文章提供了一种基于迭代和字符串包含检查的策略,详细解释了如何将源dataframe的单个值与目标dataframe中包含多个值的列进行匹配,并回填相关信息,同时讨论了性能优化和注意事项。

在数据分析和处理中,我们经常需要将两个或多个数据集(通常是Pandas DataFrame)基于某个共同的键进行合并。然而,实际数据往往并非总是规整的。一种常见的复杂情况是,在用于合并的关键列中,某些单元格可能包含由特定分隔符(如分号、逗号)连接的多个值,而另一个DataFrame的对应列则包含单个值。在这种“一对多”或“多对一”的模糊匹配场景下,标准的df.merge()函数通常无法满足需求,因为它要求精确的键匹配。

理解问题:含分隔符的键列

假设我们有两个DataFrame:df1 包含一系列独立的“产品ID”(PDs),而 df2 包含“编号”(Number)及其对应的“产品ID”(PDs)。df2 中的“PDs”列可能包含单个产品ID,也可能包含由分号 ; 分隔的多个产品ID。我们的目标是,对于 df1 中的每一个产品ID,去 df2 中查找,如果 df1 的产品ID包含在 df2 的某个“PDs”单元格中(无论是单独存在还是作为分隔符字符串的一部分),则将 df2 对应的“Number”映射回 df1。

示例数据结构:

df1 (源数据,单个PDs):

PDs
2345
2675
8706
3452
9999

df2 (目标数据,含分隔符的PDs):

Number PDs
101 2345
102 2675
103 8706
104 9045;4729;5392
105 3452
106 1111;2222

如果直接使用 df1.merge(df2[['Number', 'PDs']], on='PDs'),它将无法匹配 df1 中的 9045 到 df2 中 9045;4729;5392 这样的单元格,因为它们不是完全相等的。

解决方案:基于迭代的模糊匹配

为了解决这个问题,我们需要采用一种更灵活的匹配策略,即遍历 df1 中的每个产品ID,然后检查它是否存在于 df2 的“PDs”列的每个字符串中。

核心思路:

序列猴子开放平台
序列猴子开放平台

具有长序列、多模态、单模型、大数据等特点的超大规模语言模型

序列猴子开放平台 0
查看详情 序列猴子开放平台
  1. 将 df2 的相关列转换为一个便于查找的字典,其中键是 Number,值是 PDs 字符串。
  2. 将 df1 的“PDs”列转换为一个列表,以便逐一遍历。
  3. 通过嵌套循环,对 df1 中的每个产品ID,与 df2 字典中的每个“PDs”字符串进行包含性检查。
  4. 如果找到匹配,则记录 df2 对应的 Number。
  5. 将收集到的 Number 列表作为新列添加到 df1 中。

代码实现

下面是具体的Python代码实现,使用Pandas库来处理数据:

import pandas as pd
import numpy as np

# 模拟数据
data1 = {'PDs': [2345, 2675, 8706, 3452, 9999]}
df1 = pd.DataFrame(data1)

data2 = {'Number': [101, 102, 103, 104, 105, 106],
         'PDs': ['2345', '2675', '8706', '9045;4729;5392', '3452', '1111;2222']}
df2 = pd.DataFrame(data2)

print("原始 df1:")
print(df1)
print("\n原始 df2:")
print(df2)

# 1. 将 df2 的 'Number' 和 'PDs' 列转换为字典,方便查找
# 键是 Number,值是 PDs 字符串
df2_pd_map = dict(zip(df2['Number'], df2['PDs']))

# 2. 将 df1 的 'PDs' 列转换为列表,以便逐一遍历
df1_pds_list = df1['PDs'].tolist()

# 3. 初始化一个列表来存储匹配到的 Number
mapped_numbers = []

# 4. 遍历 df1 中的每个 PD,并在 df2_pd_map 中查找匹配
for single_pd in df1_pds_list:
    found_match = False
    for number, delimited_pds_str in df2_pd_map.items():
        # 确保比较的是字符串,并检查是否包含
        if str(single_pd) in delimited_pds_str:
            mapped_numbers.append(number)
            found_match = True
            break  # 找到第一个匹配项后,跳出内层循环,处理下一个 single_pd
    if not found_match:
        mapped_numbers.append(np.nan) # 如果没有找到匹配,则填充 NaN

# 5. 将结果作为新列添加到 df1
df1['Mapped_Number'] = mapped_numbers

print("\n合并后的 df1:")
print(df1)
登录后复制

代码解析:

  • df2_pd_map = dict(zip(df2['Number'], df2['PDs'])):创建了一个字典,其中 df2 的 Number 列作为键,PDs 列(可能含分隔符的字符串)作为值。这使得我们能够快速地通过 Number 找到对应的 PDs 字符串。
  • df1_pds_list = df1['PDs'].tolist():将 df1 的 PDs 列转换为一个列表,方便进行迭代。
  • for single_pd in df1_pds_list::外层循环遍历 df1 中的每一个独立产品ID。
  • for number, delimited_pds_str in df2_pd_map.items()::内层循环遍历 df2_pd_map 字典中的每一个键值对,number 是 df2 的编号,delimited_pds_str 是 df2 中可能包含多个PD的字符串。
  • if str(single_pd) in delimited_pds_str::这是模糊匹配的核心。str(single_pd) 确保 single_pd 被转换为字符串,以避免类型不一致导致的错误。in 操作符检查 single_pd 字符串是否作为子串存在于 delimited_pds_str 中。
  • mapped_numbers.append(number) 和 break:一旦找到匹配,就将 df2 的 Number 添加到结果列表,并立即跳出内层循环,因为我们已经找到了 df1 中当前 single_pd 的一个匹配项。
  • if not found_match: mapped_numbers.append(np.nan):这是一个重要的健壮性改进。如果 df1 中的某个 single_pd 在 df2 中完全找不到匹配项,则向结果列表添加 np.nan(或你选择的其他默认值),以确保 mapped_numbers 列表的长度与 df1 的行数一致,避免赋值错误。
  • df1['Mapped_Number'] = mapped_numbers:将最终的匹配结果作为新列赋给 df1。

注意事项与优化

  1. 性能考虑:

    • 上述基于嵌套循环的方法在处理小到中等规模的数据集时表现良好。
    • 对于非常大的数据集(例如,df1 和 df2 都有数十万行),嵌套循环的 O(N*M) 时间复杂度可能会导致性能瓶颈
    • 优化方向:
      • 使用 apply 和 str.contains: 可以将内层循环替换为 df2['PDs'].apply(lambda x: str(single_pd) in x),但这仍然是外层循环。
      • 数据预处理: 如果 df2['PDs'] 包含分隔符,可以考虑先将其“展开”成多行(例如,使用 str.split(';').explode()),然后再进行标准的 merge 操作。这种方法可能会显著增加 df2 的行数,但后续的 merge 操作效率更高。
      • 向量化字符串匹配库: 对于更复杂的模糊匹配,可以考虑使用像 fuzzywuzzy 或 rapidfuzz 这样的库,但它们通常用于计算字符串相似度而非简单的包含关系。
  2. 数据类型一致性:

    • 在进行字符串包含检查时,确保所有参与比较的值都是字符串类型至关重要。代码中的 str(single_pd) 就是为了这个目的。如果 df2['PDs'] 列本身可能包含非字符串类型,也需要对其进行预处理(例如 df2['PDs'].astype(str))。
  3. 多对一匹配:

    • 当前方案是“一对多”的匹配,即 df1 的一个 PD 可能会匹配到 df2 中包含该 PD 的多个 delimited_pds_str。但由于 break 语句,它只会返回找到的第一个 Number。
    • 如果需要收集所有匹配到的 Number(例如,将它们存储为列表),则需要修改 mapped_numbers.append(number) 和 break 的逻辑。例如,可以为每个 single_pd 存储一个 Number 列表。
  4. 分隔符的灵活性:

    • 本教程假设分隔符是固定的分号 ;。如果分隔符不固定,或者有多种分隔符,则需要更复杂的字符串解析逻辑(例如,使用正则表达式 re.split())。

总结

处理Pandas中含分隔符列的模糊匹配是一个常见的挑战。虽然标准的 merge 函数无法直接应对,但通过结合迭代和字符串包含检查,我们可以有效地实现所需的数据关联。理解数据的特性、选择合适的匹配策略以及考虑性能和健壮性,是构建高效、可靠数据处理流程的关键。对于大规模数据,预处理和向量化操作往往是优于纯Python循环的优化方向。

以上就是Pandas中处理含分隔符列的模糊匹配与数据合并的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号