为 groupby 对象绘制箱线图
Plotting boxplots for a groupby object
我想根据一个标准绘制多个数据集的箱线图。
想象一个类似于以下示例的数据框:
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 以将所需数据输入箱线图
- 如果我想控制显示的内容而不只是使用默认设置(我什至不知道它们是什么,我发现文档相当含糊),箱形图的正确语法是什么。要成为具体的,我可以让方框覆盖平均值+/-标准偏差,并使垂直线保持在中值吗?)
我认为你应该使用 Seaborn 库来创建这些类型的自定义 plots.In 你的情况我首先融化了你的数据框以将其转换为正确的格式然后创建了你选择的箱线图。
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')
情节看起来与您需要的情节相似。
最后通过稍微修改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()
结果看起来很像我想要的(据我所知,框的范围总是从第一到第三个四分位数,所以不可能将它设置为 +/- 标准差)。所以我有点失望没有单线解决方案,但我很高兴这是可能的。然而,对于数百个小组来说,这还不够好...
我想根据一个标准绘制多个数据集的箱线图。 想象一个类似于以下示例的数据框:
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 以将所需数据输入箱线图
- 如果我想控制显示的内容而不只是使用默认设置(我什至不知道它们是什么,我发现文档相当含糊),箱形图的正确语法是什么。要成为具体的,我可以让方框覆盖平均值+/-标准偏差,并使垂直线保持在中值吗?)
我认为你应该使用 Seaborn 库来创建这些类型的自定义 plots.In 你的情况我首先融化了你的数据框以将其转换为正确的格式然后创建了你选择的箱线图。
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')
情节看起来与您需要的情节相似。
最后通过稍微修改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()
结果看起来很像我想要的(据我所知,框的范围总是从第一到第三个四分位数,所以不可能将它设置为 +/- 标准差)。所以我有点失望没有单线解决方案,但我很高兴这是可能的。然而,对于数百个小组来说,这还不够好...