2015-01-30 1 views
5

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

enter image description here

До сих пор так хорошо. Теперь представьте, что мы не измеряли непрерывную переменную 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); 

enter image description here

Или данные с помощью sns.factorplot так:

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

enter image description here

Но я не вижу, как создать сюжет, аналогичный первому (т. линии для предсказаний моделей с использованием plt.plot, разброс точек для данных с использованием plt.scatter). Причина в том, что переменная x2, которую я пытаюсь использовать в качестве оси x, является строкой/объектом, поэтому команды pyplot не знают, что с ними делать.

+0

Обратите внимание, что я признаю, что линии на последнем участке такие же, как линии на втором участке (т. модельные прогнозы - это просто линии между средствами). Однако это не всегда будет правдой, поэтому я буду придерживаться более общего подхода. – tsawallis

+0

Также обратите внимание, что по какой-то неизвестной причине легенда на втором рисунке не показывает случаи «c» и «d», только название легенды. Я не знаю почему. – tsawallis

+0

Вы можете передать любую функцию в 'FacetGrid.map', если она принимает' x', 'y' позиционные аргументы и графики на активные в настоящее время оси. Таким образом, вы должны иметь возможность определять функцию, которая отображает из ваших категорий в [0, 1, 2, ...] и использовать ее. Это помогает? – mwaskom

ответ

4

Как я упоминал в своих комментариях, я бы мог подумать об этом.

Во-первых, определить функцию, которая делает посадку, а затем участки и передать его в 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

Второй вычислитель предсказанные значения, а затем объединить их в ваш DataFrame с дополнительной переменной, которая определяет, что данные, а что модель:

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

Смежные вопросы