2015-01-30 3 views
5

Seaborn ist ein großartiges Paket für High-Level-Plotting mit hübschen Ausgaben. Allerdings habe ich Schwierigkeiten, Seaborn zu verwenden, um Daten und Modellvorhersagen aus einem extern angepassten Modell zu überlagern. In diesem Beispiel passe ich Modelle in Statsmodels an, die zu komplex sind, als dass Seaborn out-of-the-box hätte, aber ich denke, das Problem ist allgemeiner (dh wenn ich Modellvorhersagen habe und diese und Daten mit Seaborn visualisieren will)).Anzeigen von Daten und Modellvorhersagen in einem Diagramm mit Seaborn- und Statsmodels

Beginnen wir mit Importen und ein Datensatz starten:

import numpy as np 
import pandas as pd 
import seaborn as sns 
import statsmodels.formula.api as smf 
import patsy 
import itertools 
import matplotlib.pyplot as plt 

np.random.seed(12345) 

# make a data frame with one continuous and two categorical variables: 
df = pd.DataFrame({'x1': np.random.normal(size=100), 
        'x2': np.tile(np.array(['a', 'b']), 50), 
        'x3': np.repeat(np.array(['c', 'd']), 50)}) 

# create a design matrix using patsy: 
X = patsy.dmatrix('x1 * x2 * x3', df) 

# some random beta weights: 
betas = np.random.normal(size=X.shape[1]) 

# create the response variable as the noisy linear combination of predictors: 
df['y'] = np.inner(X, betas) + np.random.normal(size=100) 

Wir passen ein Modell in statsmodels alle Variablen Prädiktor enthält und deren Wechselwirkungen:

# fit a model with all interactions 
fit = smf.ols('y ~ x1 * x2 * x3', df).fit() 
print(fit.summary()) 

Da in diesem Fall haben wir alle Kombinationen von Variablen Da unsere Modellvorhersagen linear sind, wäre es ausreichend, wenn Sie dem Datenrahmen, der die Modellvorhersagen enthält, eine neue Spalte "Vorhersagen" hinzufügen möchten. Allerdings, das ist nicht sehr allgemein (man stelle sich unser Modell ist nicht linear und so wollen wir unsere Grundstücke glatte Kurven zeigen), so stattdessen ich einen neuen Datenrahmen mit allen Kombinationen von Prädiktoren machen, dann erzeugen die Prognosen:

# create a new dataframe of predictions, using pandas' expand grid: 
def expand_grid(data_dict): 
    """ A port of R's expand.grid function for use with Pandas dataframes. 

    from http://pandas.pydata.org/pandas-docs/stable/cookbook.html?highlight=expand%20grid 

    """ 
    rows = itertools.product(*data_dict.values()) 
    return pd.DataFrame.from_records(rows, columns=data_dict.keys()) 


# build a new matrix with expand grid: 

preds = expand_grid(
       {'x1': np.linspace(df['x1'].min(), df['x1'].max(), 2), 
       'x2': ['a', 'b'], 
       'x3': ['c', 'd']}) 
preds['yhat'] = fit.predict(preds) 

Die preds Datenrahmen sieht wie folgt aus:

x3  x1 x2  yhat 
0 c -2.370232 a -1.555902 
1 c -2.370232 b -2.307295 
2 c 3.248944 a -1.555902 
3 c 3.248944 b -2.307295 
4 d -2.370232 a -1.609652 
5 d -2.370232 b -2.837075 
6 d 3.248944 a -1.609652 
7 d 3.248944 b -2.837075 

Da Seaborn Plot-Befehle (im Gegensatz zu ggplot2 Befehle in R) erscheinen ein zu akzeptieren und nur ein Datenrahmen, müssen wir unsere Prognosen in den Rohdaten fusionieren:

# append to df: 
merged = df.append(preds) 

Wir können nun die Modellvorhersagen zusammen mit den Daten, mit unseren kontinuierlichen Variablen x1 als die x-Achse plotten:

# plot using seaborn: 
sns.set_style('white') 
sns.set_context('talk') 
g = sns.FacetGrid(merged, hue='x2', col='x3', size=5) 
# use the `map` method to add stuff to the facetgrid axes: 
g.map(plt.plot, "x1", "yhat") 
g.map(plt.scatter, "x1", "y") 
g.add_legend() 
g.fig.subplots_adjust(wspace=0.3) 
sns.despine(offset=10); 

enter image description here

So weit so gut. Stellen Sie sich nun vor, dass wir die kontinuierliche Variable x1 nicht gemessen haben und wir nur über die anderen zwei (kategorischen) Variablen wissen (d. H. Wir haben ein 2x2-faktorielles Design). Wie können wir die Modellvorhersagen in diesem Fall gegen Daten plotten?

fit = smf.ols('y ~ x2 * x3', df).fit() 
print(fit.summary()) 

preds = expand_grid(
       {'x2': ['a', 'b'], 
       'x3': ['c', 'd']}) 
preds['yhat'] = fit.predict(preds) 
print(preds) 

# append to df: 
merged = df.append(preds) 

Nun, wir können die Modellvorhersagen mit sns.pointplot oder ähnliche Darstellung, etwa so:

# plot using seaborn: 
g = sns.FacetGrid(merged, hue='x3', size=4) 
g.map(sns.pointplot, 'x2', 'yhat') 
g.add_legend(); 
sns.despine(offset=10); 

enter image description here

Oder die Daten mit sns.factorplot wie so:

g = sns.factorplot('x2', 'y', hue='x3', kind='point', data=merged) 
sns.despine(offset=10); 
g.savefig('tmp3.png') 

enter image description here

Aber ich sehe nicht, wie man eine Handlung ähnlich der ersten (d. H. Linien für Modellvorhersagen unter Verwendung von plt.plot, eine Punktstreuung für Daten unter Verwendung von plt.scatter). Der Grund dafür ist, dass die Variable x2, die ich als x-Achse verwenden möchte, eine Zeichenfolge/ein Objekt ist, sodass die pyplot-Befehle nicht wissen, was sie damit tun sollen.

+0

Beachten Sie, dass ich erkenne, dass die Linien in der letzten Handlung die gleichen wie die Linien in der zweiten Handlung sind (d. H. die Modellvorhersagen sind nur Linien zwischen den Mitteln). Dies wird jedoch nicht immer der Fall sein, daher bin ich auf eine allgemeinere Herangehensweise aus. – tsawallis

+0

Beachten Sie auch, dass die Legende im zweiten Diagramm aus einem unbekannten Grund nicht die Fälle "c" und "d" zeigt, sondern nur den Legendentitel. Ich weiß nicht warum. – tsawallis

+0

Sie können jede Funktion an 'FacetGrid.map' übergeben, solange' x', 'y' Positionsargumente und Diagramme auf den" aktuell "aktiven Achsen benötigt werden. Sie sollten also in der Lage sein, eine Funktion zu definieren, die von Ihren Kategorien auf [0, 1, 2, ...] abbildet und diese verwendet. Hilft das? – mwaskom

Antwort

4

Wie ich in meinen Kommentaren erwähnt habe, gibt es zwei Möglichkeiten, darüber nachzudenken.

Die erste ist eine Funktion zu definieren, um die Passform hat und dann Plots und übergeben es an FacetGrid.map:

import pandas as pd 
import seaborn as sns 
tips = sns.load_dataset("tips") 

def plot_good_tip(day, total_bill, **kws): 

    expected_tip = (total_bill.groupby(day) 
           .mean() 
           .apply(lambda x: x * .2) 
           .reset_index(name="tip")) 
    sns.pointplot(expected_tip.day, expected_tip.tip, 
        linestyles=["--"], markers=["D"]) 

g = sns.FacetGrid(tips, col="sex", size=5) 
g.map(sns.pointplot, "day", "tip") 
g.map(plot_good_tip, "day", "total_bill") 
g.set_axis_labels("day", "tip") 

enter image description here

Die zweite ist die Rechen die vorhergesagten Werte und sie dann zusammenführen in Ihre Datenrahmen mit einer zusätzlichen variablen, welche Daten identifiziert sind und was Modell:

tip_predict = (tips.groupby(["day", "sex"]) 
        .total_bill 
        .mean() 
        .apply(lambda x: x * .2) 
        .reset_index(name="tip")) 
tip_all = pd.concat(dict(data=tips[["day", "sex", "tip"]], model=tip_predict), 
        names=["kind"]).reset_index() 

sns.factorplot("day", "tip", "kind", data=tip_all, col="sex", 
       kind="point", linestyles=["-", "--"], markers=["o", "D"]) 

enter image description here

Verwandte Themen