pandas DataFrame 多列的并排箱线图

Posted

技术标签:

【中文标题】pandas DataFrame 多列的并排箱线图【英文标题】:Side-by-side boxplot of multiple columns of a pandas DataFrame 【发布时间】:2017-08-03 07:28:49 【问题描述】:

一年的样本数据:

import pandas as pd
import numpy.random as rnd
import seaborn as sns
n = 365
df = pd.DataFrame(data = "A":rnd.randn(n), "B":rnd.randn(n)+1,
                  index=pd.date_range(start="2017-01-01", periods=n, freq="D"))

我想将这些数据并排按月分组(即每月两个框,一个用于A,一个用于B)。

对于单个列 sns.boxplot(df.index.month, df["A"]) 工作正常。但是,sns.boxplot(df.index.month, df[["A", "B"]]) 会引发错误 (ValueError: cannot copy sequence with size 2 to array axis with dimension 365)。通过索引 (pd.melt(df, id_vars=df.index, value_vars=["A", "B"], var_name="column")) 融合数据以使用 seaborn 的 hue 属性作为解决方法也不起作用 (TypeError: unhashable type: 'DatetimeIndex')。

(如果使用普通 matplotlib 更容易,解决方案不一定需要使用 seaborn。)

编辑

我找到了一种解决方法,基本上可以产生我想要的东西。但是,一旦 DataFrame 包含的变量多于我想要绘制的变量,使用起来就会有些尴尬。所以如果有更优雅/直接的方法,请分享!

df_stacked = df.stack().reset_index()
df_stacked.columns = ["date", "vars", "vals"]
df_stacked.index = df_stacked["date"]
sns.boxplot(x=df_stacked.index.month, y="vals", hue="vars", data=df_stacked)

产生:

【问题讨论】:

您能详细说明一下“但是,一旦 DataFrame 包含的变量比我想要绘制的多,使用起来就会有些尴尬?” 【参考方案1】:

这是一个使用 pandas 融化和 seaborn 的解决方案:

import pandas as pd
import numpy.random as rnd
import seaborn as sns
n = 365
df = pd.DataFrame(data = "A": rnd.randn(n),
                          "B": rnd.randn(n)+1,
                          "C": rnd.randn(n) + 10, # will not be plotted
                         ,
                  index=pd.date_range(start="2017-01-01", periods=n, freq="D"))
df['month'] = df.index.month
df_plot = df.melt(id_vars='month', value_vars=["A", "B"])
sns.boxplot(x='month', y='value', hue='variable', data=df_plot)

【讨论】:

【参考方案2】:
month_dfs = []
for group in df.groupby(df.index.month):
    month_dfs.append(group[1])

plt.figure(figsize=(30,5))
for i,month_df in enumerate(month_dfs):
    axi = plt.subplot(1, len(month_dfs), i + 1)
    month_df.plot(kind='box', subplots=False, ax = axi)
    plt.title(i+1)
    plt.ylim([-4, 4])

plt.show()

会给this

不完全是您要查找的内容,但如果您添加更多变量,则可以保持可读的 DataFrame。

您还可以使用

轻松删除轴
if i > 0:
        y_axis = axi.axes.get_yaxis()
        y_axis.set_visible(False)

plt.show()之前的循环中

【讨论】:

【参考方案3】:

使用Altair 非常简单:

alt.Chart(
    df.reset_index().melt(id_vars = ["index"], value_vars=["A", "B"]).assign(month = lambda x: x["index"].dt.month)
).mark_boxplot(
    extent='min-max'
).encode(
    alt.X('variable:N', title=''),
    alt.Y('value:Q'),
    column='month:N',
    color='variable:N'
)

上面的代码融化了 DataFrame 并添加了一个 month 列。然后 Altair 为每个按月细分的变量创建箱线图作为绘图列。

【讨论】:

【参考方案4】:

我不完全理解您的问题,但您可以使用matplotlib 看看这种方法。虽然不是最好的解决方案。

1) 通过months 将df 分成12 个DataFrame,全部堆叠在一个列表中

DFList = []
for group in df_3.groupby(df_3.index.month):
    DFList.append(group[1])

2) 在循环中一个接一个地绘制它们:

for _ in range(12):
    DFList[_].plot(kind='box', subplots=True, layout=(2,2), sharex=True, sharey=True, figsize=(7,7))

plt.show()

3) 这是前三行的快照:

您可能还想查看matplotlibadd_subplot method

【讨论】:

感谢您的回答。抱歉,如果我的主要帖子不清楚。如果你能帮助我改进它,我会很高兴。我将在一分钟内编辑我在原始帖子中找到的解决方法/解决方案,以帮助澄清我的意思。

以上是关于pandas DataFrame 多列的并排箱线图的主要内容,如果未能解决你的问题,请参考以下文章

同一图上 Pandas 数据框多列的箱线图(seaborn)

pandas 生成并排放置的条形图和箱线图

向 Pandas DataFrame 箱线图添加图例

同一图上的 Python 并排箱线图

基于 DataFrame 列名的颜色 seaborn 箱线图

一个数据点上的 Pandas 箱线图错误