【问题标题】:Using pandas crosstab to create a bar plot使用 pandas 交叉表创建条形图
【发布时间】:2017-09-18 13:45:47
【问题描述】:

我正在尝试使用我的数据框在 seaborn 中创建堆叠条形图。

我首先在 pandas 中生成了一个交叉表,如下所示:

pd.crosstab(df['Period'], df['Mark'])

返回:

  Mark            False  True  
Period BASELINE    583    132
       WEEK 12     721      0 
       WEEK 24     589    132 
       WEEK 4      721      0

我想使用 seaborn 创建一个堆叠的条形图以实现全等,这是我用于其余图表的内容。然而,我一直在努力做到这一点,因为我无法为交叉表编制索引。

我已经能够使用 .plot.barh(stacked=True) 在 pandas 中制作我想要的情节,但 seaborn 没有运气。有什么想法我可以做到这一点吗?

【问题讨论】:

  • 作为仅供参考,堆叠条形图并不是最佳选择,因为它们会使比较条形图值变得困难并且很容易被误解。可视化的目的是以易于理解的格式呈现数据;确保信息清晰。并排的酒吧通常是更好的选择。堆叠条可能适用于比较各组之间的总量,或比较各组中数量之间的相对差异。 Stacked Bar Graph.

标签: python pandas matplotlib seaborn bar-chart


【解决方案1】:
  • 正如您所说,您可以使用 pandas 创建堆积条形图。你想要一个“seaborn plot”的论点是无关紧要的,因为每个 seaborn plot 和每个 pandas plot 最终都只是 matplotlib 对象,因为这两个库的绘图工具只是 matplotlib 包装器。
  • 这是一个完整的解决方案(使用@andrew_reece 的回答中的数据创建)。
  • python 3.8.11pandas 1.3.2matplotlib 3.4.3seaborn 0.11.2中测试
import numpy as np 
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

n = 500
np.random.seed(365)
mark = np.random.choice([True, False], n)
periods = np.random.choice(['BASELINE', 'WEEK 12', 'WEEK 24', 'WEEK 4'], n)

df = pd.DataFrame({'mark': mark, 'period': periods})
ct = pd.crosstab(df.period, df.mark)
    
ax = ct.plot(kind='bar', stacked=True, rot=0)
ax.legend(title='mark', bbox_to_anchor=(1, 1.02), loc='upper left')

# add annotations if desired
for c in ax.containers:
    
    # set the bar label
    ax.bar_label(c, label_type='center')

【讨论】:

    【解决方案2】:
    • 创建 Seaborn doesn't like stacked bar charts 的人(但该链接有一个 hack,它使用 Seaborn + Matplotlib 来制作它们)。
    • 如果您愿意接受分组条形图而不是堆叠条形图,以下是两种方法
    • python 3.8.11pandas 1.3.2matplotlib 3.4.3seaborn 0.11.2中测试
    # first some sample data
    import numpy as np 
    import pandas as pd
    import seaborn as sns
    
    N = 1000
    np.random.seed(365)
    mark = np.random.choice([True, False], N)
    periods = np.random.choice(['BASELINE', 'WEEK 12', 'WEEK 24', 'WEEK 4'], N)
    
    df = pd.DataFrame({'mark':mark,'period':periods})
    ct = pd.crosstab(df.period, df.mark)
    
    mark      False  True
    period               
    BASELINE    124   126
    WEEK 12     102   118
    WEEK 24     118   133
    WEEK 4      140   139
    
    # now stack and reset
    stacked = ct.stack().reset_index().rename(columns={0:'value'})
    
    # plot grouped bar chart
    p = sns.barplot(x=stacked.period, y=stacked.value, hue=stacked.mark, order=['BASELINE', 'WEEK 4', 'WEEK 12', 'WEEK 24'])
    sns.move_legend(p, bbox_to_anchor=(1, 1.02), loc='upper left')
    

    • 使用pandas.crosstab 的目的是获取每组的计数,但是可以通过将原始数据帧df 传递给seaborn.countplot 来绕过这一点
    ax = sns.countplot(data=df, x='period', hue='mark', order=['BASELINE', 'WEEK 4', 'WEEK 12', 'WEEK 24'])
    sns.move_legend(ax, bbox_to_anchor=(1, 1.02), loc='upper left')
    
    for c in ax.containers:
        
        # set the bar label
        ax.bar_label(c, label_type='center')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-28
      • 1970-01-01
      • 2018-10-02
      • 1970-01-01
      • 2018-06-16
      • 2021-02-19
      相关资源
      最近更新 更多