设计五种算法精确的身份证号匹配

设计五种算法精确的身份证号匹配

问题定义与数据准备

我们有两个Excel文件:

  • small.xlsx: 包含约5,000条记录。
  • large.xlsx: 包含约140,000条记录。

目标:快速、高效地从large.xlsx中找出所有其“身份证号”字段存在于small.xlsx“身份证号”字段中的记录,并将这些匹配的记录保存到一个新的Excel文件result.xlsx中。

假设:身份证号字段名在两个表中都是id_card

首先,我们进行准备工作,安装必要的库并模拟一些数据用于测试和性能估算。

pip install pandas openpyxl 
import pandas as pd import time import random # 为演示和测试,我们可以创建一些模拟数据(实际中使用pd.read_excel读取你的文件)defgenerate_id_card():"""生成一个模拟的18位身份证号""" region_code = random.choice(['110101','310104','440301'])# 随机地区码 birth_date =f"19{random.randint(50,99):02d}{random.randint(1,12):02d}{random.randint(1,28):02d}"# 随机生日 sequence_code =f"{random.randint(0,999):03d}"# 顺序码 check_code = random.choice(['X','0','1','2','3','4','5','6','7','8','9'])# 校验码return region_code + birth_date + sequence_code + check_code # 生成小表数据 (5000条) small_data ={'id_card':[generate_id_card()for _ inrange(5000)]} small_df = pd.DataFrame(small_data) small_df.to_excel('small.xlsx', index=False)# 生成大表数据 (140000条),并确保其中包含一部分小表中的ID large_list =[]# 首先,从small_df中随机取10000个ID(有重复,但身份证号唯一,所以用sample(n, replace=False))# 但为了确保有重复,我们这样做:大部分是新的,一部分是小的里面的。 ids_from_small = small_df['id_card'].tolist()# 假设大表中约有 3000 条记录与小表重合 overlap_ids = random.sample(ids_from_small,3000)for _ inrange(140000):# 约2%的概率使用一个重叠的ID,98%的概率生成一个新的IDif random.random()<0.02and overlap_ids: id_to_use = random.choice(overlap_ids)else: id_to_use = generate_id_card() large_list.append(id_to_use) large_data ={'id_card': large_list,'other_data':['Some other info']*140000} large_df = pd.DataFrame(large_data) large_df.to_excel('large.xlsx', index=False)print("模拟数据生成完成!")print(f"小表尺寸: {small_df.shape}")print(f"大表尺寸: {large_df.shape}")

现在,我们开始设计算法。


算法一:暴力双重循环 (Brute Force Double Loop)

原理与步骤

这是最直观、最基础的方法。

  1. 加载数据:将两个Excel表分别读入Pandas DataFrame,small_dflarge_df
  2. 嵌套循环
    • 外层循环遍历large_df的每一行(140,000次迭代)。
    • 内层循环遍历small_df的每一行(5,000次迭代)。
    • 对于每一对(large_id, small_id),比较它们是否相等。
  3. 收集结果:如果相等,则将large_df的当前行标记为匹配。
  4. 保存结果:将所有标记的行提取出来,保存到新的Excel文件。
Python实现
defalgorithm_1_brute_force(small_file, large_file, output_file):""" 算法1:暴力双重循环 """print("算法1:暴力双重循环 - 开始执行") start_time = time.time()# 1. 加载数据 small_df = pd.read_excel(small_file) large_df = pd.read_excel(large_file)# 确保id_card列是字符串类型,避免因数据类型导致的匹配失败 small_df['id_card']= small_df['id_card'].astype(str) large_df['id_card']= large_df['id_card'].astype(str)# 获取小表的身份证号列表 small_ids = small_df['id_card'].tolist()# 2. 嵌套循环比对 matched_rows =[]# 存储匹配的行索引或行数据 large_ids = large_df['id_card'].tolist()# 使用enumerate同时获取索引和值for i, large_id inenumerate(large_ids):for small_id in small_ids:if large_id == small_id: matched_rows.append(i)# 记录匹配的行索引break# 找到一个匹配就可以跳出内层循环,进入下一个大表ID# 3. 收集结果 result_df = large_df.iloc[matched_rows]# 4. 保存结果 result_df.to_excel(output_file, index=False) end_time = time.time() execution_time = end_time - start_time print(f"算法1完成。找到 {len(result_df)} 条匹配记录。耗时: {execution_time:.4f} 秒")return execution_time # 预计运行时间极长,在实际测试中可能跳过# time_1 = algorithm_1_brute_force('small.xlsx', 'large.xlsx', 'result_1.xlsx')
优劣对比
  • 优点
    • 实现极其简单,逻辑清晰,无需任何复杂的数据结构知识。
    • 无需额外内存(除了存储结果)。
  • 缺点
    • 时间复杂度极高:O(n * m),其中n是large表大小(140,000),m是small表大小(5,000)。总计 140,000 * 5,000 = 700,000,000 次比较。这是一个巨大的数字。
    • 预计运行时间:在普通的Python环境中,每秒大约能进行10万到100万次简单比较(取决于硬件)。按乐观的100万次/秒计算,也需要 700秒(约12分钟)。在实际的Pandas操作中,由于循环开销,速度会更慢,预计需要 30分钟到数小时绝对不推荐用于生产环境

算法二:利用Pandas的isin()方法

原理与步骤

这是对暴力算法的极大优化,利用了Pandas内置的高效向量化操作。

  1. 加载数据:同算法一。
  2. 创建查询集合:将small_df的“身份证号”列转换为一个Python集合(Set)。集合是基于哈希表实现的,其in操作的查询时间复杂度是平均O(1)。
  3. 向量化筛选:使用Pandas的isin()方法。该方法会接收一个集合或列表,并返回一个布尔序列(Series),指示large_df的“身份证号”列中的每个元素是否存在于给定的集合中。
  4. 布尔索引:使用这个布尔序列对large_df进行索引,快速筛选出所有匹配的行。
  5. 保存结果:同算法一。
Python实现
defalgorithm_2_pandas_isin(small_file, large_file, output_file):""" 算法2:利用Pandas的isin和集合 """print("算法2:Pandas isin() - 开始执行") start_time = time.time()# 1. 加载数据 small_df = pd.read_excel(small_file) large_df = pd.read_excel(large_file) small_df['id_card']= small_df['id_card'].astype(str) large_df['id_card']= large_df['id_card'].astype(str)# 2. 创建查询集合# 首先将small的id_card列转换为一个集合。# 集合的查找速度是O(1),非常快。 target_set =set(small_df['id_card'])# 3. 向量化筛选# isin()函数会检查large_df['id_card']的每个元素是否在target_set中 mask = large_df['id_card'].isin(target_set)# 4. 使用布尔索引获取结果 result_df = large_df[mask]# 5. 保存结果 result_df.to_excel(output_file, index=False) end_time = time.time() execution_time = end_time - start_time print(f"算法2完成。找到 {len(result_df)} 条匹配记录。耗时: {execution_time:.4f} 秒")return execution_time # 这是最推荐的方法之一,预计运行时间很短 time_2 = algorithm_2_pandas_isin('small.xlsx','large.xlsx','result_2.xlsx')
优劣对比
  • 优点
    • 实现非常简单,代码非常简洁。
    • 速度极快isin()是Pandas内部用C优化过的向量化操作,背后通常也使用了哈希表机制。它的时间复杂度可以近似看作是O(n),n是large表的大小。创建集合是O(m)。
    • 内存使用可控。集合占用的内存远小于DataFrame本身。
  • 缺点
    • 本质上还是需要将小表的数据完全加载到内存中构建集合。
    • 对于极端海量数据(例如小表有上亿条),构建集合可能成为瓶颈,但在本场景(5000条)中完全不是问题。
  • 预计运行时间1秒以内。这是处理此类问题的首选标准方法

算法三:Pandas Merge(合并)

原理与步骤

利用数据库的INNER JOIN思想,使用Pandas的合并功能。

  1. 加载数据:同算法一。
  2. 执行内连接:使用pd.merge()函数,以“身份证号”作为连接键,对两个DataFrame进行内连接。内连接的特性是只会保留两个表中键值匹配的行。
  3. 保存结果:连接的结果就是我们需要的数据,直接保存即可。需要注意的是,如果两个表有其他同名列,会产生后缀,但我们的目标只是身份证号匹配,所以可以直接保存。
Python实现
defalgorithm_3_pandas_merge(small_file, large_file, output_file):""" 算法3:Pandas Merge (Inner Join) """print("算法3:Pandas Merge - 开始执行") start_time = time.time()# 1. 加载数据 small_df = pd.read_excel(small_file) large_df = pd.read_excel(large_file) small_df['id_card']= small_df['id_card'].astype(str) large_df['id_card']= large_df['id_card'].astype(str)# 2. 执行内连接# on参数指定连接的列名。how='inner'表示内连接。 result_df = pd.merge(large_df, small_df[['id_card']], on='id_card', how='inner')# 注意:这里使用small_df[['id_card']]而不是small_df,是为了避免两个表有其他同名列导致合并后产生重复列(_x, _y)。# 我们只需要用small表的id_card列作为匹配键,不需要它的其他数据。# 3. 保存结果 result_df.to_excel(output_file, index=False) end_time = time.time() execution_time = end_time - start_time print(f"算法3完成。找到 {len(result_df)} 条匹配记录。耗时: {execution_time:.4f} 秒")return execution_time # 这也是非常高效且推荐的方法 time_3 = algorithm_3_pandas_merge('small.xlsx','large.xlsx','result_3.xlsx')
优劣对比
  • 优点
    • 实现极其简洁,语义清晰,一看就懂是做连接操作。
    • 速度非常快。Pandas的merge函数底层也经过了高度优化,通常基于哈希或排序-合并算法,效率很高。其性能与isin()方法在同一数量级。
    • 可以轻松处理更复杂的连接条件(多列作为键)。
  • 缺点
    • 会比isin()方法产生一些额外的中间开销,因为需要协调两个表的列。但在本场景下差异微乎其微。
    • 如果连接键不唯一,可能会产生笛卡尔积,导致结果行数爆炸(但身份证号是唯一的,所以不存在这个问题)。
  • 预计运行时间1秒左右。与算法二同为首选标准方法

算法四:使用数据库(SQLite)

原理与步骤

将数据加载到内存数据库(如SQLite)中,使用SQL语言的INJOIN语句来让数据库引擎完成高效的查找工作。

  1. 创建内存数据库:使用sqlite3模块在内存中创建一个临时数据库。
  2. 导入数据:将两个Pandas DataFrame分别写入数据库中的两个表(例如small_tablelarge_table)。
  3. 执行SQL查询:编写SQL查询语句(例如SELECT large_table.* FROM large_table WHERE large_table.id_card IN (SELECT id_card FROM small_table))。
  4. 获取结果:将SQL查询的结果读回一个Pandas DataFrame。
  5. 保存结果:同算法一。
Python实现
import sqlite3 defalgorithm_4_sqlite(small_file, large_file, output_file):""" 算法4:使用SQLite内存数据库 """print("算法4:SQLite内存数据库 - 开始执行") start_time = time.time()# 1. 加载数据 small_df = pd.read_excel(small_file) large_df = pd.read_excel(large_file) small_df['id_card']= small_df['id_card'].astype(str) large_df['id_card']= large_df['id_card'].astype(str)# 2. 创建内存数据库连接 conn = sqlite3.connect(':memory:')# 3. 导入数据到数据库 small_df.to_sql('small_table', conn, index=False) large_df.to_sql('large_table', conn, index=False)# 4. 编写并执行SQL查询# 方法A: 使用IN子句 query =""" SELECT large_table.* FROM large_table WHERE large_table.id_card IN (SELECT id_card FROM small_table) """# 方法B: 使用INNER JOIN (通常数据库会对JOIN优化得更好)#"# SELECT l.* # FROM large_table l# INNER JOIN small_table s ON l.id_card = s.id_card# """ result_df = pd.read_sql_query(query, conn)# 5. 关闭连接 conn.close()# 6. 保存结果 result_df.to_excel(output_file, index=False) end_time = time.time() execution_time = end_time - start_time print(f"算法4完成。找到 {len(result_df)} 条匹配记录。耗时: {execution_time:.4f} 秒")return execution_time time_4 = algorithm_4_sqlite('small.xlsx','large.xlsx','result_4.xlsx')
优劣对比
  • 优点
    • 非常高效。SQLite等数据库引擎是专门为快速数据查询而设计的,会自动为连接键创建索引以加速查询(虽然在这个一次性操作中我们没显式创建,但它的查询优化器仍然很强大)。
    • 处理海量数据时优势更明显。如果数据量大到Pandas操作困难,可以改用磁盘数据库,并显式创建索引。
    • 可以利用强大的SQL语法处理极其复杂的匹配逻辑。
  • 缺点
    • 实现步骤稍多,需要将数据导入导出数据库,增加了额外的I/O开销(尽管是在内存中)。
    • 对于这种规模的问题,其性能通常略慢于纯Pandas的向量化操作(算法二和三),因为多了数据迁移的步骤。
  • 预计运行时间1-3秒。在数据量极大(数千万以上)或匹配逻辑复杂时,此方法优势会显现。

算法五:分块处理 (Chunking)

原理与步骤

这个算法并非用于提升速度,而是用于解决内存不足的问题。当large.xlsx文件巨大(例如几个GB),无法一次性读入内存时,就需要使用此方法。它结合了算法二的思想。

  1. 加载小数据:将small.xlsx全部读入内存,并创建集合S。
  2. 分块读取大数据:使用Pandas的read_excel()chunksize参数,分批读取large.xlsx。每次只读取一个块(例如10000行)到内存中。
  3. 逐块处理:对于每个数据块,使用isin(S)方法筛选出匹配的行。
  4. 累积结果:将每个块的处理结果追加到一个列表中,或者直接写入结果文件。
  5. 合并保存结果:处理完所有块后,将累积的结果合并并保存,或者由于是逐块写入文件,最后只需要确保文件关闭即可。
Python实现
defalgorithm_5_chunking(small_file, large_file, output_file, chunksize=10000):""" 算法5:分块处理(用于内存不足的大文件场景) """print("算法5:分块处理 - 开始执行") start_time = time.time()# 1. 加载小数据并创建集合 small_df = pd.read_excel(small_file) small_df['id_card']= small_df['id_card'].astype(str) target_set =set(small_df['id_card'])# 2. 初始化一个列表来存储每个块的结果,或者直接写入文件# 我们采用直接写入文件的方式,避免在内存中累积巨大的DataFrame first_chunk =True# 使用一个csv writer或者每次追加DataFrame到Excel比较麻烦。# 更简单的方法是:使用一个列表收集结果DF,最后再concat。但如果结果也很大,内存会爆。# 因此,我们使用‘a’(append)模式写入Excel,但注意OpenPyXL需要每次创建一个新的writer对象。# 这里为简单起见,我们收集块结果,最后统一写入。假设结果集本身不会太大(最多140000行中的一小部分)。 chunks_result_list =[]# 3. 分块读取大数据 chunk_reader = pd.read_excel(large_file, chunksize=chunksize)for chunk in chunk_reader: chunk['id_card']= chunk['id_card'].astype(str)# 4. 处理当前块 mask = chunk['id_card'].isin(target_set) filtered_chunk = chunk[mask] chunks_result_list.append(filtered_chunk)print(f"已处理一个数据块,该块找到 {len(filtered_chunk)} 条匹配记录。")# 5. 合并结果并保存if chunks_result_list: final_result_df = pd.concat(chunks_result_list, ignore_index=True)else: final_result_df = pd.DataFrame()# 创建一个空DataFrame final_result_df.to_excel(output_file, index=False) end_time = time.time() execution_time = end_time - start_time print(f"算法5完成。找到 {len(final_result_df)} 条匹配记录。耗时: {execution_time:.4f} 秒")return execution_time # 这个算法主要用于演示大文件处理,对于140000行数据,没必要分块。# time_5 = algorithm_5_chunking('small.xlsx', 'large.xlsx', 'result_5.xlsx', chunksize=50000)
优劣对比
  • 优点
    • 内存友好。核心优势是能够处理大于内存的数据文件,因为它永远不会同时将整个大表加载到内存中。
    • 结合了Pandas向量化操作的效率。
  • 缺点
    • 速度可能稍慢:由于需要多次读取文件、循环处理每个块,会产生额外的I/O开销和循环开销。比算法二、三要慢。
    • 实现稍复杂。
  • 预计运行时间2-5秒(主要开销在分块读取Excel上)。只有在处理超大文件、内存不足时才需要使用。对于140000条记录,完全不需要分块。

总结与最终对比

我们将五种算法的优缺点和适用场景总结如下:

算法优点缺点预计时间推荐度
1. 暴力循环实现简单速度极慢,无法忍受~30分钟以上⭐(绝不推荐)
2. Pandas isin()实现简单,速度最快需要内存容纳小表集合<1秒⭐⭐⭐⭐⭐(首选
3. Pandas Merge实现简单,速度最快略有额外开销~1秒⭐⭐⭐⭐⭐(首选
4. SQLite高效,支持复杂查询,海量数据优势步骤稍多,数据迁移开销1-3秒⭐⭐⭐⭐(备用方案)
5. 分块处理内存友好,可处理超大文件速度较慢,实现稍复杂2-5秒⭐⭐⭐(特殊场景)

最终结论与建议

  1. 对于你的具体问题(5000条 vs 140000条)
    • 毫不犹豫地选择算法二(isin())或算法三(merge()。它们是专门为这种表格数据操作设计的,代码简洁、效率最高。两者性能差异可以忽略不计,按个人编码喜好选择即可。
  2. 如果你的小表也变得非常大(例如上百万条)
    • 算法二和三仍然有效,但创建集合或进行合并的内存消耗会变大。此时需要确保你的机器有足够RAM。
  3. 如果你的大表巨大(例如几十GB,无法读入内存)
    • 选择算法五(分块处理),它是解决此类问题的标准范式。
  4. 如果你的匹配逻辑变得非常复杂(不仅仅是相等匹配)
    • 考虑使用算法四(SQLite),利用SQL强大的表达能力来编写复杂查询,或者使用专门的记录链接库(如recordlinkage)。
  5. 算法一(暴力循环):永远只存在于教学示例中,用于提醒大家时间复杂度的重要性。

代码执行:你可以创建一个主函数来运行和比较这些算法(除了算法一)。

if __name__ =='__main__': files =('small.xlsx','large.xlsx') times ={} times['alg_2']= algorithm_2_pandas_isin(*files,'result_2.xlsx') times['alg_3']= algorithm_3_pandas_merge(*files,'result_3.xlsx') times['alg_4']= algorithm_4_sqlite(*files,'result_4.xlsx')# 对于这个数据量,算法5可能比2和3慢,但可以测试 times['alg_5']= algorithm_5_chunking(*files,'result_5.xlsx', chunksize=50000)print("\n=== 所有算法耗时对比 ===")for alg, t in times.items():print(f"{alg}: {t:.4f} 秒")

在实际运行中,你会看到算法二和三以绝对优势胜出。

在这里插入图片描述

Read more

AI Agent新范式:FastGPT+MCP协议实现工具增强型智能体构建

AI Agent新范式:FastGPT+MCP协议实现工具增强型智能体构建

AI Agent新范式:FastGPT+MCP协议实现工具增强型智能体构建 作者:高瑞冬 本文目录 * AI Agent新范式:FastGPT+MCP协议实现工具增强型智能体构建 * 一、MCP协议简介 * 二、创建MCP工具集 * 1. 获取MCP服务地址 * 2. 在FastGPT中创建MCP工具集 * 三、测试MCP工具 * 四、AI模型调用MCP工具 * 1. 调用单个工具 * 2. 调用整个工具集 * 五、私有化部署支持 * 1. 环境准备 * 2. 修改docker-compose.yml文件 * 3. 修改FastGPT配置 * 4. 重启服务 * 六、使用MCP-Proxy集成多个MCP服务 * 1. MCP-Proxy简介 * 2. 安装MCP-Proxy * 3. 配置MCP-Proxy * 4. 将MCP-Proxy与FastGPT集成 * 5. 高级配置

By Ne0inhk
【大模型实战篇】基于Claude MCP协议的智能体落地示例

【大模型实战篇】基于Claude MCP协议的智能体落地示例

1. 背景         之前我们在《MCP(Model Context Protocol) 大模型智能体第一个开源标准协议》一文中,介绍了MCP的概念,虽然了解了其概念、架构、解决的问题,但还缺少具体的示例,来帮助进一步理解整套MCP框架如何落地。         今天我们基于claude的官方例子--获取天气预报【1】,来理解MCP落地的整条链路。 2. MCP示例         该案例是构建一个简单的MCP天气预报服务器,并将其连接到主机,即Claude for Desktop。从基本设置开始,然后逐步发展到更复杂的使用场景。         大模型虽然能力非常强,但其弊端就是内容是过时的,这里的过时不是说内容很旧,只是表达内容具有非实时性。比如没有获取天气预报和严重天气警报的能力。因此我们将使用MCP来解决这一问题。         构建一个服务器,该服务器提供两个工具:获取警报(get-alerts)和获取预报(get-forecast)。然后,将该服务器连接到MCP主机(在本例中为Claude for Desktop)。         首先我们配置下环

By Ne0inhk
基于腾讯云HAI + DeepSeek快速设计自己的个人网页

基于腾讯云HAI + DeepSeek快速设计自己的个人网页

前言:通过结合腾讯云HAI 强大的云端运算能力与DeepSeek先进的 AI技术,本文介绍高效、便捷且低成本的设计一个自己的个人网页。你将了解到如何轻松绕过常见的技术阻碍,在腾讯云HAI平台上快速部署DeepSeek模型,仅需简单几步,就能获取一个包含个人简介、技能特长、项目经历及联系方式等核心板块的响应式网页。 目录 一、DeepSeek模型部署在腾讯云HAI 二、设计个人网页 一、DeepSeek模型部署在腾讯云HAI 把 DeepSeek 模型部署于腾讯云 HAI,用户便能避开官网访问限制,直接依托腾讯云 HAI 的超强算力运行 DeepSeek-R1 等模型。这一举措不仅降低了技术门槛,还缩短了部署时间,削减了成本。尤为关键的是,凭借 HAI 平台灵活且可扩展的特性,用户能够依据自身特定需求定制专属解决方案,进而更出色地适配特定业务场景,满足各类技术要求 。 点击访问腾讯云HAI控制台地址: 算力管理 - 高性能应用服务 - 控制台 腾讯云高性能应用服务HAI已支持DeepSeek-R1模型预装环境和CPU算力,只需简单的几步就能调用DeepSeek - R1

By Ne0inhk
AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革

AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革

云边有个稻草人-ZEEKLOG博客 目录 引言 一、什么是DeepSeek? 1.1 DeepSeek平台概述 1.2 DeepSeek的核心功能与技术 二、蓝耘通义万相2.1概述 2.1 蓝耘科技简介 2.2 蓝耘通义万相2.1的功能与优势 1. 全链条智能化解决方案 2. 强大的数据处理能力 3. 高效的模型训练与优化 4. 自动化推理与部署 5. 行业专用解决方案 三、蓝耘通义万相2.1与DeepSeek的对比分析 3.1 核心区别 3.2 结合使用的优势 四、蓝耘注册流程 五、DeepSeek与蓝耘通义万相2.1的集成应用 5.1 集成应用场景 1. 智能医疗诊断

By Ne0inhk