如何绘制Seaborn中数据的均值和标准差?

时间:2020-07-31 11:34:56

标签: python matplotlib seaborn

我一生无法找到与此类似的问题,因此我一直在努力寻找解决办法。看来这应该很简单!

设置:我将一些X vs Y数据分组到了bin中,每个bin中都包含X和Y数据点。对于每个垃圾箱,我想绘制X的平均值与Y的平均值以及它们各自的标准差,并且最重要的是:使用Seaborn的“色盲”调色板对每个垃圾箱进行颜色编码(这是强制性的)。

我尝试过的事情:阳光下的一切。线图,散点图,猫图,绘图点。而且当所有这些都不起作用时,我尝试使用matplotlib的“ errorbars”,但是我似乎似乎无法将Seaborn的“ colorblind”调色板导出到matplotlib,因此也很失败。

一些伪代码:

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

some_data = pd.DataFrame({'X':[9,10,11,12,39,40,41,42], 'Y':[99,100,110,111,499,500,510,511], 'Bin':[1,1,1,1,2,2,2,2]})

一些尝试的结果:

sns.pointplot(x="X", y="Y", data=some_data, legend='full', hue='Bin')

pointplot Scatterplot完全拧紧了x轴刻度,所以这是我无法解决的另一个问题。

sns.lineplot(x="X", y="Y", data=some_data, legend='full', hue='Bin', err_style="band", estimator="mean", ci='sd')

lineplot 更好,但是它只是在两点之间画一条线,而不是计算均值和标准差,我认为当我指定估计量和置信区间方法时,它将这样做!!!

sns.scatterplot(x="X", y="Y", data=some_data, legend='full', hue='Bin')

散点图很好,但是它不具备 estimator 功能,所以我只是在绘制原始数据。

scatterplot

我完全不知道该怎么办。我整晚都在这。现在是凌晨4:30,过去几天晚上我几乎没睡。任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:3)

以下方法使用均值和sdevs绘制椭圆:

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
import pandas as pd
import seaborn as sns

df = pd.DataFrame({'X':[9,10,11,12,39,40,41,42], 'Y':[99,100,110,111,499,500,510,511], 'Bin':[1,1,1,1,2,2,2,2]})
means = df.groupby('Bin').mean()
sdevs = df.groupby('Bin').std()

fig, ax = plt.subplots()
colors = ['crimson', 'dodgerblue']
sns.scatterplot(x='X', y='Y', hue='Bin', palette=colors, data=df, ax=ax)
sns.scatterplot(x='X', y='Y', data=means, color='limegreen', label='means', ax=ax)

for (_, mean), (_, sdev), color in zip(means.iterrows(), sdevs.iterrows(), colors):
    ellipse = Ellipse((mean['X'], mean['Y']), width=2*sdev['X'], height=2*sdev['Y'],
                          facecolor=color, alpha=0.3)
    ax.add_patch(ellipse)
plt.show()

example plot

这是一个更详细的示例,显示椭圆为标准偏差的1、2和3倍。

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
import pandas as pd
import numpy as np
import seaborn as sns

K = 5
N = 100
df = pd.DataFrame({'X': np.random.normal(np.tile(np.random.uniform(10, 40, K), N), np.tile([3, 4, 7, 9, 10], N)),
                   'Y': np.random.normal(np.tile(np.random.uniform(90, 500, K), N), np.tile([20, 25, 8, 22, 18], N)),
                   'Bin': np.tile(np.arange(1, K + 1), N)})
means = df.groupby('Bin').mean()
sdevs = df.groupby('Bin').std()

fig, axes = plt.subplots(ncols=2, figsize=(12, 4))
colors = ['crimson', 'dodgerblue', 'limegreen', 'turquoise', 'gold']
for ax in axes:
    sns.scatterplot(x='X', y='Y', hue='Bin', palette=colors, s=5, ec='none', data=df, ax=ax)
    sns.scatterplot(x='X', y='Y', marker='o', s=50, fc='none', ec='black', label='means', data=means, ax=ax)
    if ax == axes[1]:
        for (_, mean), (_, sdev), color in zip(means.iterrows(), sdevs.iterrows(), colors):
            for sdev_mult in [1, 2, 3]:
                ellipse = Ellipse((mean['X'], mean['Y']), width=2 * sdev['X'] * sdev_mult,
                                  height=2 * sdev['Y'] * sdev_mult,
                                  facecolor=color, alpha=0.2 if sdev_mult == 1 else 0.1)
                ax.add_patch(ellipse)
plt.show()

multiples of sdev

答案 1 :(得分:1)

我承认这不是完整的答案-但我希望它对数据统计有所帮助,并为您提供有关绘图的方向。我对matplot / seaborn并不十分满意,因此,为了解决这个问题,我迅速将其绘制成图。我希望它至少可以为您提供一些指导...

平均值/标准:

import pandas as pd
from plotly.offline import iplot

x = [9, 10, 11, 12, 39, 40, 41, 42]
y = [99, 100, 110, 111, 499, 500, 510, 511]
b = [1, 1, 1, 1, 2, 2, 2, 2]

df = pd.DataFrame({'x': x, 'y': y, 'bin': b})
df = df.groupby(['bin']).agg(['mean', 'std'])
df.columns = ['_'.join(c).rstrip('_') for c in df.columns.to_list()]
df.reset_index(inplace=True)

输出:

    bin x_mean  x_std       y_mean  y_std
0   1   10.5    1.290994    105     6.377042
1   2   40.5    1.290994    505     6.377042

绘图:

data = []
for row in df.itertuples():
    data.append({'x': [row.x_mean],
                 'y': [row.y_mean],
                 'mode': 'markers',
                 'name': '{} mean'.format(row.bin),
                 'marker': {'size': 25}})
    data.append({'x': [row.x_std],
                 'y': [row.y_std],
                 'mode': 'markers',
                 'name': '{} std'.format(row.bin),
                 'marker': {'size': 25}})
iplot({'data': data})

输出:

请注意,由于标准品相同,红色/紫色点相互重叠。

enter image description here

我希望这会有所帮助...