【问题标题】:How do I plot JUST the mean and stdev of data in seaborn?如何在 seaborn 中绘制数据的均值和标准差?
【发布时间】:2020-11-21 06:12:05
【问题描述】:

我这辈子都找不到与此类似的问题,我一直在努力弄清楚如何做到这一点。看来应该是一件很简单的事情!

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

我尝试过的:阳光下的一切。线图、散点图、猫图、绘图点。当这些都不起作用时,我尝试使用 matplotlib 的“错误栏”,但显然我似乎无法将 Seaborn 的“色盲”调色板导出到 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')

散点图完全搞砸了 x 轴刻度,所以这是另一个我无法解决的问题。

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

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

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

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

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

【问题讨论】:

  • 期望的结果是 2 个散点(每个 bin 的 x 和 y 的平均值),并带有 stdev 的错误栏吗?
  • 感谢您澄清这一点 - 是的,所需的输出是 4 个数据点的每个 bin 的一个平均值和标准差,所以总共 2 个点,每个点上都有误差线 [或类似的东西] 来表示标准开发者

标签: python matplotlib seaborn


【解决方案1】:

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

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()

这是一个更详细的示例,显示 1、2 和 3 倍 sdev 的椭圆。

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()

【讨论】:

  • 如果这回答了您的问题,您可以考虑accepting 的答案。
【解决方案2】:

我承认这不是完整的答案 - 但我希望它对数据统计有所帮助,并为您提供一些关于情节的方向。我对 matplot/seaborn 不太擅长,所以为了把这个交给你,我很快就用 plotly 写了这个图表。我希望它至少能为你提供一些方向......

平均值/标准:

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})

输出:

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

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

【讨论】:

    最近更新 更多