【问题标题】:How can I sort a boxplot in pandas by the median values?如何按中值对熊猫中的箱线图进行排序?
【发布时间】:2014-03-21 16:20:41
【问题描述】:

我想按类别XY 在数据框df 中绘制列Z 的箱线图。如何按中位数对箱线图进行降序排序?

import pandas as pd
import random
n = 100
# this is probably a strange way to generate random data; please feel free to correct it
df = pd.DataFrame({"X": [random.choice(["A","B","C"]) for i in range(n)], 
                   "Y": [random.choice(["a","b","c"]) for i in range(n)],
                   "Z": [random.gauss(0,1) for i in range(n)]})
df.boxplot(column="Z", by=["X", "Y"])

请注意,this question 非常相似,但它们使用不同的数据结构。我对 pandas 比较陌生(并且一般只做过一些关于 python 的教程),所以我不知道如何使我的数据与那里发布的答案一起工作。这可能更像是一个重塑而不是一个绘图问题。也许有使用groupby的解决方案?

【问题讨论】:

    标签: python pandas boxplot


    【解决方案1】:

    您可以使用How to sort a boxplot by the median values in pandas 中的答案,但首先您需要对数据进行分组并创建一个新的数据框:

    import pandas as pd
    import random
    import matplotlib.pyplot as plt
    
    n = 100
    # this is probably a strange way to generate random data; please feel free to correct it
    df = pd.DataFrame({"X": [random.choice(["A","B","C"]) for i in range(n)], 
                       "Y": [random.choice(["a","b","c"]) for i in range(n)],
                       "Z": [random.gauss(0,1) for i in range(n)]})
    grouped = df.groupby(["X", "Y"])
    
    df2 = pd.DataFrame({col:vals['Z'] for col,vals in grouped})
    
    meds = df2.median()
    meds.sort_values(ascending=False, inplace=True)
    df2 = df2[meds.index]
    df2.boxplot()
    
    plt.show()
    

    【讨论】:

    • 我必须更改:meds.sort(ascending=False)meds.sort_values(ascending=False, inplace=True) 才能完成这项工作(Pandas 0.20.1、Python 3.6.1、Windows 8)。
    • @StephenMcAteer 感谢您的提示。我没有使用最新版本的 Pandas,因此请随时编辑答案并为未来用户添加您的答案版本。
    • 当中位数相同时,有没有办法进行备份排序?例如,如果两个中位数相同,则按其中一个四分位数排序。
    【解决方案2】:

    在函数形式中类似于 answer 以提高可移植性

    import pandas as pd
    
    def boxplot_sorted(df, by, column):
      df2 = pd.DataFrame({col:vals[column] for col, vals in df.groupby(by)})
      meds = df2.median().sort_values()
      df2[meds.index].boxplot(rot=90)
    
    boxplot_sorted(df, by=["X", "Y"], column="Z")
    

    【讨论】:

      【解决方案3】:

      回答标题中的问题,而不涉及绘制两个分类变量的所有组合的额外细节:

      n = 100
      df = pd.DataFrame({"Category": [np.random.choice(["A","B","C","D"]) for i in range(n)],      
                         "Variable": [np.random.normal(0, 10) for i in range(n)]})
      
      grouped = df.loc[:,['Category', 'Variable']] \
          .groupby(['Category']) \
          .median() \
          .sort_values(by='Variable')
      
      sns.boxplot(x=df.Category, y=df.Variable, order=grouped.index)
      
      

      我添加了这个解决方案,因为很难将接受的答案减少到单个变量,我相信人们正在寻找一种方法来做到这一点。我自己多次来这个问题寻找这样的答案。

      【讨论】:

      • 与您的最小示例有一些不一致(第一个 'Category 后缺少 ',在分组和绘图。但它背后的整体想法对我的 seaborn 驱动的应用程序很有用。
      • @ChristianKarcher 感谢您指出这些事情。这就是我不复制和粘贴的结果。
      【解决方案4】:

      我遵循了公认的答案,但是当我想覆盖使用另一个 y 轴(即ax.twinx())的第二个图时遇到了麻烦。问题是第二个图的 x 轴覆盖了排序顺序。

      我最终只使用seaborn 完成了以下操作。这类似于@rocksNwaves 的答案,但我是用问题引入的术语来写的。 只需三步:

      1. 如果您不介意创建一个组合“X”和“Y”的列,那么使用 seaborn 会让事情变得更容易:

        df["XY"] = df["X"] + df["Y"]
        

        当然,您可以按照自己的方式组合这两列。

      2. 按XY排序,得到排序后的索引

        grouped = df.groupby(["XY"])
        order = grouped.median()["Z"].sort_values().index
        
      3. 使用 seaborn 绘图

        sns.boxplot(x="XY", y="Z", data=df, order=order)
        

        请注意,您可以将 order 视为指定 x 轴上标签的顺序。

      一个完整的程序:

      import pandas as pd
      import random
      import seaborn as sns
      import matplotlib.pyplot as plt
      n = 100
      # this is probably a strange way to generate random data; please feel free to correct it
      df = pd.DataFrame({"X": [random.choice(["A","B","C"]) for i in range(n)],
                         "Y": [random.choice(["a","b","c"]) for i in range(n)],
                         "Z": [random.gauss(0,1) for i in range(n)]})
      
      df["XY"] = df["X"] + df["Y"]
      grouped = df.groupby(["XY"])
      order = grouped.median()["Z"].sort_values().index
      sns.boxplot(x="XY", y="Z", data=df, order=order, palette="light:#5A9")
      plt.show()
      

      df 看起来像

          X  Y         Z
      0   A  a  0.894873
      1   C  a -0.568682
      2   C  b  0.985260
      3   B  c  2.056287
      ...
      

      剧情是这样的

      【讨论】:

        猜你喜欢
        • 2013-10-28
        • 2023-03-09
        • 1970-01-01
        • 2011-04-15
        • 2021-10-10
        • 1970-01-01
        • 2021-03-19
        • 1970-01-01
        • 2016-03-24
        相关资源
        最近更新 更多