Seaborn - отличный пакет для выполнения высокоуровневого построения с хорошими выходами. Тем не менее, я немного борюсь с использованием Seaborn для наложения как данных, так и прогнозов модели из модели, подходящей извне. В этом примере я устанавливаю модели в Statsmodels, которые слишком сложны для Seaborn, чтобы делать из коробки, но я думаю, что проблема более общая (т.е. если у меня есть предсказания модели и вы хотите визуализировать их и данные с помощью Seaborn).Отображение данных и прогнозов модели на одном участке с использованием Seaborn и Statsmodels
Начнем с импорта и набор данных:
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)
Мы приспособит модель в statsmodels, содержащих все предикторов и их взаимодействий:
# fit a model with all interactions
fit = smf.ols('y ~ x1 * x2 * x3', df).fit()
print(fit.summary())
Поскольку в данном случае мы имеем все комбинации переменных и наши предсказания модели являются линейными, для построения графика было бы достаточно добавить новый столбец «предсказания» в блок данных, содержащий предсказания модели. Тем не менее, это не очень общее (представьте, наша модель является нелинейной, и поэтому мы хотим, чтобы наши участки, чтобы показать плавные кривые), так что вместо этого я делаю новый dataframe со всеми комбинациями предсказателей, а затем генерировать предсказание:
# 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 выглядит следующим образом:
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
Поскольку команды Seaborn сюжет (в отличие от ggplot2
команд R), по всей видимости принимать один и только один dataframe, мы должны объединить наши прогнозы в исходные данные:
# append to df:
merged = df.append(preds)
Теперь мы можем построить предсказания модели вместе с данными, с нашей непрерывной переменной x1
как ось х:
# 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);
До сих пор так хорошо. Теперь представьте, что мы не измеряли непрерывную переменную x1
, и знаем только о двух других (категориальных) переменных (т. Е. Имеем факториальную схему 2x2). Как мы можем построить прогноз модели в отношении данных в этом случае?
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)
Ну, мы можем построить предсказания модели с использованием sns.pointplot
или подобное, например, так:
# plot using seaborn:
g = sns.FacetGrid(merged, hue='x3', size=4)
g.map(sns.pointplot, 'x2', 'yhat')
g.add_legend();
sns.despine(offset=10);
Или данные с помощью sns.factorplot
так:
g = sns.factorplot('x2', 'y', hue='x3', kind='point', data=merged)
sns.despine(offset=10);
g.savefig('tmp3.png')
Но я не вижу, как создать сюжет, аналогичный первому (т. линии для предсказаний моделей с использованием plt.plot
, разброс точек для данных с использованием plt.scatter
). Причина в том, что переменная x2
, которую я пытаюсь использовать в качестве оси x, является строкой/объектом, поэтому команды pyplot не знают, что с ними делать.
Обратите внимание, что я признаю, что линии на последнем участке такие же, как линии на втором участке (т. модельные прогнозы - это просто линии между средствами). Однако это не всегда будет правдой, поэтому я буду придерживаться более общего подхода. – tsawallis
Также обратите внимание, что по какой-то неизвестной причине легенда на втором рисунке не показывает случаи «c» и «d», только название легенды. Я не знаю почему. – tsawallis
Вы можете передать любую функцию в 'FacetGrid.map', если она принимает' x', 'y' позиционные аргументы и графики на активные в настоящее время оси. Таким образом, вы должны иметь возможность определять функцию, которая отображает из ваших категорий в [0, 1, 2, ...] и использовать ее. Это помогает? – mwaskom