如何用Python调整柱状图时间并补全缺失月度的零值
月度频率柱状图零值月份缺失问题排查与修复
问题背景
现有一组含缺失值的YEAR、MONTH数据,需绘制1960-2020年的月度频率柱状图,但运行指定Python代码后,本该显示零值的月份(如二月)未出现在图表中,需排查代码问题并调整以正确展示所有月份的频率(含零值)。
原始数据
YEAR MONTH 1960 5 1961 7 1961 8 1961 11 1962 5 1963 6 1964 1965 7 1966 7 1966 7 1966 10 1967 4 1967 8 1968 1969 1970 8 1971 6 1971 9 1971 10 1972 7 1973 6 1973 9 1974 10 1974 10 1975 10 1976 1977 1978 9 1979 11 1980 7 1980 7 1980 8 1981 1982 10 1982 12 1983 1984 7 1985 9 1986 1987 1988 9 1988 10 1989 7 1989 10 1990 1991 7 1992 1993 6 1993 7 1993 9 1993 9 1994 1995 7 1996 8 1996 9 1997 5 1998 8 1998 9 1998 10 1999 8 1999 9 2000 9 2001 2002 1 2003 5 2003 7 2003 8 2003 9 2003 10 2004 2005 11 2006 7 2006 10 2007 9 2007 11 2007 11 2008 5 2009 5 2009 7 2009 9 2009 9 2010 10 2011 5 2011 9 2011 9 2012 8 2013 7 2014 9 2015 7 2016 2017 8 2018 10 2019 11 2020
原始代码
#Plot Frequency ISA = pd.read_csv (r'G\:data.csv', encoding="ISO-8859-1") ISA = pd.DataFrame(ISA,columns=['YEAR','MONTH','TYPE']) ISA= ISA[ISA['YEAR'].between(1960,2020, inclusive="both")] ISA['YEAR'] = pd.to_datetime(ISA['MONTH']) ISA = ISA.set_index('YEAR') ISA=ISA.drop(['MSW','TC NAME', 'KNOTS','PAR BEG', 'PAR END'],axis=1) ISA=ISA.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False) ax=ISA.groupby([ISA.index.month, 'MONTH']).count().plot(kind='bar',color='lightgray',width=1, edgecolor='darkgray') plt.xlabel('Month', color='black', fontsize=14, weight='bold') plt.ylabel('Monthly frequency' , color='black', fontsize=14, weight='bold',) plt.xticks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct','Nov','Dec'],rotation=0, fontsize=12) ax.yaxis.set_major_formatter(FormatStrFormatter('%.0f')) plt.yticks(fontsize=12) plt.ylim(0,20) plt.suptitle("Monthly Frequency",fontweight='bold',y=0.95,x=0.53) plt.title("ISA", pad=0) L=plt.legend() L.get_texts()[0].set_text('Frequency') plt.bar_label(ax.containers[0], label_type='center', fontsize=11) plt.plot() plt.tight_layout() plt.show()
问题排查
- YEAR列被错误覆盖:代码中
ISA['YEAR'] = pd.to_datetime(ISA['MONTH'])直接用月份生成的日期替换了原始年份数据,完全丢失年份信息,导致后续分组逻辑混乱。 - 过度删除缺失值:
ISA=ISA.dropna(axis=0, how='any')删除了所有含缺失值的行,包括仅MONTH缺失的年份数据,使得这些年份的所有月份都无法参与统计。 - 分组逻辑冗余且不完整:
groupby([ISA.index.month, 'MONTH'])重复按月份分组,且未确保包含1-12所有月份,无数据的月份被自动忽略。 - 刻度映射不匹配:手动设置12个月份的刻度,但实际分组结果只有有数据的月份,导致刻度与柱子对应关系错误。
修正后的代码
import pandas as pd import matplotlib.pyplot as plt from matplotlib.ticker import FormatStrFormatter # 读取数据 ISA = pd.read_csv(r'G:\data.csv', encoding="ISO-8859-1") # 仅保留需要的列 ISA = ISA[['YEAR', 'MONTH']] # 筛选1960-2020年的数据 ISA = ISA[ISA['YEAR'].between(1960, 2020, inclusive="both")] # 仅删除MONTH为空的行(无月份的行无法归类到具体月度) ISA = ISA.dropna(subset=['MONTH']) # 将MONTH转为整数类型 ISA['MONTH'] = ISA['MONTH'].astype(int) # 生成1-12月的完整月份序列 full_months = pd.DataFrame({'MONTH': range(1, 13)}) # 按MONTH分组统计频率,合并完整月份序列并填充零值 monthly_counts = ISA.groupby('MONTH').size().reset_index(name='Frequency') monthly_counts = pd.merge(full_months, monthly_counts, on='MONTH', how='left').fillna(0) # 绘制柱状图 plt.figure(figsize=(10,6)) ax = monthly_counts.plot(kind='bar', x='MONTH', y='Frequency', color='lightgray', width=1, edgecolor='darkgray', legend=False) # 设置图表样式 plt.xlabel('Month', color='black', fontsize=14, weight='bold') plt.ylabel('Monthly frequency', color='black', fontsize=14, weight='bold') # 设置x轴刻度为月份名称 plt.xticks(range(12), ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct','Nov','Dec'], rotation=0, fontsize=12) # y轴显示整数 ax.yaxis.set_major_formatter(FormatStrFormatter('%.0f')) plt.yticks(fontsize=12) plt.ylim(0,20) plt.suptitle("Monthly Frequency", fontweight='bold', y=0.95) plt.title("ISA", pad=10) # 添加柱子中心标签 plt.bar_label(ax.containers[0], label_type='center', fontsize=11) plt.tight_layout() plt.show()
代码说明
- 保留原始YEAR列,仅针对性删除MONTH为空的行,确保年份筛选逻辑正确。
- 生成1-12月的完整序列,通过
merge合并统计结果,自动填充无数据月份的频率为0,保证所有月份都出现在图表中。 - 简化分组逻辑,直接按MONTH分组统计数量,避免索引混乱。
- 移除冗余的列删除和重复分组操作,代码逻辑更清晰。
内容的提问来源于stack exchange,提问作者user2543
相关产品推荐
相关产品推荐

