使用 pandas 交叉表创建条形图
Using pandas crosstab to create a bar plot
我正在尝试使用我的数据框在 seaborn 中创建一个堆叠条形图。
我首先在 pandas 中生成了一个交叉表 table,如下所示:
pd.crosstab(df['Period'], df['Mark'])
哪个returns:
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 没有运气。我有什么想法可以做到这一点吗?
- 创建 Seaborn doesn't like stacked bar charts 的人(但是那个 link 有一个 hack,无论如何使用 Seaborn + Matplotlib 来制作它们)。
- 如果您愿意接受分组条形图而不是堆叠条形图,可以采用以下两种方法
- 在
python 3.8.11
、pandas 1.3.2
、matplotlib 3.4.3
、seaborn 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')
- 如您所说,您可以使用 pandas 创建堆积条形图。你想要一个“seaborn plot”的论点是无关紧要的,因为每个 seaborn plot 和每个 pandas plot 最终都只是 matplotlib 对象,因为这两个库的绘图工具只是 matplotlib 包装器。
- 这是一个完整的解决方案(使用来自@andrew_reece 的回答的数据创建)。
- 在
python 3.8.11
、pandas 1.3.2
、matplotlib 3.4.3
、seaborn 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')
我正在尝试使用我的数据框在 seaborn 中创建一个堆叠条形图。
我首先在 pandas 中生成了一个交叉表 table,如下所示:
pd.crosstab(df['Period'], df['Mark'])
哪个returns:
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 没有运气。我有什么想法可以做到这一点吗?
- 创建 Seaborn doesn't like stacked bar charts 的人(但是那个 link 有一个 hack,无论如何使用 Seaborn + Matplotlib 来制作它们)。
- 如果您愿意接受分组条形图而不是堆叠条形图,可以采用以下两种方法
- 在
python 3.8.11
、pandas 1.3.2
、matplotlib 3.4.3
、seaborn 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')
- 如您所说,您可以使用 pandas 创建堆积条形图。你想要一个“seaborn plot”的论点是无关紧要的,因为每个 seaborn plot 和每个 pandas plot 最终都只是 matplotlib 对象,因为这两个库的绘图工具只是 matplotlib 包装器。
- 这是一个完整的解决方案(使用来自@andrew_reece 的回答的数据创建)。
- 在
python 3.8.11
、pandas 1.3.2
、matplotlib 3.4.3
、seaborn 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')