如何用for循环构建按年月统计datetime的嵌套字典?是否预定义结构?
最佳实现方案:按年/月统计事件并生成嵌套字典
结论:不需要预先硬编码字典结构
硬编码结构不仅冗余,还会限制扩展性(比如后续新增年份时需要修改代码),动态构建嵌套字典是更优方案,能自动适配数据中的年份和月份,同时按需补全缺失月份的0值。
1. 动态构建嵌套统计字典
假设你已有包含(事件名称, datetime对象)的数据集,用collections.defaultdict可以轻松实现分层统计:
from collections import defaultdict from datetime import datetime # 示例数据集:替换成你的实际数据 events_data = [ ("登录事件", datetime(2021, 1, 5)), ("登录事件", datetime(2021, 1, 12)), ("登录事件", datetime(2021, 2, 3)), ("支付事件", datetime(2022, 3, 10)), # 更多数据... ] # 初始化三层嵌套字典:事件名 → 年份 → 月份(两位格式)→ 计数 event_stats = defaultdict(lambda: defaultdict(lambda: defaultdict(int))) for event_name, dt in events_data: year = dt.year month = f"{dt.month:02d}" # 统一转成"01""02"格式 event_stats[event_name][year][month] += 1 # (可选)转成普通字典,避免defaultdict的特殊行为 event_stats_dict = { event: { year: dict(months) for year, months in year_data.items() } for event, year_data in event_stats.items() }
2. 补全年份的所有月份(可选)
如果要求每个年份必须包含1-12月(即使该月无事件,计数为0),可以在统计后补全:
# 遍历每个事件的年份数据,补全12个月 for event_year_data in event_stats_dict.values(): for year in event_year_data.keys(): for month in [f"{m:02d}" for m in range(1, 13)]: if month not in event_year_data[year]: event_year_data[year][month] = 0
3. 写入CSV文件
推荐采用长格式CSV(每行对应一个「事件-年份-月份」的计数),这种结构更适合后续绘图工具处理:
import csv with open("event_monthly_stats.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) # 写入表头 writer.writerow(["事件名称", "年份", "月份", "事件数量"]) # 遍历嵌套字典写入数据 for event_name, year_data in event_stats_dict.items(): for year, month_data in year_data.items(): for month, count in month_data.items(): writer.writerow([event_name, year, month, count])
4. 绘图实现建议
用pandas读取CSV后,搭配matplotlib或seaborn可以快速生成可视化图表:
import pandas as pd import matplotlib.pyplot as plt # 读取CSV数据 df = pd.read_csv("event_monthly_stats.csv") # 生成「年月」列,方便横轴展示 df["年月"] = df["年份"].astype(str) + "-" + df["月份"] # 按事件分组绘制柱状图 for event_name, group in df.groupby("事件名称"): plt.figure(figsize=(12, 6)) plt.bar(group["年月"], group["事件数量"], color="#4287f5") plt.title(f"{event_name} 月度事件数量统计") plt.xlabel("年月") plt.ylabel("事件数量") plt.xticks(rotation=45) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者mrin9san
相关产品推荐
相关产品推荐

