机器学习特征预处理之分类缺失填充

机器学习特征预处理之分类缺失填充
示例import pandas as pd import numpy as np from sklearn.impute import SimpleImputer def categorical_imputation(X_train, X_test, cat_cols, strategymost_frequent, fill_valueNone, verboseTrue): 分类缺失填充 - 必须在编码前执行 if not cat_cols: return X_train, X_test # ⭐ 关键修复统一将 None 转换为 np.nan X_train X_train.replace({None: np.nan}) X_test X_test.replace({None: np.nan}) def is_categorical_column(col): if col not in X_train.columns: return False if (pd.api.types.is_object_dtype(X_train[col]) or pd.api.types.is_categorical_dtype(X_train[col]) or pd.api.types.is_string_dtype(X_train[col])): return True if pd.api.types.is_integer_dtype(X_train[col]): n_unique X_train[col].nunique() n_total len(X_train[col]) if n_total 0 and n_unique / n_total 0.05: if verbose: print(f ℹ️ {col} 识别为整数编码分类 (唯一值: {n_unique})) return True return False valid_cat_cols [col for col in cat_cols if is_categorical_column(col)] ignored_cols set(cat_cols) - set(valid_cat_cols) if ignored_cols and verbose: print(f ⚠️ 忽略以下列: {ignored_cols}) if not valid_cat_cols: if verbose: print(f ⚠️ 没有有效的分类列需要填充) return X_train, X_test valid_strategies [most_frequent, constant] if strategy not in valid_strategies: if verbose: print(f ⚠️ 策略 {strategy} 不适用于分类数据切换为 most_frequent) strategy most_frequent if strategy constant and fill_value is None: fill_value UNKNOWN if verbose: print(f ℹ️ fill_value未指定使用默认值: {fill_value}) for col in valid_cat_cols: train_vals set(X_train[col].dropna().unique()) test_vals set(X_test[col].dropna().unique()) new_cats test_vals - train_vals if new_cats and verbose: print(f ⚠️ 测试集新类别 {col}: {new_cats}) try: if strategy constant: imputer SimpleImputer(strategystrategy, fill_valuefill_value) else: imputer SimpleImputer(strategystrategy) X_train.loc[:, valid_cat_cols] imputer.fit_transform(X_train[valid_cat_cols]) X_test.loc[:, valid_cat_cols] imputer.transform(X_test[valid_cat_cols]) if verbose: print(f ✅ 分类填充完成: {len(valid_cat_cols)} 列 (策略: {strategy})) except Exception as e: print(f ❌ 分类填充失败: {e}) print(f 问题列: {valid_cat_cols}) print(f 数据类型: {X_train[valid_cat_cols].dtypes}) raise return X_train, X_test调用示例print( * 60) print(测试场景1基本众数填充) print( * 60) # 创建训练集 X_train pd.DataFrame({ color: [red, blue, None, red, green, None], size: [M, L, M, None, S, M], category: [A, B, A, C, None, A], price: [100, 200, 150, 300, 250, 180] # 数值列 }) # 创建测试集 X_test pd.DataFrame({ color: [blue, None, red], size: [L, M, None], category: [B, C, A], price: [220, 190, 210] }) print(原始训练集:) print(X_train) print(\n原始测试集:) print(X_test) # 执行填充 cat_cols [color, size, category] X_train_filled, X_test_filled categorical_imputation( X_train, X_test, cat_cols, strategymost_frequent ) print(\n填充后的训练集:) print(X_train_filled) print(\n填充后的测试集:) print(X_test_filled) # 验证填充结果 print(\n验证填充结果:) for col in cat_cols: mode_val X_train[col].mode()[0] print(f {col}: 众数 {mode_val}) print(f 训练集缺失值: {X_train[col].isna().sum()} → 填充为 {mode_val}) print(f 测试集缺失值: {X_test[col].isna().sum()} → 填充为 {mode_val})数据缺失填充策略1. Mean均值操作用该特征列的算术平均数来填充缺失值。适用场景数据呈正态分布或对称分布且没有明显极端值时。优点计算简单能保持数据的整体均值不变。致命缺点极易受异常值影响。如果数据里有极端大或极端小的数均值会被“拉偏”填充出来的结果可能失真。2. Median中位数操作用该特征列的中位数即按大小排序后位于中间的那个数来填充缺失值。适用场景数据分布明显偏斜如收入数据大部分人收入低极少数人收入极高或者存在异常值时。优点稳健性极强。因为只看位置所以极端值的大小对中位数毫无影响比均值更“抗造”。3. Most_frequent众数操作用该特征列中出现频率最高的那个值来填充缺失值。适用场景专门用于分类离散型数据比如性别男/女、颜色红/蓝/绿。注意如果缺失值很多或者众数占比不高填充后可能会过度强化该类别导致数据多样性降低。在连续型数据中基本不用这个方法。4. Constant常量操作用一个自定义的固定值通常是“0”、“未知”、“-999”或“None”来填充所有缺失值。适用场景业务上缺失就是有特殊含义的比如“该用户未消费”金额填0作为机器学习中的占位符告诉算法“这个值是人为补的不代表真实水平”。缺点如果随意填一个毫无意义的常数比如用0填年龄会严重干扰数据分析必须谨慎使用。简单粗暴的速记口诀数据像钟形曲线对称→ 用Mean数据有暴发户极端值→ 用Median数据是类别标签男女/颜色→ 用Most_frequent数据缺失本身就是信息填无/填0→ 用Constant