# 个人月度消费分析工具:从CSV到可视化的一站式解决方案


在数字化理财的时代,清晰的消费分析能帮助我们洞察支出结构、优化财务规划。本文将介绍如何开发一个个人月度消费分析工具,它能读取CSV格式的消费记录,自动统计各类支出的总金额、日均支出,并通过可视化图表直观展示消费结构(饼图)和每日支出趋势(折线图)。这个工具不仅能提升个人理财效率,还能帮助开发者巩固文件处理、数据统计、可视化等核心技能。

一、实现思路分析

要完成这个工具,我们将分四步走:

1. 文件读取与预处理

使用 pandas 读取CSV文件,自动解析日期列(parse_dates),处理空值和非数值金额,确保数据格式正确。

2. 数据统计

  • 按类别统计:分组计算每类消费的总支出、消费次数,并结合日期范围计算日均支出。
  • 按日期统计:分组计算每日总支出,为折线图提供数据。

3. 可视化展示

  • 饼图:展示各消费类别占总支出的比例,自定义颜色、标签和百分比格式。
  • 折线图:展示每日总支出的变化趋势,优化x轴日期显示(如“月-日”格式)。

4. 异常处理

通过 try-except 捕获文件读取和数据处理中的错误,跳过无效行(如日期格式错误、金额为空)。

二、代码实现(Python)

以下是完整的代码实现,包含详细注释:

import pandas as pd
import matplotlib.pyplot as plt
import os

def read_expense_data(file_path):
    """读取并预处理CSV格式的消费数据"""
    try:
        # 读取CSV,自动解析日期列,处理空值
        df = pd.read_csv(
            file_path, 
            parse_dates=['日期'],  # 自动识别日期格式
            na_values=['nan', 'NaN', '']  # 标记空值
        )
        # 过滤金额为空或非数值的行
        df = df.dropna(subset=['金额'])  # 移除金额为空的行
        df['金额'] = df['金额'].astype(float)  # 转换金额为浮点数
        df = df.sort_values(by='日期')  # 按日期排序
        return df
    except Exception as e:
        print(f"文件读取/处理出错:{e}")
        return None


def analyze_by_category(df):
    """按消费类别统计:总支出、消费次数、日均支出"""
    # 按类别分组,聚合计算总支出和消费次数
    category_stats = df.groupby('类别').agg(
        总支出=('金额', 'sum'),
        消费次数=('金额', 'count')
    ).reset_index()  # 重置索引,使类别作为列

    # 计算日期范围的天数(包含首尾两天)
    min_date = df['日期'].min()
    max_date = df['日期'].max()
    days = (max_date - min_date).days + 1  # 总天数 = 结束日-开始日 + 1

    # 计算日均支出(总支出 ÷ 总天数)
    category_stats['日均支出'] = category_stats['总支出'] / days

    return category_stats, min_date, max_date, days


def analyze_by_day(df):
    """按日期统计每日总支出"""
    daily_stats = df.groupby('日期').agg(
        每日总支出=('金额', 'sum')
    ).reset_index()
    return daily_stats


def plot_category_pie(category_stats, output_path='category_pie.png'):
    """绘制消费类别占比饼图"""
    # 设置中文字体,避免乱码
    plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]

    # 提取数据
    categories = category_stats['类别'].tolist()
    totals = category_stats['总支出'].tolist()
    total_expense = sum(totals)  # 总支出(用于百分比计算)

    # 绘制饼图
    fig, ax = plt.subplots(figsize=(8, 6))
    wedges, texts, autotexts = ax.pie(
        totals, 
        labels=categories, 
        autopct='%1.2f%%',  # 百分比格式(保留2位小数)
        startangle=90,      # 起始角度(使饼图顶部为第一个类别)
        colors=['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']  # 自定义颜色
    )

    # 美化文本(标签和百分比)
    for text in texts + autotexts:
        text.set_fontsize(12)
    ax.set_title('消费类别占比', fontsize=16)
    ax.axis('equal')  # 保证饼图为圆形
    plt.tight_layout()  # 自动调整布局
    plt.savefig(output_path)  # 保存图表
    plt.close()
    print(f"饼图已保存至:{output_path}")


def plot_daily_trend(daily_stats, output_path='daily_trend.png'):
    """绘制每日消费趋势折线图"""
    plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]

    # 提取日期(格式化为“月-日”)和每日总支出
    dates = daily_stats['日期'].dt.strftime('%m-%d')  # 转换为字符串格式
    daily_totals = daily_stats['每日总支出'].tolist()

    # 绘制折线图
    fig, ax = plt.subplots(figsize=(10, 6))
    ax.plot(
        dates, 
        daily_totals, 
        marker='o',  # 数据点标记
        linestyle='-',  # 折线样式
        color='#66b3ff'  # 折线颜色
    )

    # 设置图表标签与标题
    ax.set_xlabel('日期', fontsize=12)
    ax.set_ylabel('总支出(元)', fontsize=12)
    ax.set_title('每日消费趋势', fontsize=16)
    plt.xticks(rotation=45, ha='right')  # 旋转x轴标签,避免重叠
    plt.tight_layout()
    plt.savefig(output_path)
    plt.close()
    print(f"折线图已保存至:{output_path}")


def main():
    """主函数:整合数据读取、统计、可视化流程"""
    # 输入文件路径
    file_path = input("请输入CSV消费记录文件路径(如expenses.csv):")
    if not os.path.exists(file_path):
        print(f"错误:文件不存在 → {file_path}")
        return

    # 1. 读取数据
    df = read_expense_data(file_path)
    if df is None or df.empty:
        print("数据为空或读取失败,程序终止。")
        return

    # 2. 按类别统计
    category_stats, min_date, max_date, days = analyze_by_category(df)
    # 3. 按日期统计
    daily_stats = analyze_by_day(df)
    # 4. 计算总支出
    total_expense = category_stats['总支出'].sum()

    # 打印统计结果
    print(f"\n===== 消费统计({min_date.strftime('%Y-%m-%d')} ~ {max_date.strftime('%Y-%m-%d')}) =====")
    for _, row in category_stats.iterrows():
        print(f"- {row['类别']}:总支出 {row['总支出']:.2f} 元,日均 {row['日均支出']:.2f} 元(共{days}天,消费{row['消费次数']}次)")
    print(f"总支出:{total_expense:.2f} 元,日均 {total_expense/days:.2f} 元\n")

    # 5. 可视化
    plot_category_pie(category_stats)
    plot_daily_trend(daily_stats)
    print("分析完成!")


if __name__ == "__main__":
    main()

三、代码运行与测试

1. 准备CSV文件

创建 expenses.csv,内容如下(示例数据):

日期,类别,金额
2023-10-01,餐饮,50.0
2023-10-01,购物,100.0
2023-10-02,交通,10.0
2023-10-02,餐饮,30.0
2023-10-03,购物,50.0

2. 安装依赖

确保已安装 pandasmatplotlib

pip install pandas matplotlib

3. 运行程序

执行脚本后,输入CSV文件路径(如 expenses.csv),程序会自动输出统计结果并生成两张图表(category_pie.pngdaily_trend.png)。

四、扩展与优化方向

  • 多文件合并:支持读取多个CSV文件,合并后分析更长周期的消费数据。
  • 交互界面:使用 StreamlitTkinter 开发图形界面,提升用户体验。
  • 自动导入:对接银行/支付平台API,自动拉取消费数据,减少手动录入成本。
  • 高级分析:添加支出预警(如超预算提醒)、消费模式识别(如周期性支出分析)。

总结

通过这个项目,我们实践了数据处理→统计分析→可视化的完整流程,掌握了:
pandas 高效处理CSV、日期解析、分组统计的技巧。
matplotlib 绘制专业可视化图表的方法(饼图、折线图)。
– 异常处理与鲁棒性设计,确保工具在复杂场景下稳定运行。

这个工具不仅能帮助个人管理财务,更能作为开发者巩固核心技能的实践项目。如果你有更多需求,不妨基于此代码进行扩展,让它更贴合你的理财习惯!