熊猫中两组的箱线图
Posted
技术标签:
【中文标题】熊猫中两组的箱线图【英文标题】:Boxplot by two groups in pandas 【发布时间】:2021-10-14 11:19:38 【问题描述】:我有以下数据集:
df_plots = pd.DataFrame('Group':['A','A','A','A','A','A','B','B','B','B','B','B'],
'Type':['X','X','X','Y','Y','Y','X','X','X','Y','Y','Y'],
'Value':[1,1.2,1.4,1.3,1.8,1.5,15,19,18,17,12,13])
df_plots
Group Type Value
0 A X 1.0
1 A X 1.2
2 A X 1.4
3 A Y 1.3
4 A Y 1.8
5 A Y 1.5
6 B X 15.0
7 B X 19.0
8 B X 18.0
9 B Y 17.0
10 B Y 12.0
11 B Y 13.0
我想为每个Group
创建箱线图(示例中有两个),并在每个图中按类型显示。我试过这个:
fig, axs = plt.subplots(1,2,figsize=(8,6), sharey=False)
axs = axs.flatten()
for i, g in enumerate(df_plots[['Group','Type','Value']].groupby(['Group','Type'])):
g[1].boxplot(ax=axs[i])
导致IndexError
,因为循环尝试创建 4 个图。
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-12-8e1150950024> in <module>
3
4 for i, g in enumerate(df[['Group','Type','Value']].groupby(['Group','Type'])):
----> 5 g[1].boxplot(ax=axs[i])
IndexError: index 2 is out of bounds for axis 0 with size 2
然后我尝试了这个:
fig, axs = plt.subplots(1,2,figsize=(8,6), sharey=False)
axs = axs.flatten()
for i, g in enumerate(df_plots[['Group','Type','Value']].groupby(['Group','Type'])):
g[1].boxplot(ax=axs[i], by=['Group','Type'])
但是不,我有同样的问题。预期的结果应该只有两个图,每个图的每个类型都有一个盒须。这是这个想法的草图:
请,任何帮助将不胜感激,使用此代码,我可以控制数据的某些方面,而我无法使用 seaborn。
【问题讨论】:
【参考方案1】:使用seaborn.catplot
:
import seaborn as sns
sns.catplot(data=df, kind='box', col='Group', x='Type', y='Value', hue='Type', sharey=False, height=4)
【讨论】:
你好@mozway,我很欣赏你的回答,但我更喜欢给定的代码,没有seaborn,因为我必须在循环内进行一些计算。无论如何,谢谢。 那你不能用FacetGrid
吗?它可以处理图形布局,并且仍然可以让您访问每组的原始数据。如果您真的不想这样做,请预处理您的数据并仅按“组”分组以进行绘图。
@Alexis 我必须在循环内进行一些计算 OP 中没有显示。最好将计算步骤与绘图步骤分开。【参考方案2】:
我们可以使用groupby boxplot
为每个Group
创建子图,然后用Type
分隔每个boxplot
:
fig, axes = plt.subplots(1, 2, figsize=(8, 6), sharey=False)
df_plots.groupby('Group').boxplot(by='Type', ax=axes)
plt.show()
或者不用subplots
直接通过函数调用传递参数:
axes = df_plots.groupby('Group').boxplot(by='Type', figsize=(8, 6),
layout=(1, 2), sharey=False)
plt.show()
数据和导入:
import pandas as pd
from matplotlib import pyplot as plt
df_plots = pd.DataFrame(
'Group': ['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B'],
'Type': ['X', 'X', 'X', 'Y', 'Y', 'Y', 'X', 'X', 'X', 'Y', 'Y', 'Y'],
'Value': [1, 1.2, 1.4, 1.3, 1.8, 1.5, 15, 19, 18, 17, 12, 13]
)
【讨论】:
我很惊讶by='Type'
似乎无法与df_plots.groupby('Group').plot(kind='box', by='Type', figsize=(8, 6), layout=(1, 2), sharey=False)
一起正常工作
在我的快速(并且绝不是对某些源代码的全面阅读)中,by
似乎被传递给不处理 by
的 matplotlib.pyplot.boxplot
,而groupby.boxplot
传递给DataFrame.boxplot
,它确实处理by
,并将剩余的值传递给matplotlib.pyplot.boxplot
。
您好@HenryEcker,非常感谢您的回答和时间!【参考方案3】:
作为@Prune mentioned,直接的问题是您的groupby()
返回四个组(AX、AY、BX、BY),所以首先修复索引,然后再清理几个问题:
-
将
axs[i]
更改为 axs[i//2]
以将组 0 和 1 放在 axs[0]
上,将组 2 和 3 放在 axs[1]
上。
添加positions=[i]
将箱线图并排放置,而不是堆叠放置。
在绘图后设置title
和xticklabels
(我不知道如何在主循环中执行此操作)。
for i, g in enumerate(df_plots.groupby(['Group', 'Type'])):
g[1].boxplot(ax=axs[i//2], positions=[i])
for i, ax in enumerate(axs):
ax.set_title('Group: ' + df_plots['Group'].unique()[i])
ax.set_xticklabels(['Type: X', 'Type: Y'])
请注意,里程可能因版本而异:
matplotlib.__version__ |
pd.__version__ |
|
---|---|---|
confirmed working | 3.4.2 | 1.3.1 |
confirmed not working | 3.0.1 | 1.2.4 |
【讨论】:
你好@tdy,我尝试了你的解决方案,但我看起来与你的图像不同(我的每边只显示 1 个箱线图)。我什至复制粘贴了你的代码,但我没有显示你有什么。我错过了什么吗? 嗯不确定。我刚刚添加了一个完整的最小示例,它给了我你预期的输出。如果那仍然没有给您相同的结果,也许是版本问题?我正在使用 matplotlib 3.4.2 和 pandas 1.3.1 那一定是问题!,我的matplotlib版本是3.0.1,pandas版本是1.2.4,我试试更新看看能不能重现你的情节。谢谢! 这就是问题所在,版本!现在已经用你的代码解决了,谢谢!【参考方案4】:直接的问题是您的groupby
操作返回四个元素(AX、AY、BX、BY),您尝试单独绘制它们。您尝试使用ax=axs[i]
...但i
运行0-3,而您的扁平结构中只有两个元素。没有axs[2]
或axs[3]
,这会引发给定的运行时异常。
您需要以一种或另一种方式解决您的引用问题。
【讨论】:
以上是关于熊猫中两组的箱线图的主要内容,如果未能解决你的问题,请参考以下文章