如何保留目标变量值为1的行,同时过滤其他行的异常值?
不平衡数据集的异常值过滤需求
我有一个包含30个预测变量和1个目标变量的大型不平衡数据集:280,000条数据的目标值为false,仅450条为true。我需要基于这30个预测变量过滤异常值,但必须保留所有目标值为true(Class=1)的行。
当前尝试的代码
异常值检测与移除函数
def detect_outlier(df_in, col_name): for row in df_in['Class']: if row != 1: q1 = df_in[col_name].quantile(0.25) q3 = df_in[col_name].quantile(0.75) iqr = q3-q1 fence_low = q1-1.5*iqr fence_high = q3+1.5*iqr df_out = df_in.index[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)] return df_out def remove(df, ls): ls = sorted(set(ls)) df = df.drop(ls) return df def remove(df, ls): ls = sorted(set(ls)) df = df.drop(ls) return df
调用代码
# 检测Amount列的异常值 list = detect_outlier(cc_df,'Amount') list # 移除异常值得到新数据集 cc_df2 = remove(cc_df,list) cc_df2
现有代码的问题
- 异常值检测逻辑完全错误:
- 循环遍历
Class列时,遇到第一个Class≠1的行就直接计算全量数据的IQR区间并返回,既没有针对Class≠1的子集处理,也没实现保留Class=1行的要求。 - 计算分位数用了整个数据集,会被少数
Class=1的样本干扰异常值判断。 - 返回的是正常行的索引,但后续删除操作会把正常行删掉,完全搞反了逻辑。
- 循环遍历
- 冗余代码:重复定义了两次
remove函数,无意义。 - 变量名不规范:使用Python内置类型
list作为变量名,容易引发冲突。
改进后的实现方案
核心思路:仅对Class≠1的子集计算异常值,标记需要删除的异常行索引,最终保留Class=1的所有行 + Class≠1中的非异常行。
def detect_outliers_by_class(df, col_name, target_col='Class', target_keep=1): # 分离需要保留的行和需要检测异常的行 keep_df = df[df[target_col] == target_keep] check_df = df[df[target_col] != target_keep] # 仅基于待检测子集计算IQR区间 q1 = check_df[col_name].quantile(0.25) q3 = check_df[col_name].quantile(0.75) iqr = q3 - q1 fence_low = q1 - 1.5 * iqr fence_high = q3 + 1.5 * iqr # 找出待检测子集中的异常行索引 outlier_indices = check_df[(check_df[col_name] <= fence_low) | (check_df[col_name] >= fence_high)].index return outlier_indices def remove_outliers(df, outlier_indices): # 删除异常行,自动保留所有Class=1的行 cleaned_df = df.drop(outlier_indices) return cleaned_df # 单列处理示例(比如Amount列) outlier_idx = detect_outliers_by_class(cc_df, 'Amount') cc_df_cleaned = remove_outliers(cc_df, outlier_idx) # 批量处理30个预测变量示例 # 先定义所有预测变量列名(假设排除目标列Class) # predictor_cols = [col for col in cc_df.columns if col != 'Class'] # all_outlier_idx = [] # for col in predictor_cols: # col_outliers = detect_outliers_by_class(cc_df, col) # all_outlier_idx.extend(col_outliers) # # 去重后删除所有异常行 # all_outlier_idx = list(set(all_outlier_idx)) # cc_df_cleaned_all = remove_outliers(cc_df, all_outlier_idx)
改进点说明
- 精准过滤:仅针对
Class≠1的样本计算异常值,避免少数正样本干扰判断。 - 逻辑正确:返回需要删除的异常行索引,确保所有
Class=1的行被完整保留。 - 可扩展性:支持单列处理,也能批量遍历所有30个预测变量完成全局异常值过滤。
- 代码规范:移除冗余函数,避免使用内置类型作为变量名。
内容的提问来源于stack exchange,提问作者NewbDataME
相关产品推荐
相关产品推荐

