显示比例的最简单方法是通过sns.histogram(..., multiple='fill')。要为年龄组和状态强制排序,创建有序类别会有所帮助。
这是一些示例代码,使用 seaborn 0.11.1 进行测试:
import matplotlib.pyplot as plt
from matplotlib.ticker import PercentFormatter
import seaborn as sns
import numpy as np
import pandas as pd
data = pd.DataFrame({'status': np.random.choice(['Success', 'Failure'], 100, p=[.7, .3]),
'age_group': np.random.choice(['18-45', '45-60', '> 60'], 100, p=[.2, .3, .5])})
data['age_group'] = pd.Categorical(data['age_group'], ordered=True, categories=['18-45', '45-60', '> 60'])
data['status'] = pd.Categorical(data['status'], ordered=True, categories=['Failure', 'Success'])
ax = sns.histplot(y='age_group', hue='status', multiple='fill', data=data)
ax.xaxis.set_major_formatter(PercentFormatter(1))
ax.set_xlabel('Percentage')
plt.show()
现在,为了创建问题的确切情节,一些 pandas 操作可能会创建以下数据框:
也许可以采取一些捷径,但这就是我试图与熊猫玩杂耍的方式(编辑@PatrickFitzGerald 的评论:使用pd.crosstab()):
# df = data.groupby(['status', 'age_group']).agg(len).reset_index(level=0) \
# .pivot(columns='status').droplevel(level=0, axis=1)
# totals = df.sum(axis=1)
# df['Success'] /= totals
# df['Failure'] /= totals
df = pd.crosstab(data['age_group'], data['status'], normalize='index')
df1 = df.melt(var_name='status', value_name='percentage', ignore_index=False).reset_index()
ax = sns.barplot(y='status', x='percentage', hue='age_group', palette='rocket', data=df1)
ax.xaxis.set_major_formatter(PercentFormatter(1))
ax.set_xlabel('Percentage')
ax.set_ylabel('')
plt.show()