使用Pandas Agg绘制阴影误差条

3

我有以下格式的数据:

|      | Measurement 1 |      | Measurement 2 |      |
|------|---------------|------|---------------|------|
|      | Mean          | Std  | Mean          | Std  |
| Time |               |      |               |      |
| 0    | 17            | 1.10 | 21            | 1.33 |
| 1    | 16            | 1.08 | 21            | 1.34 |
| 2    | 14            | 0.87 | 21            | 1.35 |
| 3    | 11            | 0.86 | 21            | 1.33 |

我使用以下代码从这些数据中生成一个matplotlib折线图,该图显示标准偏差作为填充区域,如下所示:

def seconds_to_minutes(x, pos):
    minutes = f'{round(x/60, 0)}'
    return minutes

fig, ax = plt.subplots()
mean_temperature_over_time['Measurement 1']['mean'].plot(kind='line', yerr=mean_temperature_over_time['Measurement 1']['std'], alpha=0.15, ax=ax)
mean_temperature_over_time['Measurement 2']['mean'].plot(kind='line', yerr=mean_temperature_over_time['Measurement 2']['std'], alpha=0.15, ax=ax)

ax.set(title="A Line Graph with Shaded Error Regions", xlabel="x", ylabel="y")
formatter = FuncFormatter(seconds_to_minutes)
ax.xaxis.set_major_formatter(formatter)
ax.grid()
ax.legend(['Mean 1', 'Mean 2'])

输出:

输出图表 这种方法似乎很混乱,只有在我有大量数据时才会产生阴影效果。 从我拥有的数据框中生成带有阴影误差区域的折线图的正确方法是什么? 我已经看过 Plot yerr/xerr as shaded region rather than error bars,但无法将其适应我的情况。

1个回答

7

这个链接解决方案有什么问题吗?它看起来非常直接。

让我重新排列您的数据集,以便更容易在Pandas DataFrame中加载。

   Time  Measurement  Mean   Std
0     0            1    17  1.10
1     1            1    16  1.08
2     2            1    14  0.87
3     3            1    11  0.86
4     0            2    21  1.33
5     1            2    21  1.34
6     2            2    21  1.35
7     3            2    21  1.33


for i, m in df.groupby("Measurement"):
    ax.plot(m.Time, m.Mean)
    ax.fill_between(m.Time, m.Mean - m.Std, m.Mean + m.Std, alpha=0.35)

enter image description here

这里是使用随机生成数据的结果:

enter image description here

编辑

由于问题显然是在您特定的数据框格式上进行迭代,让我展示一下您可以如何做到这一点(我对 pandas 还很陌生,所以可能有更好的方法)。如果我正确理解了您的截图,您应该有类似以下的内容:

Measurement    1          2      
            Mean   Std Mean   Std
Time                             
0             17  1.10   21  1.33
1             16  1.08   21  1.34
2             14  0.87   21  1.35
3             11  0.86   21  1.33

df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 4 entries, 0 to 3
Data columns (total 4 columns):
(1, Mean)    4 non-null int64
(1, Std)     4 non-null float64
(2, Mean)    4 non-null int64
(2, Std)     4 non-null float64
dtypes: float64(2), int64(2)
memory usage: 160.0 bytes

df.columns
MultiIndex(levels=[[1, 2], [u'Mean', u'Std']],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
           names=[u'Measurement', None])

而且您应该能够用循环迭代它,并获得相同的绘图:

for i, m in df.groupby("Measurement"):
    ax.plot(m["Time"], m['Mean'])
    ax.fill_between(m["Time"],
                    m['Mean'] - m['Std'],
                    m['Mean'] + m['Std'], alpha=0.35)

或者你可以使用以下格式重新堆叠它:

(df.stack("Measurement")      # stack "Measurement" columns row by row
 .reset_index()               # make "Time" a normal column, add a new index
 .sort_values("Measurement")  # group values from the same Measurement
 .reset_index(drop=True))     # drop sorted index and make a new one

我已经截取了使用.groupby.agg()方法后数据集的屏幕截图: https://i.imgur.com/JIfPYqZ.png - LarsaSolidor
1
@LarsaSolidor 你可以使用 mean_temperature_over_time.swaplevel(0,1,axis=1).stack().reset_index().sort_values("Measurement") 来获取我的格式,或者你可以使用类似于 for i, m in mean_temperature_over_time.groupby(level=0, axis=1): print(m[i].Mean) 的方式在你的数据框中进行迭代。 - filippo
1
@LarsaSolidor 更新了答案,请查看编辑。 - filippo
那个完美地运行了!你能加一些解释性的注释来描述你正在做什么吗?我有点明白它为什么有效,但我不理解得足够自信地向别人解释。谢谢你的帮助! - LarsaSolidor
1
@LarsaSolidor 更新了答案,提供了一种稍微容易理解的方法(无需手动级别寻址和交换)。使用连接的pandas函数的技巧是从第一个函数开始,查看它如何重新塑造数据框,并逐步添加所有步骤以更好地理解正在发生的事情。 - filippo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接