如何为300万行Pandas DataFrame生成无重复的拼接ID列?
问题描述
我有一个Pandas DataFrame,包含一列随机字母数字组合的id列,以及一列表示需为对应id添加的随机字符长度的missing列,数据量达300万行以上,示例如下:
id missing XK39J 4 NI94N 4 9IN3 5 MN83D 4 IUN2 5
我使用以下代码生成新的随机序列并拼接得到final_id:
import string import random import pandas as pd def id_generator(size, chars=string.ascii_uppercase + string.digits): return ''.join(random.SystemRandom().choice(chars) for _ in range(size)) data['new_id'] = data['missing'].apply(lambda x: id_generator(size=x)) data['final_id'] = data['id'] + data['new_id']
但生成的final_id列存在重复值,而我需要该列所有值唯一。我曾尝试将生成的ID存入列表并校验重复,但面对300万行数据时效率极低,代码如下:
def id_generator(size, chars=string.ascii_uppercase + string.digits): val_ls = [] val = ''.join(random.SystemRandom().choice(chars) for _ in range(size)) while val in val_ls: val = ''.join(random.SystemRandom().choice(chars) for _ in range(size)) else: val_ls.append(val) return val
请问如何高效确保final_id列无重复?
高效解决方案
方法1:批量生成+重复补全(适合完全随机需求)
核心思路:先批量生成所有new_id,再检查final_id的重复项,仅对重复的行重新生成,直到无重复。利用集合的O(1)查询特性替代列表的O(n)查询,大幅提升效率。
代码实现:
import string import random import pandas as pd def generate_batch_ids(sizes, chars=string.ascii_uppercase + string.digits): # 批量生成对应长度的随机字符串 return [''.join(random.SystemRandom().choice(chars) for _ in range(s)) for s in sizes] # 初始生成 data['new_id'] = generate_batch_ids(data['missing'].tolist()) data['final_id'] = data['id'] + data['new_id'] # 处理重复项 while True: # 找出重复的final_id行 duplicates = data[data.duplicated('final_id', keep=False)] if len(duplicates) == 0: break # 为重复行重新生成new_id duplicates['new_id'] = generate_batch_ids(duplicates['missing'].tolist()) duplicates['final_id'] = duplicates['id'] + duplicates['new_id'] # 更新原数据 data.loc[duplicates.index] = duplicates
优势:保证生成的字符串完全随机,仅处理少量重复项(当missing长度足够时,重复概率极低),效率远高于逐行校验。
方法2:基于行号的唯一随机字符串(最高效,绝对唯一)
核心思路:利用DataFrame的行号(唯一标识)生成指定长度的36进制字符串(字母+数字),既满足missing的长度要求,又能保证final_id绝对唯一,无需任何重复校验。
代码实现:
import string def row_id_to_str(row_num, length): # 36进制字符集,和原生成器一致 chars = string.ascii_uppercase + string.digits base = len(chars) # 转换行号为36进制 result = [] while row_num > 0: row_num, rem = divmod(row_num, base) result.append(chars[rem]) # 反转并补零至指定长度 str_id = ''.join(reversed(result)).zfill(length) # 若长度超要求则截断末尾(300万行用5位36进制足够:36^5=60466176) return str_id[-length:] if len(str_id) > length else str_id # 生成唯一的new_id data['new_id'] = data.apply(lambda row: row_id_to_str(row.name, row['missing']), axis=1) data['final_id'] = data['id'] + data['new_id']
优势:O(n)时间复杂度,无重复校验,绝对保证唯一性,适合超大规模数据。唯一缺点是字符串基于行号生成,并非完全随机,若允许这种“伪随机”,这是最优解。
方法3:分组预生成唯一随机字符串(适合分组场景)
核心思路:按missing的长度分组,为每个分组预先生成足够多的唯一随机字符串(数量大于该分组的行数),然后分配给对应行,避免重复。
代码实现:
import string import random import pandas as pd def generate_unique_ids(count, size, chars=string.ascii_uppercase + string.digits): # 生成指定数量的唯一随机字符串 unique_ids = set() while len(unique_ids) < count: unique_ids.add(''.join(random.SystemRandom().choice(chars) for _ in range(size))) return list(unique_ids) # 按missing分组处理 for size, group in data.groupby('missing'): # 为该组生成足够的唯一字符串 unique_ids = generate_unique_ids(len(group), size) # 分配给组内的行 data.loc[group.index, 'new_id'] = unique_ids data['final_id'] = data['id'] + data['new_id']
优势:每组内的字符串完全随机,且组内无重复;集合去重的效率高于逐行校验,适合missing取值较少的场景。
内容的提问来源于stack exchange,提问作者mjoy
相关产品推荐
相关产品推荐

