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);
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);
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')
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.
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
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
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