Не удаляются выбросы в таблице pandas
Пытаюсь удалить выбросы в таблице. Данные можно скачать по этой ссылке: http://data.insideairbnb.com/belize/bz/belize/2023-03-30/visualisations/listings.csv
Загружаю таблицу:
df = pd.read_csv('listings.csv')
df.head(5)
Строю диаграмму "Ящик с усами", чтобы проверить на выбросы.
all_numeric = ['price', 'minimum_nights', 'number_of_reviews', 'reviews_per_month',
'calculated_host_listings_count','availability_365', 'number_of_reviews_ltm']
for col in all_numeric:
plt.figure(figsize=(10, 5)) # Создаем frame
sns.boxplot(x=df[col]) # boxplot это ящик с усами. в скобочках указывается столбец.
plt.show()
Потом я удаляю выбросы таким способом:
for col in all_numeric:
Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df = df[(df[col] >= lower_bound) & (df[col] <= upper_bound)]
После удаления выбросов я еще раз строю диаграмму "Ящик с усами", но на ней отображаются выбросы. Подскажите, пожалуйста, так и должно быть или я что-то делаю не так?
Ответы (2 шт):
попробуйте указать параметр showfliers = False:
sns.boxplot(x=df[col], showfliers = False)
причем, ненужно удалять выбросы вручную:
f = pd.read_csv("listings.csv")
#df.head()
all_numeric = ['price', 'minimum_nights', 'number_of_reviews', 'reviews_per_month',
'calculated_host_listings_count','availability_365', 'number_of_reviews_ltm']
plt.figure(figsize=(10, 5))
sns.boxplot(x=df["price"])
sns.boxplot(x=df["price"], showfliers=False)
Странно, что этот параметр не упоминается в официальной документации к boxplot, но присутствует в официальной документации к boxenplot.
Кроме того, с помощью инструментария matplotlib можно получить сами выбросы и избавиться от них в датафрейме. Напрмер:
from matplotlib.cbook import boxplot_stats
outliers = boxplot_stats(df["price"]).pop(0)['fliers']
res = df[~df["price"].isin(outliers)]
Повторю здесь комментарий под вопросом:
Когда Вы последовательно применяете фильтрацию к каждой из колонок, то на каждой последующей итерации, следующая колонка представляет собой уже не тот набор данных, который был изначально, так как Вы уже отрезали часть данных по данным из предыдущих колонок. В результате, Вы рушите данные и когда Вы строите боксплот после фильтрации, эти ящики уже совсем не те, что были в начале, а совсем другое распределение. Я бы не удалял строки при фильтрации, а сделал бы обратную фильтрацию и забивал бы значения, выпадающие за усы, NaN. Тогда изначальный DF и распределения останутся целы.
Попробуйте вот так (меняем последнюю строку в цикле фильтрации):
df[col].where((df[col] >= lower_bound) & (df[col] <= upper_bound), other = np.nan, inplace=True)
Если не подключаете numpy, то np.nan поменяйте на float('nan')

