Kaggle警察枪击案数据集Label编码插补后逆转换报错如何解决
问题背景
现有一份可在Kaggle获取的警察枪击案数据集,多列存在缺失值,各列缺失率如下:
UID 0.000000 Name 0.000000 Age 0.018653 Gender 0.000640 Race 0.317429 Date 0.000000 City 0.000320 State 0.000000 Manner_of_death 0.000000 Armed 0.454487 Mental_illness 0.000000 Flee 0.000000 dtype: float64
复制原始DataFrame执行编码、缺失值插补操作后,逆转换还原标签时报错。
原始操作步骤
- 对所有分类列执行Label encode,涉及列如下:
Index(['Gender', 'Race', 'City', 'State', 'Manner_of_death', 'Armed', 'Mental_illness', 'Flee'], dtype='object')
对应代码:
le = LabelEncoder() lpf = {} for col in lepf.columns: lpf[col] = le.fit_transform(lepf[col]) lpfdf = pd.DataFrame(lpf)
- 定位原始数据集pf中的nan值,将lpfdf中对应缺失值的编码替换为np.nan:
统计各列缺失数代码:
for col in lpfdf: print(col,"\n",len(np.where(pf[col].to_frame().isna())[0]))
统计结果:
Gender 8
Race 3965
City 4
State 0
Manner_of_death 0
Armed 5677
Mental_illness 0
Flee 0
以City列为例,定位缺失值对应编码后,统一将各列缺失值编码替换为np.nan:
""" Gender: 2, Race: 6, City: 3327, Armed: 59 """ lpfdf["Gender"] = lpfdf["Gender"].replace(2, np.nan) lpfdf["Race"] = lpfdf["Race"].replace(6, np.nan) lpfdf["City"] = lpfdf["City"].replace(3327, np.nan) lpfdf["Armed"] = lpfdf["Armed"].replace(59, np.nan)
- 实例化IterativeImputer执行插补,取整后生成新DataFrame:
itimp = IterativeImputer() iilpf = itimp.fit_transform(lpfdf)
itimplpf = pd.DataFrame(np.round(iilpf), columns = lepf.columns)
报错信息
逆转换还原原标签时触发ValueError:
for col in lpfdf: le.inverse_transform(itimplpf[col].astype(int)) --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-191-fbdde4bb4781> in <module> 1 for col in lpfdf: ----> 2 le.inverse_transform(itimplpf[col].astype(int)) ~\anaconda3\lib\site-packages\sklearn\preprocessing\_label.py in inverse_transform(self, y) 158 diff = np.setdiff1d(y, np.arange(len(self.classes_))) 159 if len(diff): --> 160 raise ValueError( 161 "y contains previously unseen labels: %s" % str(diff)) 162 y = np.asarray(y) ValueError: y contains previously unseen labels: [2 3 4 5]
核心问题原因
- 全局共用同一个
LabelEncoder实例:循环编码所有分类列时仅用了一个le实例反复fit,该实例最终仅保存了最后一列Flee的类别映射关系,逆转换时用Flee的映射规则转换其他列的编码,自然会出现标签不匹配的报错。 - 插补结果存在超出原始编码范围的数值:
IterativeImputer输出的是连续值,取整后可能生成原始分类列不存在的编码值(比如Gender列原始有效编码只有0、1,插补后可能出现2、3等不存在的取值),逆转换时无法匹配到对应标签。
解决方法
步骤1:为每列单独存储LabelEncoder实例
编码时每个分类列单独实例化LabelEncoder,保存对应列的映射关系,避免相互覆盖,同时可直接保留空值,省略后续手动替换NaN的操作:
le_dict = {} lpf = {} for col in lepf.columns: # 每列单独初始化编码器 le = LabelEncoder() # 仅编码非空值,空值直接保留 non_na_mask = lepf[col].notna() lpf_col = lepf[col].copy() lpf_col[non_na_mask] = le.fit_transform(lpf_col[non_na_mask]) lpf[col] = lpf_col # 保存当前列的专属编码器 le_dict[col] = le lpfdf = pd.DataFrame(lpf)
步骤2:插补后截断编码范围
插补取整后,将每列的编码值限制在该列原始类别对应的编码范围内,避免出现不存在的标签:
itimp = IterativeImputer() iilpf = itimp.fit_transform(lpfdf) itimplpf = pd.DataFrame(np.round(iilpf), columns = lepf.columns) # 对每列做范围截断 for col in itimplpf.columns: max_valid_label = len(le_dict[col].classes_) - 1 itimplpf[col] = itimplpf[col].clip(0, max_valid_label).astype(int)
步骤3:使用对应列的专属编码器逆转换
逆转换时调用该列单独保存的编码器,不要用全局的le实例:
for col in itimplpf.columns: itimplpf[col] = le_dict[col].inverse_transform(itimplpf[col])
内容的提问来源于stack exchange,提问作者Mario Aguilar
相关产品推荐
相关产品推荐

