如何修复DataFrame按IQR过滤时出现的KeyError: '[x] not found in axis'
IQR异常值过滤时KeyError问题解决
问题描述
尝试用IQR(四分位距)对DataFrame的指定特征进行异常值过滤,代码如下:
import pandas as pd import numpy as np # Load data df = pd.read_csv("dataframe.csv") features = df.loc[:, ('col1, col2, col3, col4, col5')] print("Old Shape: ", df.shape) def filtering(column_name): print(column_name) Q1 = np.percentile(df[column_name], 25, interpolation = 'midpoint') Q3 = np.percentile(df[column_name], 75, interpolation = 'midpoint') IQR = Q3 - Q1 # Upper bound upper = np.where(df[column_name] >= (Q3+1.5*IQR)) # Lower bound lower = np.where(df[column_name] <= (Q1-1.5*IQR)) ''' Removing the Outliers ''' df.drop(upper[0], inplace = True) df.drop(lower[0], inplace = True) print("New Shape: ", df.shape) print('==== done ====') for col in features.columns: filtering(col)
运行时在df.drop(lower[0], inplace=True)处报错:
KeyError: '[14] not found in axis'
错误原因
- 索引与行位置混淆:
np.where()返回的是当前DataFrame中异常行的位置下标(从0开始的整数),但df.drop()默认按索引标签删除行。当之前删除过行后,DataFrame的索引不再连续,此时传入的位置下标对应的索引标签可能已被删除,触发KeyError。 - 逐步过滤的逻辑缺陷:循环处理每个特征时,每次删除行都会修改原DataFrame,后续特征的IQR计算基于已过滤后的数据集,导致过滤标准不断变化,同时可能重复尝试删除已被移除的行。
- 特征选取语法错误:原代码中
features = df.loc[:, ('col1, col2, col3, col4, col5')]是错误的,该写法会将整个字符串当作单个列名查找,正确的多列选取应使用列表['col1', 'col2', 'col3', 'col4', 'col5']。
解决方案
方案一:修正删除逻辑,按位置匹配索引标签
修改drop操作,通过行位置获取对应索引标签后再删除,确保操作的是当前DataFrame中存在的行:
import pandas as pd import numpy as np # Load data df = pd.read_csv("dataframe.csv") # 修正特征选取语法 features = df.loc[:, ['col1', 'col2', 'col3', 'col4', 'col5']] print("Old Shape: ", df.shape) def filtering(column_name): print(column_name) Q1 = np.percentile(df[column_name], 25, interpolation = 'midpoint') Q3 = np.percentile(df[column_name], 75, interpolation = 'midpoint') IQR = Q3 - Q1 # 获取异常行的位置下标 upper_pos = np.where(df[column_name] >= (Q3+1.5*IQR))[0] lower_pos = np.where(df[column_name] <= (Q1-1.5*IQR))[0] # 通过位置下标获取对应索引标签并删除 df.drop(df.index[upper_pos], inplace=True) df.drop(df.index[lower_pos], inplace=True) print("New Shape: ", df.shape) print('==== done ====') for col in features.columns: filtering(col)
方案二:统一收集异常行索引,一次性删除(推荐)
如果希望基于原始数据集的IQR标准过滤所有特征的异常值(避免逐步过滤导致的标准偏移),可先收集所有需删除的索引,最后一次性删除:
import pandas as pd import numpy as np # Load data df = pd.read_csv("dataframe.csv") # 修正特征选取语法 features = df.loc[:, ['col1', 'col2', 'col3', 'col4', 'col5']] original_df = df.copy() # 保存原始数据用于计算统一的IQR标准 to_drop = set() print("Old Shape: ", df.shape) def get_outlier_indices(column_name): col_data = original_df[column_name] Q1 = np.percentile(col_data, 25, interpolation='midpoint') Q3 = np.percentile(col_data, 75, interpolation='midpoint') IQR = Q3 - Q1 # 获取原始数据中的异常行索引 upper_indices = original_df[col_data >= (Q3+1.5*IQR)].index lower_indices = original_df[col_data <= (Q1-1.5*IQR)].index return set(upper_indices) | set(lower_indices) # 收集所有特征的异常行索引 for col in features.columns: outlier_indices = get_outlier_indices(col) to_drop.update(outlier_indices) print(f"{col} 找到 {len(outlier_indices)} 个异常值") # 一次性删除所有异常行 df.drop(to_drop, inplace=True) print("New Shape: ", df.shape) print('==== done ====')
内容的提问来源于stack exchange,提问作者SanderJ
相关产品推荐
相关产品推荐

