Группировка ящиков в морском дне, когда ввод данных является DataFrame
Я намерен построить несколько столбцов в pandas dataframe
, все сгруппированы по другому столбцу, используя groupby
внутри seaborn.boxplot
. Здесь есть приятный ответ на аналогичную проблему в matplotlib
matplotlib: Group boxplots, но учитывая тот факт, что seaborn.boxplot
поставляется с опцией groupby
, я думал, что это было бы намного проще сделать это в seaborn
.
Здесь мы переходим к воспроизводимому примеру, который терпит неудачу:
import seaborn as sns
import pandas as pd
df = pd.DataFrame(
[
[2, 4, 5, 6, 1],
[4, 5, 6, 7, 2],
[5, 4, 5, 5, 1],
[10, 4, 7, 8, 2],
[9, 3, 4, 6, 2],
[3, 3, 4, 4, 1]
], columns=['a1', 'a2', 'a3', 'a4', 'b'])
#Plotting by seaborn
sns.boxplot(df[['a1','a2', 'a3', 'a4']], groupby=df.b)
То, что я получаю, это то, что полностью игнорирует параметр groupby
:
![Failed groupby]()
Если я делаю это с одним столбцом, он работает благодаря другому SO-запросу Seaborn groupby pandas Series:
sns.boxplot(df.a1, groupby=df.b)
![seaborn that does not fail]()
Итак, я хотел бы получить все мои столбцы в одном сюжете (все столбцы имеют аналогичный масштаб).
EDIT:
Вышеупомянутый вопрос SO был отредактирован и теперь включает в себя "не чистый" ответ на эту проблему, но было бы неплохо, если бы у кого-то была лучшая идея для этой проблемы.
Ответы
Ответ 1
Как отмечают другие ответы, функция boxplot
ограничена построением одиночного "слоя" ящиков, а параметр groupby
действует только тогда, когда вход представляет собой Серию, и у вас есть вторая переменная, которую вы хотите для использования для хранения наблюдений в каждой коробке.
Однако вы можете выполнить то, что, как я думаю, вы надеетесь с помощью функции factorplot
, используя kind="box"
. Но сначала вам нужно "растопить" образец данных в так называемый формат long-form или "tidy", где каждый столбец является переменной, и каждая строка является наблюдением:
df_long = pd.melt(df, "b", var_name="a", value_name="c")
Тогда это очень просто построить:
sns.factorplot("a", hue="b", y="c", data=df_long, kind="box")
![enter image description here]()
Ответ 2
На самом деле это не лучше, чем ответ, который вы связали, но я думаю, что для достижения этого в морском море используется FacetGrid
, поскольку параметр groupby определен только для Series, переданных функции boxplot.
Здесь некоторый код - pd.melt
необходим, потому что (насколько я могу это сказать) отображение фасета может принимать только отдельные столбцы в качестве параметров, поэтому данные необходимо преобразовать в "длинный" формат.
g = sns.FacetGrid(pd.melt(df, id_vars='b'), col='b')
g.map(sns.boxplot, 'value', 'variable')
![faceted seaborn boxplot]()
Ответ 3
Функция групповой группировки берет серию не DataFrames, поэтому она не работает.
Как работа, вы можете сделать это:
fig, ax = plt.subplots(1,2, sharey=True)
for i, grp in enumerate(df.filter(regex="a").groupby(by=df.b)):
sns.boxplot(grp[1], ax=ax[i])
он дает: ![sns]()
Обратите внимание, что df.filter(regex="a")
эквивалентно df[['a1','a2', 'a3', 'a4']]
a1 a2 a3 a4
0 2 4 5 6
1 4 5 6 7
2 5 4 5 5
3 10 4 7 8
4 9 3 4 6
5 3 3 4 4
Надеюсь, что это поможет
Ответ 4
Вы можете использовать непосредственно boxplot
(я думаю, когда вопрос был задан, это было невозможно, но с версией seaborn
> 0.6 это так).
Как объясняет @mwaskom, вы должны "расплавить" образец кадра данных в его "длинную форму", где каждый столбец является переменной, а каждая строка - наблюдением:
df_long = pd.melt(df, "b", var_name="a", value_name="c")
Тогда вы просто заговорите:
sns.boxplot(x="a", hue="b", y="c", data=df_long)
![plot obtained with boxplot]()