1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
| print("\n=== 专业支出分析报告 ===")
from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment from openpyxl.chart import LineChart, BarChart, PieChart, Reference import matplotlib.pyplot as plt
def 生成专业支出报告(df, 文件名="月度支出分析报告.xlsx"): """生成专业的支出分析报告""" print("📊 生成专业报告...") wb = Workbook() 汇总表 = wb.active 汇总表.title = "执行汇总" 汇总表["A1"] = "月度支出分析报告" 汇总表["A1"].font = Font(size=18, bold=True, color="FFFFFF") 汇总表["A1"].fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid") 汇总表.merge_cells("A1:H1") 汇总表["A1"].alignment = Alignment(horizontal="center") 分析期间 = f"{df['日期'].min().strftime('%Y年%m月%d日')} - {df['日期'].max().strftime('%Y年%m月%d日')}" 汇总表["A3"] = f"分析期间:{分析期间}" 汇总表["A4"] = f"数据记录数:{len(df)}笔" 汇总表["A5"] = f"报告生成时间:{pd.Timestamp.now().strftime('%Y年%m月%d日 %H:%M')}" 关键指标 = [ ["关键指标", "数值", "单位", "环比变化", "健康状况"], ["总支出", f"{df['金额'].sum():,.2f}", "元", "-", "待评估"], ["平均单笔支出", f"{df['金额'].mean():.2f}", "元/笔", "-", "待评估"], ["日均支出", f"{df.groupby('日期')['金额'].sum().mean():.2f}", "元/天", "-", "待评估"], ["支出笔数", f"{len(df):,}", "笔", "-", "待评估"], ["支出类别数", f"{df['类别'].nunique()}", "类", "-", "待评估"], ["支出方式数", f"{df['方式'].nunique()}", "种", "-", "待评估"] ] 起始行 = 7 for 行号, 数据行 in enumerate(关键指标, 起始行): for 列号, 值 in enumerate(数据行, 1): 单元格 = 汇总表.cell(row=行号, column=列号, value=值) if 行号 == 起始行: 单元格.font = Font(bold=True) 单元格.fill = PatternFill(start_color="D9E2F3", end_color="D9E2F3", fill_type="solid") 分类表 = wb.create_sheet("分类支出分析") 分类表["A1"] = "分类支出分析" 分类表["A1"].font = Font(size=14, bold=True) 分类统计 = df.groupby('类别').agg({ '金额': ['count', 'sum', 'mean', 'max'], '日期': 'nunique' }).round(2) 分类统计.columns = ['支出笔数', '总支出', '平均支出', '最大支出', '支出天数'] 分类统计 = 分类统计.sort_values('总支出', ascending=False) 分类统计['占比'] = (分类统计['总支出'] / 分类统计['总支出'].sum() * 100).round(1) 表头 = ['类别', '支出笔数', '总支出', '平均支出', '最大支出', '占比', '支出天数'] for 列号, 标题 in enumerate(表头, 1): 单元格 = 分类表.cell(row=3, column=列号, value=标题) 单元格.font = Font(bold=True) 单元格.fill = PatternFill(start_color="E8F4FD", end_color="E8F4FD", fill_type="solid") for 行号, (类别, 数据) in enumerate(分类统计.iterrows(), 4): 分类表.cell(row=行号, column=1, value=类别) 分类表.cell(row=行号, column=2, value=数据['支出笔数']) 分类表.cell(row=行号, column=3, value=数据['总支出']) 分类表.cell(row=行号, column=4, value=数据['平均支出']) 分类表.cell(row=行号, column=5, value=数据['最大支出']) 分类表.cell(row=行号, column=6, value=f"{数据['占比']}%") 分类表.cell(row=行号, column=7, value=数据['支出天数']) 图表数据行 = len(分类统计) + 6 分类表.cell(row=图表数据行, column=1, value="图表数据") 分类表.cell(row=图表数据行, column=1).font = Font(bold=True) for i, (类别, 数据) in enumerate(分类统计.iterrows(), 图表数据行 + 1): 分类表.cell(row=i, column=1, value=类别) 分类表.cell(row=i, column=2, value=数据['总支出']) 饼图 = PieChart() 饼图.title = "支出分类占比" 数据 = Reference(分类表, min_col=2, min_row=图表数据行 + 1, max_row=图表数据行 + len(分类统计)) 分类 = Reference(分类表, min_col=1, min_row=图表数据行 + 1, max_row=图表数据行 + len(分类统计)) 饼图.add_data(data) 饼图.set_categories(分类) 分类表.add_chart(饼图, "I3") 时间表 = wb.create_sheet("时间趋势分析") 时间表["A1"] = "支出时间趋势分析" 时间表["A1"].font = Font(size=14, bold=True) 日支出 = df.groupby('日期')['金额'].sum().sort_index() 时间表["A3"] = "日支出明细" 时间表["A3"].font = Font(bold=True) 表头 = ['日期', '支出金额', '星期', '是否周末'] for 列号, 标题 in enumerate(表头, 1): 单元格 = 时间表.cell(row=5, column=列号, value=标题) 单元格.font = Font(bold=True) for 行号, (日期, 金额) in enumerate(日支出.items(), 6): 该日数据 = df[df['日期'] == 日期].iloc[0] 时间表.cell(row=行号, column=1, value=日期.strftime('%m-%d')) 时间表.cell(row=行号, column=2, value=金额) 时间表.cell(row=行号, column=3, value=该日数据['星期']) 时间表.cell(row=行号, column=4, value='是' if 该日数据['是否周末'] else '否') 折线图 = LineChart() 折线图.title = "日支出趋势" 折线图.style = 2 折线图.y_axis.title = '支出金额(元)' 折线图.x_axis.title = '日期' 数据 = Reference(时间表, min_col=2, min_row=6, max_row=6 + len(日支出)) 分类 = Reference(时间表, min_col=1, min_row=6, max_row=6 + len(日支出)) 折线图.add_data(data) 折线图.set_categories(分类) 时间表.add_chart(折线图, "F5") 健康表 = wb.create_sheet("消费健康度评估") 健康表["A1"] = "消费健康度评估" 健康表["A1"].font = Font(size=14, bold=True) 日消费频次 = df.groupby('日期').size() 支出集中度 = df.nlargest(int(len(df) * 0.2), '金额')['金额'].sum() / df['金额'].sum() * 100 类别多样性 = len(df['类别'].unique()) / 8 * 100 理性消费率 = (1 - len(df[df['金额'] > 300]) / len(df)) * 100 健康指标 = { '支出稳定性': max(0, 100 - (日消费频次.std() / 日消费频次.mean() * 100)), '消费多样性': min(100, 类别多样性), '理性消费率': 理性消费率, '支出分散度': max(0, 100 - 支出集中度) } 总体健康度 = sum(健康指标.values()) / len(健康指标) 健康表["A3"] = "健康指标" 健康表["A3"].font = Font(bold=True) 健康数据 = [ ["健康指标", "得分", "等级", "建议"], ["支出稳定性", f"{健康指标['支出稳定性']:.1f}", "良好" if 健康指标['支出稳定性'] >= 80 else "需改善", "保持规律消费习惯"], ["消费多样性", f"{健康指标['消费多样性']:.1f}", "优秀" if 健康指标['消费多样性'] >= 90 else "良好", "适当增加消费类别"], ["理性消费率", f"{健康指标['理性消费率']:.1f}", "优秀" if 健康指标['理性消费率'] >= 90 else "良好", "控制大额支出"], ["支出分散度", f"{健康指标['支出分散度']:.1f}", "良好" if 健康指标['支出分散度'] >= 70 else "需改善", "避免过度集中消费"] ] for 行号, 数据行 in enumerate(健康数据, 5): for 列号, 值 in enumerate(数据行, 1): 单元格 = 健康表.cell(row=行号, column=列号, value=值) if 行号 == 5: 单元格.font = Font(bold=True) 单元格.fill = PatternFill(start_color="E8F4FD", end_color="E8F4FD", fill_type="solid") 健康表.cell(row=11, column=1, value="总体健康度") 健康表.cell(row=11, column=1).font = Font(bold=True) 健康表.cell(row=12, column=1, value=f"{总体健康度:.1f}分") 健康表.cell(row=12, column=2, value="优秀" if 总体健康度 >= 85 else "良好" if 总体健康度 >= 70 else "需改善") for 列 in ["A", "B", "C", "D"]: 健康表.column_dimensions[列].width = 20 wb.save(文件名) print(f"✅ 专业支出报告已生成:{文件名}") return 文件名
专业报告文件 = 生成专业支出报告(df)
print("\n📊 生成数据可视化图表...")
plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False
plt.figure(figsize=(10, 8)) 分类统计 = df.groupby('类别')['金额'].sum().sort_values(ascending=False) plt.pie(分类统计.values, labels=分类统计.index, autopct='%1.1f%%', startangle=90) plt.title('月度支出分类分布', fontsize=16) plt.axis('equal') plt.savefig('支出分类分布.png', dpi=300, bbox_inches='tight') plt.close()
plt.figure(figsize=(14, 6)) 日支出 = df.groupby('日期')['金额'].sum() plt.plot(日支出.index, 日支出.values, marker='o', linewidth=2, markersize=4) plt.title('日支出趋势图', fontsize=16) plt.xlabel('日期', fontsize=12) plt.ylabel('支出金额(元)', fontsize=12) plt.grid(True, alpha=0.3) plt.xticks(rotation=45) plt.tight_layout() plt.savefig('日支出趋势.png', dpi=300, bbox_inches='tight') plt.close()
plt.figure(figsize=(12, 6)) 分类数据 = df.groupby('类别').agg({ '金额': 'sum', '日期': 'count' }) 分类数据.columns = ['总支出', '支出笔数']
fig, ax1 = plt.subplots(figsize=(12, 6)) ax2 = ax1.twinx()
bars = ax1.bar(分类数据.index, 分类数据['总支出'], color='skyblue', alpha=0.7, label='总支出') ax1.set_xlabel('支出类别', fontsize=12) ax1.set_ylabel('总支出(元)', fontsize=12, color='blue') ax1.tick_params(axis='y', labelcolor='blue')
line = ax2.plot(分类数据.index, 分类_data['支出笔数'], color='red', marker='o', linewidth=2, label='支出笔数') ax2.set_ylabel('支出笔数', fontsize=12, color='red') ax2.tick_params(axis='y', labelcolor='red')
plt.title('各类别支出对比', fontsize=16) plt.xticks(rotation=45) plt.tight_layout() plt.savefig('类别支出对比.png', dpi=300, bbox_inches='tight') plt.close()
print("✅ 所有可视化图表已生成!")
|