如何在Pandas中按姓氏首字母分类生成姓名字典
按姓氏首字母分组的全名字典构建方案
需求说明
需要生成一个字典,将所有姓名按**姓氏首字母(大写英文字母)**分组,每个字母键对应一个子列表,存储该首字母姓氏的全名,示例格式如下:
{'A': ['V. Aakalu', 'J.L. Accini', 'Kimberly A. Aeling', 'Konstantin Afanaciev', 'T. Afzar', 'Heidi Agnic'], 'B': ['Nicholas P. Breznay', 'B. Breznock', 'Rebecca Brincks', 'M.A. Brito Sanfiel', 'Reinhard Brunmeir'] .... }
遇到的问题
- 所有姓名出现在每个字母的列表中:用
dict.fromkeys(string.ascii_uppercase, [])初始化字典后,所有字母键共享同一个空列表,追加姓名时所有键的列表都会同步更新。 - 姓名被覆盖:使用
update()方法时,每个字母键最终只保留最后一个赋值的姓名,之前的内容被覆盖。
错误原因分析
dict.fromkeys的第二个参数如果是可变对象(比如列表),所有键会指向同一个对象引用,并非每个键独立创建新列表。update()方法用于替换字典的键值对,直接赋值字符串会覆盖原本的列表类型,导致每个键只能存储单个值。
最优解决方案
方案一:基于Pandas的高效实现(推荐)
利用Pandas的分组功能直接处理DataFrame,代码简洁且效率高:
import pandas as pd import string # 1. 生成全名列(名 + 空格 + 姓) main_db['full_name'] = main_db['auth_name'] + ' ' + main_db['auth_surname'] # 2. 过滤掉姓氏为空的行 valid_data = main_db.dropna(subset=['auth_surname']).copy() # 3. 提取姓氏首字母并转为大写 valid_data['surname_initial'] = valid_data['auth_surname'].str[0].str.upper() # 4. 拆分英文字母首字母和非英文字母/特殊字符的行 english_data = valid_data[valid_data['surname_initial'].isin(string.ascii_uppercase)] non_english_data = valid_data[~valid_data['surname_initial'].isin(string.ascii_uppercase)] # 5. 分组生成目标字典 name_dict = english_data.groupby('surname_initial')['full_name'].apply(list).to_dict() # 6. 处理非英文字母的姓名(可选) unnorm_dict = {} if not non_english_data.empty: unnorm_dict['Non-English'] = non_english_data['full_name'].tolist()
方案二:基础循环实现
手动初始化独立列表,遍历DataFrame行处理:
import string import pandas as pd # 初始化字典,每个字母键对应独立的空列表(关键:避免共享引用) name_dict = {char: [] for char in string.ascii_uppercase} unnorm_dict = {'Non-English': []} # 遍历每一行数据 for _, row in main_db.iterrows(): surname = row['auth_surname'] # 跳过姓氏为空的行 if pd.isna(surname): continue full_name = f"{row['auth_name']} {surname}" first_char = surname[0].upper() if first_char in name_dict: name_dict[first_char].append(full_name) else: unnorm_dict['Non-English'].append(full_name) # 可选:对每个子列表按姓氏排序 for key in name_dict: name_dict[key].sort()
原代码问题修正点
- 字典初始化错误:将
norm_dict = dict.fromkeys(string.ascii_uppercase, [])改为norm_dict = {char: [] for char in string.ascii_uppercase},确保每个键拥有独立列表。 - 遍历逻辑简化:无需将DataFrame转为字典,直接用
iterrows()遍历行更直观。 - 避免覆盖问题:使用
append()向列表添加元素,而非update()替换键值对。
内容的提问来源于stack exchange,提问作者BBB
相关产品推荐
相关产品推荐

