如何将DataFrame每行异常值替换为NaN?现有代码致全表NaN求解决
问题:替换DataFrame每行异常值为NaN后全表变NaN的原因及修正
我尝试使用以下代码将DataFrame每行中的异常值替换为NaN,但运行后整个DataFrame都变为NaN,请问我哪里出错了?
附尝试的代码:
import pandas as pd data = [['ANJSHD12', 140, 8, 99992, 0, 0, 0, 0, 1, 99999, 0,0, 0], ['ANJSHD15',10, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0], ['ANJSHD17',19, 18, 22, 19, 25, 18, 23, 22, 22, 17,16, 19]] df = pd.DataFrame(data, columns=['MATRÍCULA','V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7', 'V8', 'V9', 'V10','V11', 'V12']) range_cols = list(df.columns.values)[1:13] q1 = df[range_cols].quantile(0.25, axis=1) q3 = df[range_cols].quantile(0.75, axis=1) iqr = q3-q1 #interquartile range min_val = df.min(axis=1) max_val = q3+3*iqr df_filtered = df[(df[range_cols] > min_val) & (df[range_cols] < max_val)]
错误原因分析
- 非数值列干扰最小值计算:使用
df.min(axis=1)时包含了字符串类型的MATRÍCULA列,导致min_val成为字符串与数值混合的Series,和数值列比较时逻辑失效。 - 布尔索引形状不匹配:布尔矩阵仅对应12个数值列,但原DataFrame有13列,第一列无对应布尔判断,直接被置为NaN。
- 广播逻辑错误:
min_val和max_val是每行单个值的Series,直接与每行12个值的DataFrame比较时,广播方向错误,无法实现“逐元素和本行上下界对比”的需求。
修正后的代码
针对数值列逐行判断异常值,替换为NaN后合并回原DataFrame:
方法一:利用同形状DataFrame实现逐元素比较
import pandas as pd data = [['ANJSHD12', 140, 8, 99992, 0, 0, 0, 0, 1, 99999, 0,0, 0], ['ANJSHD15',10, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0], ['ANJSHD17',19, 18, 22, 19, 25, 18, 23, 22, 22, 17,16, 19]] df = pd.DataFrame(data, columns=['MATRÍCULA','V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7', 'V8', 'V9', 'V10','V11', 'V12']) # 提取数值列 num_cols = df.columns[1:] # 计算每行的四分位数、IQR及上下界 q1 = df[num_cols].quantile(0.25, axis=1) q3 = df[num_cols].quantile(0.75, axis=1) iqr = q3 - q1 # 若需沿用原逻辑用最小值当下界,替换为 df[num_cols].min(axis=1) lower_bound = q1 - 3 * iqr upper_bound = q3 + 3 * iqr # 将上下界转换为与数值列同形状的DataFrame lower_bound_df = pd.DataFrame([lower_bound]*len(num_cols)).T lower_bound_df.columns = num_cols upper_bound_df = pd.DataFrame([upper_bound]*len(num_cols)).T upper_bound_df.columns = num_cols # 替换异常值为NaN df_cleaned = df.copy() df_cleaned[num_cols] = df[num_cols].mask((df[num_cols] < lower_bound_df) | (df[num_cols] > upper_bound_df)) print(df_cleaned)
方法二:逐行apply处理
import pandas as pd data = [['ANJSHD12', 140, 8, 99992, 0, 0, 0, 0, 1, 99999, 0,0, 0], ['ANJSHD15',10, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0], ['ANJSHD17',19, 18, 22, 19, 25, 18, 23, 22, 22, 17,16, 19]] df = pd.DataFrame(data, columns=['MATRÍCULA','V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7', 'V8', 'V9', 'V10','V11', 'V12']) num_cols = df.columns[1:] def replace_row_outliers(row): num_vals = row[num_cols] q1 = num_vals.quantile(0.25) q3 = num_vals.quantile(0.75) iqr = q3 - q1 upper = q3 + 3 * iqr # 若需用最小值当下界,替换为 num_vals.min() lower = q1 - 3 * iqr num_vals[(num_vals < lower) | (num_vals > upper)] = pd.NA return row df_cleaned = df.apply(replace_row_outliers, axis=1) print(df_cleaned)
内容的提问来源于stack exchange,提问作者Jaribel Pokasideia
相关产品推荐
相关产品推荐

