Pandas按prisoner_type合并多列出现死循环与赋值报错求解
问题描述
首次在此提问,多日反复尝试未找到目标需求的最优实现方案,恳请大家提供帮助。
当前正在处理囚犯及判决相关调研数据:数据中prisoner_type列存储囚犯调研分类,每个囚犯类型对应5个记录罪名信息的列(并非所有列都会被使用)。需求为将不同囚犯类型对应的多组罪名列折叠合并为统一的5个罪名编码列+5个罪名类型列,添加到数据集后,每行仅需访问这10个新列即可获取对应罪名信息。
已构建字典存储每个囚犯类型对应的罪名编码、罪名类型源列名映射,外层字典键为囚犯类型,简化版本如下:
offense_variables= { 3: {'codes':{1:'V0114',2:'V0115',3:'V0116',4:'V0117',5:'V0118'}, 'off_types':{1:'V0124',2:'V0125',3:'V0126',4:'V0127',5:'V0128'}}, 8: {'codes':{1:'V0270',2:'V0271',3:'V0272',4:'V0273',5:'V0274'}, 'off_types': {1:'V0280',2:'V0281',3:'V0282',4:'V0283',5:'V0285'}} }
最初实现思路为:
- 创建10个新列:
offense_1...offense_5和type_1...type_5 - 使用pandas定位指定囚犯类型对应的所有行
- 对照字典查询该囚犯类型下每个序号对应的罪名存储列名,将对应列的值赋值给新列
运行时出现两个问题:
- 代码运行后无法终止,不清楚死循环原因
- 抛出报错:"A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead"
原有问题代码:
pris_types=[3,8] for pt in pris_types: # 调研中共记录5项罪名,因此需要5列存储罪名编码、5列存储罪名类型 # 1和2仅为占位值 for item in [i+1 for i in range(5)]: dataset[f'off_{item}_code']='1' dataset[f'off_{item}_type']='2' # 使用.loc获取当前囚犯类型对应的行索引 # 通过上述字典查询需要取值的源列名 for item in [i+1 for i in range(5)]: dataset.loc[dataset['prisoner_type'] == pt, \ dataset[f'off_{item}_code']] = \ dataset[offense_variables[pt]['codes'][item]] dataset.loc[dataset[prisoner_type] == pt, \ dataset[f'off_{item}_type']] = \ dataset[offense_variables[pt]['types'][item]]
错误原因与修正方案
代码共有5处核心问题,直接导致运行异常:
.loc索引参数错误:.loc第二个参数需要直接传入列名,原代码传入dataset[f'off_{item}_code'](整列Series),pandas会将Series值作为列名匹配,触发无意义的全量索引遍历,导致程序卡死- 字典键名不匹配:定义字典时罪名类型对应的键为
off_types,代码中误写为types,会触发KeyError - 列引用语法错误:第二处行筛选时
dataset[prisoner_type]未给prisoner_type加引号,会被识别为未定义变量,触发NameError - 新列初始化逻辑冗余:循环每个囚犯类型时都重复重置新列值为占位符,会覆盖之前循环的赋值结果
- 赋值逻辑不规范:右侧直接传入全量列数据,容易触发SettingWithCopy警告
修正后可直接运行的代码:
import numpy as np # 提前一次性初始化10个新列,用空值填充即可,无需占位符 for item in range(1, 6): dataset[f'off_{item}_code'] = np.nan dataset[f'off_{item}_type'] = np.nan pris_types = [3, 8] for pt in pris_types: # 提前生成当前囚犯类型的行筛选掩码,避免重复计算 row_filter = dataset['prisoner_type'] == pt for item in range(1, 6): # 从映射字典取对应源列名 source_code_col = offense_variables[pt]['codes'][item] source_type_col = offense_variables[pt]['off_types'][item] # 仅对筛选出的行做赋值,左右两侧用相同筛选逻辑,避免警告和索引错位 dataset.loc[row_filter, f'off_{item}_code'] = dataset.loc[row_filter, source_code_col] dataset.loc[row_filter, f'off_{item}_type'] = dataset.loc[row_filter, source_type_col]
扩展提示:如果后续新增其他囚犯类型,只需将对应类型的列映射补充到
offense_variables字典,同时将类型值加入pris_types列表即可,无需修改核心循环逻辑。
内容的提问来源于stack exchange,提问作者SecondStar
相关产品推荐
相关产品推荐

