2017-03-24 3 views
5

Wenn ich den "tips" -Datensatz als Jointplot grafiere, würde ich die Top 10-Ausreißer (oder top-n-Ausreißer) anhand ihrer Indizes aus dem "tips" -Datafeld beschriften. Ich berechne den Rest (die Entfernung eines Punktes von der Durchschnittslinie), um die Ausreißer zu finden. Bitte ignorieren Sie die Vorzüge dieser Ausreißer-Erkennungsmethode. Ich möchte nur den Graphen gemäß der Spezifikation annotieren.Ausreißer auf dem Seaborn-Jointplot kommentieren

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) 

enter image description here

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

enter image description here

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

Wie mit Anmerkungen versehen ich die 10 Ausreißer (größte 5 und kleinste 5 Residuen) auf dem Graphen von jedem Indexwert des Punktes (größte Residuen) um dies zu haben:

enter image description here

Antwort

4

Sie können matplotlib annotate verwenden, um eine Anmerkung zu einem Punkt zu erstellen. Die Idee besteht darin, über die Datenrahmen zu iterieren und eine Annotation an die jeweilige Position zu setzen, die durch die Spalte "tip" und "total_bill" angegeben wird.

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() 

enter image description here


Beachten Sie, dass als Pandas Version 0.20 der pandas.ols has been removed. Um es zu ersetzen, kann man die OLS model von statsmodels verwenden. Die entsprechenden Zeilen würden dann lauten:

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

Beachten Sie, dass das Ergebnis etwas anders ist (wahrscheinlich aufgrund unterschiedlicher Gewichtung).

+0

Das Sortieren und Abschneiden der Iterablen 'head' und' tail' war eine gute Möglichkeit, die Anzahl der Iterationen zu reduzieren, vor allem für große Datenframes wie meine eigentliche Datenmenge. Danke –

+0

Das ist wirklich cool. Gute Arbeit! – Charlie

+0

Ich aktualisierte die Antwort mit einer Lösung für neuere Pandas. – ImportanceOfBeingErnest