web-dev-qa-db-ja.com

入力がDataFrameの場合のSeabornでの箱ひげ図のグループ化

pandas dataframeに複数の列をプロットし、seaborn.boxplot内でgroupbyを使用してすべてを別の列でグループ化します。 matplotlibmatplotlib: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

一方、1つの列でこれを行うと、別のSO質問 Seaborn groupby pandas Series のおかげで機能します。

sns.boxplot(df.a1, groupby=df.b)

seaborn that does not fail

したがって、1つのプロットですべての列を取得したいと思います(すべての列は同様のスケールになります)。

編集:

上記のSOの質問は編集され、この問題に対する「クリーンではない」回答が含まれていますが、誰かがこの問題についてより良いアイデアを持っているといいでしょう。

20
Arman

直接boxplotを使用できます(質問が行われたとき、それは不可能でしたが、seaborn version> 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

1
MrT77

他の回答のメモにあるように、boxplot関数はボックスプロットの単一の「レイヤー」のプロットに制限され、groupbyパラメーターは入力がシリーズで2番目の場合にのみ効果があります。観測値を各ボックスにバインドするために使用する変数。

ただし、kind="box"を使用して、factorplot関数を使用して、期待していることを実現できます。ただし、最初にサンプルデータフレームを「長い形式」または「整頓された」形式と呼ばれる形式に「溶かす」必要があります。ここで、各列は変数であり、各行は観測値です。

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

24
mwaskom

Seabornのgroupby関数はDataFrameではなくSeriesを使用するため、機能しません。

回避策として、これを行うことができます:

_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
jrjc

実際にリンクした答えよりも優れているわけではありませんが、seabornでこれを達成する方法は FacetGrid 機能を使用することだと思います。 boxplot関数に渡されます。

ここにいくつかのコードがあります-pd.meltが必要なのは、(私が知る限り)ファセットマッピングが個々の列のみをパラメーターとして受け取ることができるため、データを「長い」形式に変換する必要があるためです。

g = sns.FacetGrid(pd.melt(df, id_vars='b'), col='b')
g.map(sns.boxplot, 'value', 'variable')

faceted seaborn boxplot

4
chrisb