当输入是DataFrame时,在seaborn中分组箱图

Arm*_*man 20 matplotlib pandas seaborn

我打算在a中绘制多个列pandas dataframe,所有列都使用groupbyinside在另一列中进行分组seaborn.boxplot.这里有一个很好的答案,对于matplotlib matplotlib中的类似问题:组框图,但考虑到选项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)
Run Code Online (Sandbox Code Playgroud)

我得到的是完全忽略groupby选项的东西:

groupby失败

然而,如果我用一个专栏做这个,它的工作得益于另一个SO问题Seaborn groupby pandas系列:

sns.boxplot(df.a1, groupby=df.b)
Run Code Online (Sandbox Code Playgroud)

seaborn不会失败

所以我想在一个图中得到我的所有列(所有列都以相似的比例).

编辑:

上面的SO问题已被编辑,现在包含了一个"不干净"的问题答案,但如果有人对这个问题有更好的了解,那就太好了.

mwa*_*kom 24

正如其他答案所指出的那样,该boxplot功能仅限于绘制单个"图层"箱形图,并且该groupby参数仅在输入为系列时才有效,并且您有第二个变量要用于将观察结果插入每个框中..

但是,您可以使用该factorplot功能完成我认为您希望使用的功能kind="box".但是,您首先必须将样本数据框"融化"为所谓的长格式或"整齐"格式,其中每列都是变量,每行都是一个观察点:

df_long = pd.melt(df, "b", var_name="a", value_name="c")
Run Code Online (Sandbox Code Playgroud)

然后绘制非常简单:

sns.factorplot("a", hue="b", y="c", data=df_long, kind="box")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 这偶尔会引起赞成,但是自从0.6以来,在`sns.boxplot`中已经可以使用FWIW嵌套的箱形图. (6认同)

MrT*_*T77 11

您可以直接使用sns.boxplot轴级函数 或sns.catplotwithkind='box'图形级函数。有关更多详细信息,请参阅图形级函数与轴级函数

sns.catplot具有colrow变量,用于使用不同的变量创建子图/方面。

默认值palette由传递给 的变量类型(连续(数字)或分类)确定hue

正如@mwaskom 所解释的,您必须将melt示例数据帧转换为“长格式”,其中每列都是一个变量,每行都是一个观察值。

测试于python 3.12.0, pandas 2.1.2, matplotlib 3.8.1,seaborn 0.13.0

df_long = pd.melt(df, "b", var_name="a", value_name="c")

# display(df_long.head())
   b   a   c
0  1  a1   2
1  2  a1   4
2  1  a1   5
3  2  a1  10
4  2  a1   9
Run Code Online (Sandbox Code Playgroud)

sns.boxplot

fig, ax = plt.subplots(figsize=(5, 5))
sns.boxplot(x="a", hue="b", y="c", data=df_long, ax=ax)
ax.spines[['top', 'right']].set_visible(False)
sns.move_legend(ax, bbox_to_anchor=(1, 0.5), loc='center left', frameon=False)
Run Code Online (Sandbox Code Playgroud)

sns.catplot

sns.boxplot使用更少的代码行创建相同的绘图。

g = sns.catplot(kind='box', data=df_long, x='a', y='c', hue='b', height=5, aspect=1)
Run Code Online (Sandbox Code Playgroud)

结果图

在此输入图像描述


chr*_*isb 5

它实际上并不比您链接的答案更好,但我认为在 seaborn 中实现此目的的方法是使用该功能FacetGrid,因为 groupby 参数仅为传递给 boxplot 函数的 Series 定义。

这是一些代码 - 这pd.melt是必要的,因为(据我所知)构面映射只能将单个列作为参数,因此数据需要转换为“长”格式。

g = sns.FacetGrid(pd.melt(df, id_vars='b'), col='b')
g.map(sns.boxplot, 'value', 'variable')
Run Code Online (Sandbox Code Playgroud)

多面 Seaborn 箱线图


jrj*_*rjc 5

Seaborn 的 groupby 函数采用 Series 而不是 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])
Run Code Online (Sandbox Code Playgroud)

它给 : 网络安全

请注意,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
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助