缺失值超30%时勿直接dropna,应分类型处理:数值列用time插值,类别列先编码再众数填充,高基数文本列标记MISSING;KNN填补需标准化且避免距离失真。

缺失值太多时,df.dropna() 直接删掉会丢数据,别急着删
当 df.isnull().mean().max() 超过 0.3(即某列 30% 以上是空),用 dropna() 很可能砍掉整行有效字段。尤其时间序列或用户行为日志里,缺失常呈块状分布——删一行可能损失多个关键指标。
更稳妥的做法是先分类型处理:
- 数值型列:优先考虑插值或邻近样本填补
- 类别型列(
dtype == 'object'或category):慎用插值,mode()或 KNN 更合适 - 高基数文本列(如用户 ID、URL):基本不填补,标记为
'MISSING'或保留NaN更安全
df.interpolate() 不是万能的,线性插值在非单调时间索引上会出错
interpolate() 默认按行索引线性插值,但如果你的 DataFrame 没设时间索引,或索引是乱序整数(比如从 CSV 读入未重置),它会把第 5 行和第 7 行之间“脑补”出第 6 行的值——这毫无业务意义。
正确做法:
- 先确保索引有意义:
df = df.set_index('timestamp').sort_index()(时间列需是datetime64) - 指定插值方法:
method='time'(按真实时间间隔)、method='pad'(前向填充)、limit=2(最多连续填 2 个) - 跳过非数值列:
df.select_dtypes(include='number').interpolate(method='time'),再用combine_first()合并回原表
示例:df['temp'].interpolate(method='time', limit_direction='both') 可双向填补,但注意 limit_direction 对 method='linear' 无效。
用 KNeighborsImputer 填类别变量前,必须做标签编码且不能含 NaN
sklearn.impute.KNeighborsImputer 只接受数值矩阵,直接传入含字符串的列会报 ValueError: Input contains NaN, infinity or a value too large for dtype('float64')——它自己不处理缺失,反而要求输入已 clean。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
实操流程必须严格按顺序:
- 对每个类别列,先用
pd.Categorical编码,再用.codes转成整数(-1 表示 NaN,需先替换) - 将所有 -1 替换为
np.nan,然后统一用SimpleImputer(strategy='most_frequent')填一次,保证无 NaN 才能进 KNN -
KNeighborsImputer(n_neighbors=3)的性能开销大,列数 > 50 或样本 > 10k 时建议采样或降维(如用TruncatedSVD)
别漏掉这步:imputer.fit_transform(X_numeric) 返回的是 numpy.ndarray,要手动转回 DataFrame 并对齐列名,否则后续 merge 会错位。
混合类型数据集上,KNN 和插值混用时要注意缩放与距离定义
如果同时对温度(单位 ℃)、用户点击次数(0–500)、页面停留秒数(0–30000)做 KNN 填补,未标准化会导致距离完全由大数值字段主导——点击次数一个单位变化 ≈ 温度变化 100℃,KNN 找到的“邻居”根本不是业务意义上的相似用户。
必须做:
- 数值列用
StandardScaler(不是MinMaxScaler,后者对离群值敏感) - 类别编码后的整数列,若取值范围过大(如用户 ID 达 1e6),需先哈希降维或改用频率编码
- 验证填补合理性:随机 mask 1% 已知值,用相同流程填补后,对比
mean_absolute_error,高于原始 std 的 0.5 倍就说明特征工程有问题
真正麻烦的不是代码写几行,而是每次换数据源就得重跑分布诊断——时间戳是否对齐、类别是否漂移、新出现的空字符串算不算缺失,这些没法靠一个 fit_transform 自动覆盖。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










