如何用Pythonic方式为DataFrame匹配字符串对生成唯一ID
问题描述
现有如下Pandas DataFrame:
# Test dataframe import pandas as pd import numpy as np # Build df df = pd.DataFrame({ 'Title': ['title1', 'cat', 'dog'], 'References': [['donkey','chicken'],['title1','dog'],['bird','snake']] }) # 为唯一标题插入ID df['IDs'] = list(np.arange(0, len(df)) + 1) df = df[['Title','IDs','References']]
其中Title列的每个字符串对应唯一ID。需求是:为References列中的每个字符串分配ID,若该字符串与Title列某值匹配,则使用对应的ID;若不匹配,则分配新的唯一ID。
当前尝试通过嵌套循环配合以下匹配函数实现,但过程繁琐:
# Matching function def string_match(string1,string2): if string1 == string2: a = 1 else: a = 0 return a
寻求更Pythonic的实现方法。
更Pythonic的实现方案
方案一:预收集新字符串,批量分配ID
1. 构建标题-ID映射字典
先把Title和IDs转换成字典,实现O(1)时间复杂度的快速查找:
title_id_map = df.set_index('Title')['IDs'].to_dict()
2. 筛选未匹配的引用字符串并分配新ID
提取所有引用中的字符串,筛选出不在标题映射中的内容,去重后从现有最大ID开始分配新ID:
# 提取所有引用元素 all_refs = [item for sublist in df['References'] for item in sublist] # 去重后筛选未匹配的字符串 new_titles = list(set(all_refs) - set(title_id_map.keys())) # 分配新ID max_existing_id = df['IDs'].max() new_id_map = {title: max_existing_id + i + 1 for i, title in enumerate(new_titles)}
3. 合并映射并替换引用字符串
合并新旧ID映射,批量替换References中的字符串为对应ID:
full_id_map = {**title_id_map, **new_id_map} df['Reference_IDs'] = df['References'].apply(lambda x: [full_id_map[item] for item in x])
方案二:动态分配新ID(更简洁)
如果不需要单独保存新标题的映射关系,可以用dict.get()结合计数器动态处理,无需提前收集所有新字符串:
title_id_map = df.set_index('Title')['IDs'].to_dict() current_max_id = df['IDs'].max() def map_refs(ref_list): nonlocal current_max_id result = [] for item in ref_list: # 先尝试从已有映射获取,不存在则分配新ID id_val = title_id_map.get(item) if id_val is None: current_max_id += 1 id_val = current_max_id title_id_map[item] = id_val result.append(id_val) return result df['Reference_IDs'] = df['References'].apply(map_refs)
最终效果
处理后的DataFrame新增Reference_IDs列,示例结果如下:
| Title | IDs | References | Reference_IDs |
|---|---|---|---|
| title1 | 1 | ['donkey', 'chicken'] | [4, 5] |
| cat | 2 | ['title1', 'dog'] | [1, 3] |
| dog | 3 | ['bird', 'snake'] | [6, 7] |
内容的提问来源于stack exchange,提问作者keeran_q789
相关产品推荐
相关产品推荐

