Python/Pandas:按年龄分组提取no_show特定值并返回Series?
解决按年龄段统计赴约/未赴约计数与占比的问题
我来帮你搞定这个问题!你猜的没错,问题确实出在value_counts()返回的结构上——分组后的value_counts()会生成一个多级索引的Series,直接用[1]或[0]提取值会因为索引层级不对,导致拿到的结果完全不符合预期。下面是两种简单可靠的解决方法:
方法一:用unstack()转换多级索引为DataFrame
分组后的value_counts()会把age_bracket作为第一级索引,no_show的取值(0/1)作为第二级索引。我们可以用unstack()把第二级索引转成列,这样就能直接提取每个年龄段对应的赴约/未赴约计数:
# 统计每个年龄段下no_show=0和no_show=1的数量,转成DataFrame(fill_value=0避免缺失值) counts_df = df.groupby('age_bracket')['no_show'].value_counts().unstack(fill_value=0) # 提取赴约(no_show=0)和未赴约(no_show=1)的Series show_counts = counts_df[0] noshow_counts = counts_df[1] # 计算每个年龄段的总人数 age_totals = counts_df.sum(axis=1) # 计算占比 show_proportions = show_counts / age_totals noshow_proportions = noshow_counts / age_totals
方法二:用pd.crosstab()直接生成交叉统计表
如果你觉得上面的步骤有点绕,pandas的crosstab函数可以直接生成年龄段和赴约状态的交叉计数表,更直观:
import pandas as pd # 直接生成age_bracket和no_show的交叉计数表 counts_df = pd.crosstab(df['age_bracket'], df['no_show'], margins=False) # 后续提取计数、计算占比的步骤和方法一完全一致 show_counts = counts_df[0] noshow_counts = counts_df[1] age_totals = counts_df.sum(axis=1) show_proportions = show_counts / age_totals noshow_proportions = noshow_counts / age_totals
修正后的柱状图代码
现在用正确的Series来绘制柱状图,只需要稍微调整x轴标签的部分,确保对应正确的年龄段:
import numpy as np import matplotlib.pyplot as plt ind = np.arange(len(age_totals.index)) width = 0.40 # 绘制柱状图 noshow_bars = plt.bar(ind, noshow_proportions, width, color='g', alpha=.7, label='No Show') show_bars = plt.bar(ind + width, show_proportions, width, color='b', alpha=.7, label='Show') # 设置x轴标签、标题等(rotation可选,防止标签重叠) plt.xticks(ind + width/2, age_totals.index, rotation=45) plt.xlabel('Age Bracket') plt.ylabel('Proportion') plt.title('Proportion of Show/No Show by Age Bracket') plt.legend() plt.tight_layout() # 自动调整布局,防止标签被截断 plt.show()
为什么之前的代码出错?
你之前的df.groupby('age_bracket')['no_show'].value_counts()返回的是一个多级索引Series,它的索引结构是(age_bracket_value, no_show_value),比如('20-25', 1), ('20-25', 0), ('25-30', 1)...。直接用[1]提取时,Python会尝试找第一级索引为1的元素,这显然不是你想要的,所以才会得到错误的数值。
内容的提问来源于stack exchange,提问作者d_wesseling
相关产品推荐
相关产品推荐

