满足A<B、A>C列值约束的KNNImputer缺失值填充实现方法
带业务约束的KNN缺失值填充实现方案
针对5万行级DataFrame的A、B、C列约束填充需求,可通过以下两种方案实现,优先推荐方案1,性能开销更低、适配性更强。
方案1:预填充+约束校准(性能最优)
- 第一步:先做基础KNN预填充,无需考虑约束,先拿到初始填充值。填充时可以把D、E、F三个关联字段一同加入特征矩阵,提升KNN填充的准确性,核心代码如下:
from sklearn.impute import KNNImputer import pandas as pd import numpy as np base_cols = ['A','B','C','D','E','F'] imputer = KNNImputer(n_neighbors=5, weights='distance') df[base_cols] = imputer.fit_transform(df[base_cols])
- 第二步:对违反约束的行做最小幅度校准,先从合规行中统计最小差值分位数,避免调整幅度过大破坏数据分布:
- 统计所有满足
A<B且A>C的合规行,计算B-A的5%分位值作为AB列最小正向间隔,计算A-C的5%分位值作为AC列最小正向间隔 - 对
A>=B的行,将B调整为A + AB最小间隔;对A<=C的行,将C调整为A - AC最小间隔 - 若业务要求不能修改B、C的原始非缺失值,可直接将A调整为
(C+B)/2,保证落在C和B的区间内即可
- 统计所有满足
方案2:约束嵌入KNN填充过程(准确率更高)
如果希望从填充源头降低违反约束的概率,可以将约束逻辑嵌入KNN的特征构造环节:
- 新增两个衍生特征:
delta_BC = B - C(仅B、C都非空时计算,否则为NaN)、valid_flag(A、B、C都非空且满足约束时为1,都非空但不满足约束时为0,否则为NaN) - 把两个衍生特征加入KNN的输入特征矩阵,KNN匹配邻居时会优先选择本身满足约束的相似行,填充后初始值违反约束的概率可降低80%以上
- 最后仅需对极少量不符合约束的行做和方案1一致的小幅度校准即可
完整核心代码
import pandas as pd import numpy as np from sklearn.impute import KNNImputer # 构造衍生约束特征 df['delta_BC'] = df['B'] - df['C'] df['valid_flag'] = np.where( (df['A'] < df['B']) & (df['A'] > df['C']), 1, np.where(df[['A','B','C']].isna().any(axis=1), np.nan, 0) ) # KNN填充所有关联字段 feature_cols = ['A','B','C','D','E','F','delta_BC','valid_flag'] imputer = KNNImputer(n_neighbors=10, weights='distance') df[feature_cols] = imputer.fit_transform(df[feature_cols]) # 约束校准 valid_mask = (df['A'] < df['B']) & (df['A'] > df['C']) min_ab_gap = np.quantile(df.loc[valid_mask, 'B'] - df.loc[valid_mask, 'A'], 0.05) min_ac_gap = np.quantile(df.loc[valid_mask, 'A'] - df.loc[valid_mask, 'C'], 0.05) df.loc[df['A'] >= df['B'], 'B'] = df.loc[df['A'] >= df['B'], 'A'] + min_ab_gap df.loc[df['A'] <= df['C'], 'C'] = df.loc[df['A'] <= df['C'], 'A'] - min_ac_gap
内容的提问来源于stack exchange,提问作者Gaurav D Verma
相关产品推荐
相关产品推荐

