Аннотировать выбросы на совместном графике Seaborn

Графически отображая набор данных «советы» как совместный график, я хотел бы пометить 10 лучших выбросов (или топ-n выбросов) на графике их индексами из кадра данных «советы». Я вычисляю невязку (расстояние точки от средней линии) для нахождения выбросов. Пожалуйста, игнорируйте достоинства этого метода обнаружения выбросов. Я просто хочу аннотировать график в соответствии со спецификацией.

import seaborn as sns
sns.set(style="darkgrid", color_codes=True)

tips = sns.load_dataset("tips")
model = pd.ols(y=tips.tip, x=tips.total_bill)
tips['resid'] = model.resid

#indices to annotate
tips.sort_values(by=['resid'], ascending=[False]).head(5)

введите описание изображения здесь

tips.sort_values(by=['resid'], ascending=[False]).tail(5)

введите описание изображения здесь

%matplotlib inline
g = sns.jointplot("total_bill", "tip", data=tips, kind="reg",
                  xlim=(0, 60), ylim=(0, 12), color="r", size=7)

Как аннотировать 10 лучших выбросов (наибольшие 5 и наименьшие 5 остатков) на графике по значению индекса каждой точки (наибольшие остатки), чтобы иметь это:

введите описание изображения здесь


person Thomas Matthew    schedule 24.03.2017    source источник


Ответы (1)


Вы можете использовать matplotlib annotate для создания аннотации к точке. Идея состоит в том, чтобы перебрать кадры данных и поместить аннотацию в соответствующую позицию, заданную столбцами "tip" и "total_bill".

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

sns.set(style="darkgrid", color_codes=True)

tips = sns.load_dataset("tips")
model = pd.ols(y=tips.tip, x=tips.total_bill)
tips['resid'] = model.resid

g = sns.jointplot("total_bill", "tip", data=tips, kind="reg",
                  xlim=(0, 60), ylim=(0, 12), color="r", size=7)

#indices to annotate
head = tips.sort_values(by=['resid'], ascending=[False]).head(5)

tail = tips.sort_values(by=['resid'], ascending=[False]).tail(5)

def ann(row):
    ind = row[0]
    r = row[1]
    plt.gca().annotate(ind, xy=(r["total_bill"], r["tip"]), 
            xytext=(2,2) , textcoords ="offset points", )

for row in head.iterrows():
    ann(row)
for row in tail.iterrows():
    ann(row)

plt.show()

введите описание изображения здесь


Обратите внимание, что в пандах версии 0.20 pandas.ols был удален. Чтобы заменить его, можно использовать модель OLS от statsmodels. Тогда соответствующие строки будут выглядеть так:

import statsmodels.api as sm
model = sm.OLS(tips.tip, tips.total_bill)
tips['resid'] = model.fit().resid

Обратите внимание, что результат немного отличается (вероятно, из-за разного веса).

person ImportanceOfBeingErnest    schedule 24.03.2017
comment
сортировка и усечение итераций head и tail были хорошим способом сократить количество итераций, особенно для больших фреймов данных, таких как мой фактический набор данных. Благодарность - person Thomas Matthew; 25.03.2017
comment
Я обновил ответ решением для более новых версий pandas. - person ImportanceOfBeingErnest; 02.07.2017