Вывести часть датафрейма, соответствующую экстремальным значениям

У меня есть график ящик с усами, который показывает по годам уровень счастья в мире. И за три последних года я увидела, что есть экстремальные значения.

Задача: вывести фрагмент DataFrame который соответствует этим экстремальным значениям.

Я использовала такой код:

df_all_years[(df_all_years['Ladder score'] < 3.2)&(df_all_years['year']>2018)]

НО он выводит больше информации, чем хотелось бы получить.

Идея у меня состоит в том, что бы указать значения за пределами интерквартального размаха: q1-iqr*1.5.

А как это сделать я не понимаю.

Использовала цикл for и if, но ничего не получается. ('График с ящик с усами по парметру "Ladder Score" - уровень счастья') График ящик с усами по парметру "Ladder Score" - уровень счастья'


Ответы (1 шт):

Автор решения: Alexey Trukhanov

Не хотел использовать построчный .apply, так как ничего, кроме синтаксиса он не улучшает по сравнению с for, но так ничего и не придумал.

Решение

C помощью .groupby, считаем края нижних усов для каждого года. (Комментарий: фильтрацию по годам можно добавить на любом этапе).

С помощью построчного .apply создаем маску с использованием данных из предыдущего этапа и применяем ее к исходному датафрейму.

import random
import pandas as pd

# создадим тестовый датафрейм с нормальным распределением в колонке 'Ladder score'
dic = {
    'year': [random.randint(2017,2020) for _ in range(1000)],
    'Ladder score': [int(random.normalvariate(500, 90)) for _ in range(1000)],
    'some': [random.randint(100, 999) for _ in range(1000)]
}

df = pd.DataFrame.from_dict(dic)

# в переменную gr получим подсчитанные нижние усы для каждого года
gr = df.groupby('year')['Ladder score'].apply(
    lambda x: x.quantile(0.25) - (x.quantile(0.75) - x.quantile(0.25)) * 1.5
)

# создадим маску
mask = df.apply(lambda x: x['Ladder score'] < gr[x['year']], axis=1)

print(df[mask])

Повторю, этот код вернет все аномалии по всем годам. Чтобы ограничить нужными годами, можете применить фильтр на любом этапе.

print(df[mask & (df['year'] > 2018)]) 
→ Ссылка