💓 博客主页:瑕疵的CSDN主页
📝 Gitee主页:瑕疵的gitee主页
⏩ 文章专栏:《热点资讯》
被 OneHotEncoder 的 NaN 坑到凌晨三点,终于搞定了
目录
昨晚写特征工程,OneHotEncoder 突然炸了。报错信息刺眼得像深夜的键盘声:ValueError: Input contains NaN, infinity or a value too large for dtype('float64')
我盯着屏幕看了半小时,才反应过来:它根本不吃 NaN!
数据里有缺失值(比如空字符串或np.nan),直接塞给 OneHotEncoder 就崩。
核心根源:
scikit-learn 的 OneHotEncoder 设计时就默认输入必须是干净的数值。它不处理缺失值,也不认 NaN。你得先清理数据,它才肯干活。
错误示范(我踩过坑):
fromsklearn.preprocessingimportOneHotEncoder# 假设 df['country'] 有 NaN 值enc=OneHotEncoder()X=df[['country']]# 有缺失值的列X_encoded=enc.fit_transform(X)# 报错!直接崩为啥崩?因为 OneHotEncoder 会检查输入,发现 NaN 就直接抛异常。它不负责填缺失,你得先处理。
正确姿势(直接上代码):
fromsklearn.composeimportColumnTransformerfromsklearn.pipelineimportPipelinefromsklearn.imputeimportSimpleImputerfromsklearn.preprocessingimportOneHotEncoder# 关键:用 SimpleImputer 先填充缺失,再编码preprocessor=ColumnTransformer(transformers=[('cat',Pipeline(steps=[('imputer',SimpleImputer(strategy='most_frequent')),# 用最常见值填充缺失(比如填"Unknown")('onehot',OneHotEncoder(handle_unknown='ignore'))# 处理未知类别,避免额外报错]),['country'])# 要处理的列名])# 一次性搞定:填充缺失 + 编码X_transformed=preprocessor.fit_transform(df)为什么这样写?
SimpleImputer(strategy='most_frequent'):把缺失值替换成该列最常出现的值(比如"China"填了 50 次,就用它)。handle_unknown='ignore':避免新类别(比如测试集有"Japan"但训练集没出现)导致崩溃。ColumnTransformer:把缺失值处理和编码打包成流水线,省得手动分步。
(图:数据输入 → 缺失值填充 → OneHot编码 → 输出特征)
避坑总结:
- 别跳过缺失值处理:OneHotEncoder 不会自动填 NaN,你得先喂它干净数据。
- 用 Pipeline 统一处理:别分开写 imputer 和 encoder,容易漏步骤。
handle_unknown别忘:测试集有新类别时,这个参数能救命。- 验证数据:
df.isnull().sum()先跑一遍,别让 NaN 悄悄混进来。
我昨天就是死磕了 2 小时,以为是 OneHotEncoder 的 bug。结果发现是自己忘了数据清洗。
现在写代码,先加一行df.fillna('Missing', inplace=True),再套编码器——省下半夜摸鱼的时间。
记住:数据脏了,再牛的模型也得跪。