当前位置: 首页 > news >正文

Python 实战:骑行数据可视化分析(Pandas+Matplotlib)

文章目录

    • 项目概述:
    • 技术栈
  • 代码实现
      • 从fit文件中获取数据:
      • 导入必要的库
      • 使用matplotlib的rcParams进行全局配置
      • 读取文件、将时间转换为datetime类型
      • 查看基本数据信息
      • 创建画布、子图和总标题
      • 绘制折线图
      • 绘制散点图
      • 显示、保存图片
    • 可视化最终效果
    • 加载数据的完整代码
    • 数据可视化的完整代码
    • 常见问题与注意事项
    • 总结与拓展

项目概述:

本文从零开始,讲解如何解析骑行设备导出的 FIT 文件,并使用 Python(fitparse、pandas、matplotlib)对骑行数据进行清洗、分析与可视化。通过生成海拔、速度、卡路里等多维度图表,帮助骑手直观了解运动表现,从而科学地调整训练策略。文章提供了完整的可运行代码,适合运动科学爱好者、数据分析初学者参考。
本文导读

技术栈

本数据分析项目使用一下Python库:

  • fitparse:用于读取保存原始数据的骑行文件
  • pandas:用于读取csv文件
  • matplotlib:用于数据可视化
pipinstallfitparse pandas matplotlib

代码实现

一、数据读取与预处理

从fit文件中获取数据:

# 读取fit文件fitfile=fitparse.FitFile("MAGENE_C506SE_2026-03-12_151516_1396807.fit")# 存储列表records=[]forrecordinfitfile.get_messages("record"):# 筛选出类型为record的数据record_data={}# 遍历record数据中的所有数据字段fordatainrecord:# 如果该字段的值不为空ifdata.valueisnotNone:# data.name: 字段名# data.value: 字段值record_data[data.name]=data.value# 添加到列表中records.append(record_data)

2.保存在csv文件中

# 转换为dataframe, 方便存储df=pd.DataFrame(records)df.to_csv('骑行数据.csv',index=False,encoding='utf-8-sig')print("骑行数据.csv文件已保存")

二、数据可视化

导入必要的库

importmatplotlib matplotlib.use('TkAgg')importmatplotlib.pyplotaspltimportpandasaspd

matplotlib.use('TkAgg'):设置matplotlib使用TkAgg后端,在Tkinter界面显示图形

使用matplotlib的rcParams进行全局配置

①设置中文字体

# 设置中文字体plt.rcParams['font.sans-serif']=['SimHei','Microsoft Yahei','DejaVu Sans']

②解决负号显示问题

# 解决负号显示问题plt.rcParams['axes.unicode_minus']=False

plt.rcParams['axes.unicode_minus']设置为False的时候,matplotlib会采取ASCII显示负号

读取文件、将时间转换为datetime类型

# 读取文件data=pd.read_csv('骑行数据.csv',encoding='utf-8-sig')# 将“时间”列转换为 datetime 类型data['时间']=pd.to_datetime(data['时间'],format='%Y/%m/%d %H:%M',errors='coerce')

errors中的参数设置为coerce,当无法显示时间时,会表示为NAT或者NaN

查看基本数据信息

print(data.head(5))print(data.info())print(data.shape)

data.head(5)查看前五行的字段和数据信息
data.info()查看数据的摘要信息
data.shape查看数据的形状(行、列)

创建画布、子图和总标题

# 创建画布和子图 - 3行2列的子图, subplots函数返回两个参数fig,axes=plt.subplots(3,2,figsize=(14,12))# 总标题plt.suptitle('骑行数据分析',fontsize=20)

figsize(14, 12)设置图形的大小,14:宽, 12: 高

绘制折线图

# 1. 海拔vs距离# 设置子图在布局中的位置 - 首行首列ax1=axes[0,0]# 绘制折线图ax1.plot(data['距离'],data['海拔'],color="blue",linewidth=1)# 设置x轴ax1.set_xlabel('距离 (km)',fontsize=9)# 设置y轴ax1.set_ylabel('海拔 (m)',fontsize=9)# 设置标题ax1.set_title('海拔-距离')# 添加网格线ax1.grid(True,alpha=0.6,linestyle='--')# 2. 速度vs距离# 设置在布局中的位置ax2=axes[0,1]# 绘制折线图ax2.plot(data['距离'],data['速度'],color="red",linewidth=1)# 设置x轴ax2.set_xlabel('距离 (km)',fontsize=9)# 设置y轴ax2.set_ylabel('速度 (km/h)',fontsize=9)# 设置标题ax2.set_title('速度-距离')# 添加网格线ax2.grid(True,alpha=0.6,linestyle='--')# 3. 卡路里vs距离ax3=axes[1,0]ax3.plot(data['距离'],data['卡路里'],color="green",linewidth=1)ax3.set_xlabel('距离 (km)',fontsize=9)ax3.set_ylabel('卡路里 (kcal)',fontsize=9)ax3.set_title('卡路里-距离')ax3.grid(True,alpha=0.6,linestyle='--')# 4. 等级vs距离ax4=axes[1,1]ax4.plot(data['距离'],data['等级'],color="black",linewidth=1)ax4.set_xlabel('距离 (km)',fontsize=9)ax4.set_ylabel('等级',fontsize=9)ax4.set_title('等级-距离')ax4.grid(True,alpha=0.6,linestyle='--')# 5. 体温vs距离ax5=axes[2,0]ax5.plot(data['距离'],data['体温'],color="purple",linewidth=1)ax5.set_xlabel('距离 (km)',fontsize=9)ax5.set_ylabel('体温 (°C)',fontsize=9)ax5.set_title('体温-距离')ax5.grid(True,alpha=0.6,linestyle='--')

axes[行, 列]子图在整个图片中的位置设置,行和列都是从0开始

ax1.plot(data['距离'], data['海拔'], color="blue", linewidth=1)
x轴数据源:data[‘距离’]
y轴数据源:data[‘海拔’]
color=“blue”: 设置线条颜色为蓝色
linewidth: 设置线条宽度

ax1.set_xlabel('距离', fontsize=9)设置x轴的标题
ax1.set_ylabel('海拔', fontsize=9)设置y轴的标题
ax1.set_title('海拔-距离')设置子图的标题

ax1.grid(True, alpha=0.6, linestyle='--')True:显示网格线 alpha:透明度 linestyle:线条样式

绘制散点图

# 6. 速度vs海拔散点图ax6=axes[2,1]# 散点图 - c:按强度等级着色sc=ax6.scatter(data['速度'],data['海拔'],c=data['等级'],cmap='coolwarm',s=20,alpha=0.6)# 设置x轴ax6.set_xlabel('速度 (km/h)',fontsize=9)# 设置y轴ax6.set_ylabel('海拔',fontsize=9)# 设置标题ax6.set_title('速度-海拔散点图')# 添加网格线ax6.grid(True,alpha=0.6,linestyle='--')

scatter(x, y, c, cmap, s, alpha)
x: x轴的数据源
y: y轴的数据源
c: 按强度等级着色
cmap:散点的颜色
s:散点的大小
alpha:透明度

显示、保存图片

# 自动调节子参数plt.tight_layout()# 保存图片, 分辨率600plt.savefig('骑行数据分析.png',dpi=600,bbox_inches="tight")# 显示图片plt.show()

dpi图片的分辨率,分辨率越高,图片的线条清晰度越高
bbox_inches="tight": 使用tight进行保存,裁剪空白部分

可视化最终效果

图表解读:

  1. 海拔-距离图:在约15km处有一个明显的爬坡(海拔上升),随后下降。

  2. 速度-距离图:对应爬坡段,速度明显下降,说明爬坡对速度影响显著;下坡段速度回升。

  3. 卡路里-距离图:卡路里消耗随距离增加呈上升趋势,符合运动生理学规律。

  4. 等级-距离图:等级(强度)波动较大,爬坡段等级升高,下坡段等级降低。

  5. 体温-距离图:体温总体平稳,但在高强度区间略有上升。

  6. 散点图:高等级(暖色)的点集中在较低海拔区域,可能是平路冲刺阶段;低海拔区域也有部分高等级点,可能与加速有关。

加载数据的完整代码

importfitparseimportpandasaspd# 读取fit文件fitfile=fitparse.FitFile("MAGENE_C506SE_2026-03-12_151516_1396807.fit")# 存储列表records=[]forrecordinfitfile.get_messages("record"):# 筛选出类型为record的数据record_data={}# 遍历record数据中的所有数据字段fordatainrecord:# 如果该字段的值不为空ifdata.valueisnotNone:# data.name: 字段名# data.value: 字段值record_data[data.name]=data.value# 添加到列表中records.append(record_data)# 转换为dataframe, 方便存储df=pd.DataFrame(records)df.to_csv('骑行数据.csv',index=False,encoding='utf-8-sig')print("骑行数据.csv文件已保存")

数据可视化的完整代码

importmatplotlib matplotlib.use('TkAgg')importmatplotlib.pyplotaspltimportpandasaspd# 设置中文字体plt.rcParams['font.sans-serif']=['SimHei','Microsoft Yahei','DejaVu Sans']# 解决负号显示问题plt.rcParams['axes.unicode_minus']=False# 读取文件data=pd.read_csv('骑行数据.csv',encoding='utf-8-sig')# 将“时间”列转换为 datetime 类型data['时间']=pd.to_datetime(data['时间'],format='%Y/%m/%d %H:%M',errors='coerce')# 查看数据基本信息 - 前5行数据、摘要信息、形状print(data.head(5))print(data.info())print(data.shape)# 创建画布和子图 - 3行2列的子图, subplots函数返回两个参数fig,axes=plt.subplots(3,2,figsize=(14,12))# 总标题plt.suptitle('骑行数据分析',fontsize=20)# 1. 海拔vs距离# 设置子图在布局中的位置 - 首行首列ax1=axes[0,0]# 绘制折线图ax1.plot(data['距离'],data['海拔'],color="blue",linewidth=1)# 设置x轴ax1.set_xlabel('距离 (km)',fontsize=9)# 设置y轴ax1.set_ylabel('海拔 (m)',fontsize=9)# 设置标题ax1.set_title('海拔-距离')# 添加网格线ax1.grid(True,alpha=0.6,linestyle='--')# 2. 速度vs距离# 设置在布局中的位置ax2=axes[0,1]# 绘制折线图ax2.plot(data['距离'],data['速度'],color="red",linewidth=1)# 设置x轴ax2.set_xlabel('距离 (km)',fontsize=9)# 设置y轴ax2.set_ylabel('速度 (km/h)',fontsize=9)# 设置标题ax2.set_title('速度-距离')# 添加网格线ax2.grid(True,alpha=0.6,linestyle='--')# 3. 卡路里vs距离ax3=axes[1,0]ax3.plot(data['距离'],data['卡路里'],color="green",linewidth=1)ax3.set_xlabel('距离 (km)',fontsize=9)ax3.set_ylabel('卡路里 (kcal)',fontsize=9)ax3.set_title('卡路里-距离')ax3.grid(True,alpha=0.6,linestyle='--')# 4. 等级vs距离ax4=axes[1,1]ax4.plot(data['距离'],data['等级'],color="black",linewidth=1)ax4.set_xlabel('距离 (km)',fontsize=9)ax4.set_ylabel('等级',fontsize=9)ax4.set_title('等级-距离')ax4.grid(True,alpha=0.6,linestyle='--')# 5. 体温vs距离ax5=axes[2,0]ax5.plot(data['距离'],data['体温'],color="purple",linewidth=1)ax5.set_xlabel('距离 (km)',fontsize=9)ax5.set_ylabel('体温 (°C)',fontsize=9)ax5.set_title('体温-距离')ax5.grid(True,alpha=0.6,linestyle='--')# 6. 速度vs海拔散点图ax6=axes[2,1]# 散点图 - c:按强度等级着色sc=ax6.scatter(data['速度'],data['海拔'],c=data['等级'],cmap='coolwarm',s=20,alpha=0.6)# 设置x轴ax6.set_xlabel('速度 (km/h)',fontsize=9)# 设置y轴ax6.set_ylabel('海拔',fontsize=9)# 设置标题ax6.set_title('速度-海拔散点图')# 添加网格线ax6.grid(True,alpha=0.6,linestyle='--')# 自动调节子参数plt.tight_layout()# 保存图片, 分辨率600plt.savefig('骑行数据分析.png',dpi=600,bbox_inches="tight")# 显示图片plt.show()

常见问题与注意事项

  • 文件路径错误
    请确保FIT文件存在于当前工作目录,或使用绝对路径。建议将文件放在与脚本相同的文件夹中。

  • 中文显示乱码
    如果图表中的中文显示为方框,说明系统中没有代码中指定的字体(如SimHei)。可以安装相应字体,或更换为系统已有的中文字体(如 ‘Arial Unicode MS’ on macOS)。

  • 时间转换失败
    如果CSV中的时间格式与代码中的 format 不匹配,errors=‘coerce’ 会将无效时间设为 NaT。请检查原始数据的时间格式,必要时调整 format 参数。

  • 图片保存为空白
    如果在 plt.show() 之后调用 plt.savefig(),可能保存空白图片。请确保 savefig 在 show 之前,或使用 plt.savefig 后不调用 show。

总结与拓展

本文从零开始,演示了如何解析FIT文件、保存为CSV,并使用Matplotlib进行多维度数据可视化。最终生成包含6个子图的骑行分析图表,帮助骑手直观了解运动表现。

http://www.jsqmd.com/news/479508/

相关文章:

  • 2026国产大模型参数全曝光!MiniMax、GLM-5吊打GPT-5.2,性价比碾压国际巨头
  • 除螨仪哪个品牌最好?家用除螨仪什么品牌的好?内行人揭秘十大公认好用的除螨仪,放心选!
  • 微服务到底要不要上?中小项目如何低成本落地
  • DCT-Net人像卡通化模型参数详解:CUDA 11.3+cuDNN 8.2环境适配要点解析
  • 立创萤辉露营灯:基于STM32F411+IP5328P+WS2812的DIY氛围灯硬件设计与软件实现
  • 震惊!这家轨道灯厂竟让服装店老板排队抢货,背后真相太意外!
  • 小区业主自治的深度剖析
  • 射频工程师岗位解析:职责、技能、发展与就业前景
  • Nanbeige 4.1-3B在MySQL数据库优化中的应用:性能调优实战
  • 智能文档处理工具:PP-DocLayoutV3版面分析模型,开箱即用支持多格式
  • 工程师级USB-C多功能Hub硬件设计指南
  • Qwen3-ForcedAligner-0.6B实操手册:多段音频连续处理与结果合并技巧
  • MedGemma能力展示:医学术语解释、指南对比、症状鉴别全测评
  • 2026川西北殡葬定制服务推荐榜含高端墓碑定制:丧葬一条龙、丧葬服务、九龙山公墓、公墓价格、公墓销售、圣水陵园公墓选择指南 - 优质品牌商家
  • 口碑好的移动阳光房零售公司
  • Audio Pixel Studio开源实践:添加WebRTC实时语音合成流式响应功能
  • HCIP-AI-EI Developer V2.5 第一章笔记
  • YOLO12与CNN对比分析:注意力机制带来的性能突破
  • 图文并茂2分钟教会你用飞书聊天就可以控制大龙虾OpenClaw
  • SMPL-X模型实战:如何用单张照片生成带表情的3D数字人(附Python代码示例)
  • GLM-4v-9b惊艳效果:1120×1120输入下准确识别微信聊天截图中的时间戳与头像框
  • 零基础玩转SiameseAOE:中文评论情感分析,10分钟上手实战
  • Qwen2.5-VL-7B-Instruct真实案例:用户上传的模糊截图→精准还原意图并生成答案
  • QOJ17245 Strange Machine
  • 鸭式布局探空火箭嵌入式制导系统设计与实现
  • 双路USB功率计设计:快充场景下的高精度电参数测量
  • 16位电压电流采集表硬件设计与Modbus RTU实现
  • Excel 学习笔记整理:常用操作、数据清洗与公式应用实战
  • 基于超级电容的机电能量转换小车设计
  • 如何用WeChatFerry打造企业级微信自动化解决方案