Seaborn to świetny pakiet do robienia wysokiej jakości kreślenia z ładnymi wyjściami. Trochę jednak borykam się z używaniem Seaborn do nakładania zarówno danych, jak i prognoz modeli z modelu dopasowanego zewnętrznie. W tym przykładzie dopasowuję modele w Statsmodels, które są zbyt skomplikowane, aby Seaborn robił coś poza opakowaniem, ale myślę, że problem jest bardziej ogólny (tj. Jeśli mam przewidywania modelu i chcę wizualizować zarówno je, jak i dane za pomocą Seaborn).Wyświetlanie prognoz danych i modeli na jednym wykresie za pomocą Seaborn i Statsmodels
Zacznijmy od importu i zestaw danych:
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)
Mamy dopasować model w statsmodels zawierających wszystkie zmienne predykcyjne i ich interakcje:
# fit a model with all interactions
fit = smf.ols('y ~ x1 * x2 * x3', df).fit()
print(fit.summary())
Ponieważ w tym przypadku mamy wszystkie kombinacje zmiennych określone, a nasze prognozy modelu są liniowe, wystarczyłoby, aby na wykresie dodać nową kolumnę "predykcje" do ramki danych zawierającej prognozy modelu. Jednak, że nie jest bardzo ogólny (wyobrazić nasz model jest nieliniowa, a więc chcemy naszych działek, aby pokazać gładkie krzywe), więc zamiast tego zrobić nowy dataframe ze wszystkich kombinacji czynników predykcyjnych, następnie wygenerować prognozy:
# 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)
preds
dataframe wygląda następująco:
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
Od Seaborn działka poleceń (w przeciwieństwie ggplot2
poleceń w R) wydaje się, aby przyjąć jedną i tylko jeden dataframe, musimy połączyć nasze prognozy do surowych danych:
# append to df:
merged = df.append(preds)
Możemy teraz wykreślić modelu prognozy wraz z danymi z naszej ciągłej zmiennej x1
jako osi x:
# 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);
tej pory tak dobrze. Teraz wyobraźmy sobie, że nie mierzyliśmy zmiennej ciągłej x1
i wiemy tylko o dwóch pozostałych (kategorycznych) zmiennych (tj. Mamy strukturę czynnikową 2x2). W jaki sposób możemy wykreślić przewidywania modelu względem danych w tym przypadku?
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)
Cóż, możemy wykreślić modeli przewidywania użyciu sns.pointplot
lub podobny, jak w przykładzie:
# plot using seaborn:
g = sns.FacetGrid(merged, hue='x3', size=4)
g.map(sns.pointplot, 'x2', 'yhat')
g.add_legend();
sns.despine(offset=10);
lub dane za pomocą sns.factorplot
tak:
g = sns.factorplot('x2', 'y', hue='x3', kind='point', data=merged)
sns.despine(offset=10);
g.savefig('tmp3.png')
Ale nie widzę sposobu tworzenia wykresu podobnego do pierwszego (np. linie dla przewidywań modelu za pomocą plt.plot
, punkt rozproszenia danych za pomocą plt.scatter
). Powodem jest to, że zmienna x2
, którą próbuję użyć jako osi X, jest ciągiem/obiektem, więc komendy pyplot nie wiedzą, co z nimi zrobić.
Zauważ, że rozpoznaję, że linie na ostatnim wykresie są takie same jak linie na drugim wykresie (tj. prognozy modelu są liniami między środkami). To nie zawsze będzie prawdą, więc popieram bardziej ogólne podejście. – tsawallis
Należy również zauważyć, że z jakiegoś nieznanego powodu legenda na drugim wykresie nie pokazuje przypadków "c" i "d", a jedynie tytuł legendy. Nie wiem dlaczego. – tsawallis
Możesz przekazać dowolną funkcję do 'FacetGrid.map', dopóki pobiera argumenty pozycyjne i działki' x', 'y' na" aktualnie "aktywne osie. Więc powinieneś być w stanie zdefiniować funkcję, która mapuje z twoich kategorii do [0, 1, 2, ...] i używasz tego. To pomaga? – mwaskom