为 groupby 对象绘制箱线图
Posted
技术标签:
【中文标题】为 groupby 对象绘制箱线图【英文标题】:Plotting boxplots for a groupby object 【发布时间】:2017-10-24 10:22:06 【问题描述】:我想根据一个标准为几个数据集绘制箱线图。 想象一个类似于以下示例的数据框:
df = pd.DataFrame('Group':[1,1,1,2,3,2,2,3,1,3],'M':np.random.rand(10),'F':np.random.rand(10))
df = df[['Group','M','F']]
Group M F
0 1 0.465636 0.537723
1 1 0.560537 0.727238
2 1 0.268154 0.648927
3 2 0.722644 0.115550
4 3 0.586346 0.042896
5 2 0.562881 0.369686
6 2 0.395236 0.672477
7 3 0.577949 0.358801
8 1 0.764069 0.642724
9 3 0.731076 0.302369
在这种情况下,我有三个组,所以我想为每个组制作一个箱线图,并为 M 和 F 分别制作 Y 轴上的组和 M 和 F 的列颜色编码。 This answer 非常接近我想要实现的目标,但我更喜欢更健壮的东西,适用于具有更多组数的更大数据帧。我觉得 groupby 是要走的路,但我对 groupby 对象不熟悉,我什至没有对它们进行切片。 .理想的输出如下所示:
好像几年前,有人遇到过同样的问题,但没有得到答案:(Having a boxplot as a graphical representation of the describe function of groupby
我的问题是:
-
如何实现 groupby 以将所需数据输入箱线图
如果我想控制显示的内容而不仅仅是使用默认设置(我什至不知道它们是什么,我发现文档相当模糊,那么箱线图的正确语法是什么。具体来说,我可以让盒子覆盖平均值 +/- 标准差,并将垂直线保持在中值吗?)
【问题讨论】:
您尝试了一些代码吗?你遇到了什么样的问题/错误? import matplotlib.pyplot as plt 然后 df.boxplot(['M','F'],'Group') 这将根据组为男性和女性生成 2 个单独的图。 正如你所说,这会生成单独的子图,它不会将它们绘制在一起。另外,它没有解决第 2 点。但是,谢谢,对于一个更简单的情况,很高兴知道它是多么容易完成。 请试试这个,它会给你 x 轴上的 4 个四分位数 df.boxplot(by='Group',vert=False) 很难在一个图中得到所有变量我们也在同时应用 groupby 操作,但我们可以得到多个图取决于按分组变量分组的变量的基础。 【参考方案1】:我认为您应该使用提供创建这些类型的自定义图的 Seaborn 库。在您的情况下,我首先融化了您的数据框以将其转换为正确的格式,然后创建了您选择的箱线图。
import pandas as pd
import matplotlib.pyplot as plt
Import seaborn as sns
dd=pd.melt(df,id_vars=['Group'],value_vars=['M','F'],var_name='sex')
sns.boxplot(y='Group',x='value',data=dd,orient="h",hue='sex')
情节看起来与您所需的情节相似。
【讨论】:
【参考方案2】:最后通过对this answer稍作修改找到了解决方案。它不使用 groupby 对象,因此准备数据比较繁琐,但到目前为止,它对我来说似乎是最好的解决方案。这里是:
# here I prepare the data (group them manually and then store in lists)
Groups=[1,2,3]
Columns=df.columns.tolist()[1:]
print Columns
Mgroups=[]
Fgroups=[]
for g in Groups:
dfgc = df[df['Group']==g]
m=dfgc['M'].dropna()
f=dfgc['F'].dropna()
Mgroups.append(m.tolist())
Fgroups.append(f.tolist())
fig=plt.figure()
ax = plt.axes()
def setBoxColors(bp,cl):
plt.setp(bp['boxes'], color=cl, linewidth=2.)
plt.setp(bp['whiskers'], color=cl, linewidth=2.5)
plt.setp(bp['caps'], color=cl,linewidth=2)
plt.setp(bp['medians'], color=cl, linewidth=3.5)
bpl = plt.boxplot(Mgroups, positions=np.array(xrange(len(Mgroups)))*3.0-0.4,vert=False,whis='range', sym='', widths=0.6)
bpr = plt.boxplot(Fgroups, positions=np.array(xrange(len(Fgroups)))*3.0+0.4,vert=False,whis='range', sym='', widths=0.6)
setBoxColors(bpr, '#D7191C') # colors are from http://colorbrewer2.org/
setBoxColors(bpl, '#2C7BB6')
# draw temporary red and blue lines and use them to create a legend
plt.plot([], c='#D7191C', label='F')
plt.plot([], c='#2C7BB6', label='M')
plt.legend()
plt.yticks(xrange(0, len(Groups) * 3, 3), Groups)
plt.ylim(-3, len(Groups)*3)
#plt.xlim(0, 8)
plt.show()
结果看起来很像我想要的(据我所知,该框的范围总是从第一四分位数到第三四分位数,因此无法将其设置为 +/- 标准差)。所以我有点失望,没有单线解决方案,但我很高兴这是可能的。然而,对于数百个团体来说,这还不够好......
【讨论】:
以上是关于为 groupby 对象绘制箱线图的主要内容,如果未能解决你的问题,请参考以下文章
Fig4-a ggplot2绘制箱线图叠加散点图2020-12-14