# 个人运动数据统计与可视化工具:从CSV到图表的全流程实现


在健康管理热潮下,越来越多人通过记录跑步、骑行等运动数据来追踪健身效果。但手动统计分析耗时费力,如何快速从CSV格式的运动记录中提取关键信息(如总距离、月度趋势)并可视化?本文将用Python结合pandas(数据处理)和matplotlib(可视化),实现一个自动化的运动数据分析工具,帮助你一键生成统计报告和直观图表。

实现思路

我们的工具需完成四大核心任务:
1. 数据读取:解析CSV文件,处理日期格式并计算运动速度;
2. 统计分析:计算总次数、总距离、平均距离、最快速度,并按月份分组统计;
3. 可视化展示:用折线图展示单次运动距离趋势,柱状图对比月度运动总量;
4. 结果输出:格式化打印统计信息,直观呈现分析结果。

代码实现(Python)

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

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

def read_data(file_path):
    """读取CSV文件并预处理数据:解析日期、计算速度、提取月份"""
    try:
        # 读取CSV,自动识别日期列(需确保日期格式正确)
        df = pd.read_csv(file_path)
        df['日期'] = pd.to_datetime(df['日期'])  # 转换为datetime类型
        # 计算速度:距离(km) ÷ 时间(分钟),单位 km/分钟
        df['速度(km/分钟)'] = df['距离(km)'] / df['时间(分钟)']
        # 提取月份名称(如“1月”“2月”),用于分组
        df['月份名称'] = df['日期'].dt.strftime('%m月').str.replace('^0', '', regex=True)
        return df
    except FileNotFoundError:
        print(f"错误:文件 {file_path} 不存在!")
        return None
    except Exception as e:
        print(f"数据处理失败:{e}")
        return None


def analyze_data(df):
    """统计分析:总次数、总距离、平均距离、最快速度、月度统计"""
    # 总运动次数
    total_count = len(df)
    # 总距离(km)
    total_distance = df['距离(km)'].sum()
    # 平均距离(km)
    avg_distance = df['距离(km)'].mean()
    # 最快速度:找到速度最大值的行
    max_speed_row = df[df['速度(km/分钟)'] == df['速度(km/分钟)'].max()]
    max_speed = max_speed_row['速度(km/分钟)'].values[0]
    max_speed_date = max_speed_row['日期'].dt.strftime('%Y-%m-%d').values[0]
    max_speed_distance = max_speed_row['距离(km)'].values[0]
    max_speed_time = max_speed_row['时间(分钟)'].values[0]
    # 月度统计:按月份分组,求和距离、计数次数
    monthly_stats = df.groupby('月份名称').agg(
        总距离=('距离(km)', 'sum'),
        运动次数=('距离(km)', 'count')
    ).reset_index()
    # 按月份数字排序(避免“10月”排在“2月”前)
    monthly_stats['month_num'] = monthly_stats['月份名称'].str.replace('月', '').astype(int)
    monthly_stats = monthly_stats.sort_values('month_num').drop('month_num', axis=1)
    return {
        'total_count': total_count,
        'total_distance': total_distance,
        'avg_distance': avg_distance,
        'max_speed': max_speed,
        'max_speed_date': max_speed_date,
        'max_speed_distance': max_speed_distance,
        'max_speed_time': max_speed_time,
        'monthly_stats': monthly_stats
    }


def visualize_data(df, stats):
    """可视化:折线图(日期-距离)、柱状图(月份-总距离)"""
    # 设置中文显示(Windows/macOS/Linux通用方案)
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 替换为系统支持的中文字体
    plt.rcParams['axes.unicode_minus'] = False    # 解决负号显示问题

    # ---- 折线图:单次运动距离趋势 ----
    plt.figure(figsize=(10, 6))
    plt.plot(
        df['日期'].dt.strftime('%Y-%m-%d'),  # x轴:格式化后的日期
        df['距离(km)'],                     # y轴:距离
        marker='o', color='blue', label='运动距离(km)'
    )
    plt.xlabel('日期')
    plt.ylabel('距离(km)')
    plt.title('每次运动距离变化趋势')
    plt.xticks(rotation=45)  # 旋转x轴标签,避免重叠
    plt.grid(linestyle='--', alpha=0.7)  # 添加网格线
    plt.legend()
    plt.tight_layout()  # 自动调整布局
    plt.savefig('distance_trend.png')    # 保存图表

    # ---- 柱状图:月度总距离对比 ----
    plt.figure(figsize=(8, 6))
    months = stats['monthly_stats']['月份名称']
    total_distances = stats['monthly_stats']['总距离']
    plt.bar(months, total_distances, color='green', width=0.6)
    plt.xlabel('月份')
    plt.ylabel('总距离(km)')
    plt.title('各月运动总距离对比')
    # 在柱子上方显示数值
    for i, v in enumerate(total_distances):
        plt.text(i, v + 0.1, f'{v:.1f}', ha='center')
    plt.tight_layout()
    plt.savefig('monthly_total_distance.png')

    # 显示所有图表
    plt.show()


def print_stats(stats):
    """打印统计信息:总次数、总距离、平均距离、最快速度、月度汇总"""
    print(f"总运动次数:{stats['total_count']}次")
    print(f"总距离:{stats['total_distance']:.1f} km")
    print(f"平均距离:{stats['avg_distance']:.2f} km")
    print(f"最快速度:{stats['max_speed']:.3f} km/分钟(对应{stats['max_speed_date']},{stats['max_speed_distance']}km/{stats['max_speed_time']}分钟)")
    print("月度总距离:")
    for _, row in stats['monthly_stats'].iterrows():
        print(f"- {row['月份名称']}:{row['总距离']:.1f} km({row['运动次数']}次)")


def main():
    # 示例CSV文件路径(可改为用户输入或文件选择)
    file_path = 'sports_data.csv'
    if not os.path.exists(file_path):
        print(f"错误:文件 {file_path} 不存在!请检查路径或替换为实际文件。")
        return
    # 读取数据
    df = read_data(file_path)
    if df is None:
        return
    # 分析数据
    stats = analyze_data(df)
    # 输出统计信息
    print_stats(stats)
    # 可视化
    visualize_data(df, stats)


if __name__ == "__main__":
    main()

代码运行与测试

  1. 依赖安装:执行 pip install pandas matplotlib 安装所需库。
  2. 数据准备:将示例CSV内容保存为 sports_data.csv(与脚本同目录):
    csv
    日期,距离(km),时间(分钟),卡路里
    2023-01-01,5.2,30,250
    2023-01-05,6.1,35,280
    2023-02-02,4.8,28,220
    2023-02-10,5.5,32,260
    2023-03-01,7.0,40,320
  3. 运行脚本:执行 python 脚本名.py,将输出统计信息并弹出两张图表(距离趋势折线图、月度总距离柱状图)。

扩展与优化建议

  • 多运动类型支持:在CSV中添加“运动类型”列,分组时按 运动类型+月份 统计,可视化时用不同颜色区分类型。
  • 异常值过滤:在 read_data 中添加逻辑,如 df = df[df['距离(km)'] > 0] 排除无效数据。
  • 用户交互:通过 tkinterPyQt 实现文件选择界面,提升工具易用性。

总结

本工具通过Python的pandas和matplotlib,实现了从CSV文件读取到数据统计、可视化的全流程。你不仅能掌握文件读写、数据分组聚合、可视化绘图等核心技能,还能将其拓展为更强大的健康管理工具。快来试试用自己的运动数据生成个性化分析报告吧!


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注