Как удалить выброс из DataFrame с помощью IQR?
У меня есть Dataframe с большим количеством столбцов (около 100), я хочу применить метод межквартильного разметки и хотел удалить выброс из фрейма данных.
Я использую эту ссылку stackOverflow
Но проблема в том, что вышеприведенный метод работает правильно,
Как я пытаюсь вот так
Q1 = stepframe.quantile(0.25)
Q3 = stepframe.quantile(0.75)
IQR = Q3 - Q1
((stepframe < (Q1 - 1.5 * IQR)) | (stepframe > (Q3 + 1.5 * IQR))).sum()
это дает мне это
((stepframe < (Q1 - 1.5 * IQR)) | (stepframe > (Q3 + 1.5 * IQR))).sum()
Out[35]:
Day 0
Col1 0
Col2 0
col3 0
Col4 0
Step_Count 1179
dtype: int64
Я просто хотел знать, что я буду делать дальше, чтобы все выбросы из фрейма данных были удалены.
если я использую это
def remove_outlier(df_in, col_name):
q1 = df_in[col_name].quantile(0.25)
q3 = df_in[col_name].quantile(0.75)
iqr = q3-q1 #Interquartile range
fence_low = q1-1.5*iqr
fence_high = q3+1.5*iqr
df_out = df_in.loc[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)]
return df_out
re_dat = remove_outlier(stepframe, stepframe.columns)
Я получаю эту ошибку
ValueError: Cannot index with multidimensional key
в этой строке
df_out = df_in.loc[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)]
3 ответа
Ты можешь использовать:
np.random.seed(33454)
stepframe = pd.DataFrame({'a': np.random.randint(1, 200, 20),
'b': np.random.randint(1, 200, 20),
'c': np.random.randint(1, 200, 20)})
stepframe[stepframe > 150] *= 10
print (stepframe)
Q1 = stepframe.quantile(0.25)
Q3 = stepframe.quantile(0.75)
IQR = Q3 - Q1
df = stepframe[~((stepframe < (Q1 - 1.5 * IQR)) |(stepframe > (Q3 + 1.5 * IQR))).any(axis=1)]
print (df)
a b c
1 109 50 124
3 137 60 1990
4 19 138 100
5 86 83 143
6 55 23 58
7 78 145 18
8 132 39 65
9 37 146 1970
13 67 148 1880
15 124 102 21
16 93 61 56
17 84 21 25
19 34 52 126
Детали:
Сначала создать boolean DataFrame
с цепью |
:
print (((stepframe < (Q1 - 1.5 * IQR)) | (stepframe > (Q3 + 1.5 * IQR))))
a b c
0 False True False
1 False False False
2 True False False
3 False False False
4 False False False
5 False False False
6 False False False
7 False False False
8 False False False
9 False False False
10 True False False
11 False True False
12 False True False
13 False False False
14 False True False
15 False False False
16 False False False
17 False False False
18 False True False
19 False False False
А потом использовать DataFrame.any
для проверки хотя бы одного True
за строку и последнюю инвертированную логическую маску ~
:
print (~((stepframe < (Q1 - 1.5 * IQR)) | (stepframe > (Q3 + 1.5 * IQR))).any(axis=1))
0 False
1 True
2 False
3 True
4 True
5 True
6 True
7 True
8 True
9 True
10 False
11 False
12 False
13 True
14 False
15 True
16 True
17 True
18 False
19 True
dtype: bool
invert
решение с измененными условиями - <
в >=
а также >
в <=
по цепочке &
для AND и последний фильтр по all
для проверки всех True
с на строки
print (((stepframe >= (Q1 - 1.5 * IQR)) & (stepframe <= (Q3 + 1.5 * IQR))).all(axis=1))
0 False
1 True
2 False
3 True
4 True
5 True
6 True
7 True
8 True
9 True
10 False
11 False
12 False
13 True
14 False
15 True
16 True
17 True
18 False
19 True
dtype: bool
df = stepframe[((stepframe >= (Q1 - 1.5 * IQR))& (stepframe <= (Q3 + 1.5 * IQR))).all(axis=1)]
Вы забыли написать название своей колонки в цитате (['col_name'])
.
Правильный:
df_out = df_in.loc[(df_in['col_name'] > fence_low) & (df_in['col_name'] < fence_high)]
Прежде чем использовать эту функцию, убедитесь, что ваша DATAFRAME находится в переменной «df», потому что я создаю эту функцию таким образом. Если у вас другое имя переменной DATAFRAME, замените «df» на имя переменной DATAFRAME и все.
Почему я создаю длинную функцию??-> Потому что мне нужна вся информация, такая как выбросы, индекс выбросов, чтобы я мог видеть, как она работает с нижним и верхним забором.
def outliers(data):
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1
Lower_fence = Q1 - (1.5*IQR)
print(f"Lower fence is = {Lower_fence}")
Higher_fence = Q3 + (1.5*IQR)
print(f"Higher fence is = {Higher_fence}")
#here i'm taking all Outliers and appending this in Variable "Outlier".
Outlier =[]
for i in data:
if i < Lower_fence:
Outlier.append(i)
data.drop(data==i)
elif i > Higher_fence:
Outlier.append(i)
#With the help of "index" function here we are getting all the indexes of Lower_fence and Higher_fence
Index_Outlier = df[data < Lower_fence ].index
Index_Outlier = df[data > Higher_fence].index
#Here we are converting all the "Outliers" and "Index_Outliers" into string just to see all the data in One line
#If you do print(Outliers) or print(Outliers_index) you will get every element of data in New Line.
print(f"\nOutliers = {', '.join([str(x) for x in Outlier])}")
print(f"\nOutliers_INDEX = {', '.join([str(x) for x in Index_Outlier ])}")
#here we are seeing before and after shape.
print(f'\nBEFORE dropping Outlier we have rows = {df.shape[0]}, and columns = {df.shape[1]}')
df.drop(Index_Outlier,inplace=True)
print(f'AFTER dropping Outlier we have rows = {df.shape[0]}, and columns = {df.shape[1]}')