web-dev-qa-db-ja.com

seabornを使用して同じグラフに2つのバイオリン図シリーズをプロットする方法は?

バイオリン図 とseabornに関するドキュメントを見て、同じ軸上に2つの一連のバイオリン図をプロットする方法(ポイント1)とそれらが比較可能であること(ポイント2)を知りたいと思います。

ポイント1については、性別ごとにそのプロットを再現したいと思います。

fig, ax = plt.subplots()
sns.violinplot(x="day", y="total_bill", hue="smoker",
                    data=tips, split=True, ax=ax)

私は2つのサブプロットでそれを行うことができました:

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(211)
sns.violinplot(x="day", y="total_bill", hue="smoker",
               data=tips[tips.sex == "Female"], split=True, ax=ax)

ax = fig.add_subplot(212)
sns.violinplot(x="day", y="total_bill", hue="smoker",
               data=tips[tips.sex == "Male"], split=True, ax=ax)

同じmatplotlib軸に2つのバイオリン図シリーズをプロットしたいと思います。

もう一つのポイントは、バイオリン図の幅についてです。バイオリンが正常化されているかどうか、そしてどのようにしたらよいのかはっきりとわかりません。幅はプロットごとに計算されると思います。上記の例では、幅は最初のサブプロットの女性と2番目のサブプロットの男性に対して計算されます。したがって、密度を直接比較できますか?形は比較できると思いますが、例えば月曜日の男性喫煙者と女性喫煙者の量を比較することはできませんか?バイオリンの正常化を管理する方法はありますか?

6
Ger

最初のポイントとして、Seabornでこれを行う方法はありません。考えられる回避策については私のコメントを確認してください。しかし、簡単に言えば、費やした時間は価値がないと思います。

2番目の質問として、scaleおよびscale_hueパラメーターをviolinplotに設定すると、バイオリンパッチの正規化/スケーリング方法が制御されます。

scale:{“ area”、“ count”、“ width”}、optional

各バイオリンの幅をスケーリングするために使用される方法。面積の場合、各バイオリンは同じ面積になります。カウントする場合、バイオリンの幅は、そのビン内の観測数によってスケーリングされます。幅の場合、各バイオリンは同じ幅になります。

scale_hue:bool、オプション

色相変数を使用してバイオリンをネストする場合、このパラメーターは、スケーリングが主要なグループ化変数の各レベル内で計算されるか(scale_hue = True)、プロット上のすべてのバイオリンにわたって計算されるか(scale_hue = False)を決定します。

デフォルトは'area'Falseです。これらのパラメーターの変更がバイオリンにどのように影響するかを以下で確認できます。たとえば、プロットを比較して絶対数を正確に表現したい場合は、scale='count'scale_hue=Falseを設定できます。バイオリンは(データセットではなく)プロット内の最大数にスケーリングされることに注意してください。したがって、この場合、女性の最大のバイオリンは最大40の観測値を表し、男性の最大のバイオリンは最大25の観測値を表します。

fig, axes = plt.subplots(4, 2, figsize=(10, 16), sharey='row')
axes_cols = (axes.flatten()[::2], axes.flatten()[1::2])

for (sex_name, sex), axes_col in Zip(tips.groupby('sex'), axes_cols):
    sns.countplot(x="day", hue="smoker", data=sex, ax=axes_col[0])
    for scale, ax in Zip(['area', 'count', 'width'], axes_col[1:]):
        sns.violinplot(x="day", y="total_bill", hue="smoker",
            data=sex, split=True, ax=ax, scale=scale)
        ax.set_title('scale = {}'.format(scale), y=0.95)
sns.despine()
fig.tight_layout()

enter image description here

scale_hue=Falseの追加: enter image description here

5
joelostblom

Joel Ostblomが正解で述べたように、海の生まれのバイオリン図をいくつかプロットする方法はありません。私はここで彼のヒントに従った解決策を提案します。彼が答えたように、私は上部にカウントプロットも追加します。

ヒントのデータセットはよくわからないので、以下のプロットは確かに無意味です。

import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="whitegrid", font_scale=1.5)

tips = sns.load_dataset("tips")
# here you add a new column with the two categorical data you want
tips["sex_time"] = tips[["sex", "time"]].apply(lambda x: "_".join(x), axis=1)

fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(8, 10), 
                         sharex=True, gridspec_kw=dict(height_ratios=(1, 3), hspace=0))

# select the order you want:
order=["Female_Lunch", "Male_Lunch", "Female_Dinner", "Male_Dinner"]

sns.countplot(
    data=tips, x="sex_time", hue="smoker", 
    order=order,
    ax=axes[0]
)

sns.violinplot(
    x="sex_time", y="total_bill", hue="smoker", data=tips, 
    split=True, scale="count", scale_hue=False, inner="stick",
    order=order,
    ax=axes[1]
)
axes[1].set_xticklabels(["Lunch (Female)", "Lunch (Male)", "Dinner (Female)", "Dinner (Male)"])
axes[1].set_xlabel("Time (Sex)")
axes[1].legend("")

enter image description here

1
Ger