本文目录导读:

这是一个关于使用Python统计和分析慢跑恢复时间数据(即运动后心率、配速等指标恢复到正常水平所需的时间)的案例,这类数据通常来自运动手表或心率带,可以用来评估训练强度、疲劳程度以及有氧基础。
以下是一个完整的Python案例分析,包含数据模拟、预处理、指标计算、可视化和统计报告。
场景设定
你有一份来自智能手表的数据,包含每次慢跑的时间戳、心率(HR)、配速(Pace),我们想统计运动结束后,心率恢复到静息心率+20%以内所需的时间。
完整代码实现
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
# -------------------- 1. 模拟数据(替换为你的实际数据) --------------------
np.random.seed(42)
num_points = 1000
time_range = pd.date_range(start='2023-10-01 06:00:00', periods=num_points, freq='1s')
# 模拟跑步活动:前400秒跑步,之后恢复
heart_rate = []
pace = []
for t in range(num_points):
if t < 400: # 跑步阶段
hr_base = 140 + 20 * np.sin(t / 50) + np.random.normal(0, 3)
pace_base = 5.5 + 0.5 * np.sin(t / 30) + np.random.normal(0, 0.2)
else: # 恢复阶段
# 指数衰减恢复模拟
hr_base = 120 * np.exp(- (t - 400) / 200) + 65 + np.random.normal(0, 2)
pace_base = 7.0 + np.random.normal(0.5, 0.3) # 恢复后慢走
heart_rate.append(max(60, min(190, hr_base)))
pace.append(max(4.0, min(10.0, pace_base)))
# 构建DataFrame
df = pd.DataFrame({
'timestamp': time_range,
'heart_rate': heart_rate,
'pace_min_per_km': pace
})
# 设定静息心率为65 bpm,恢复标准为静息心率+20%(即78 bpm)
resting_hr = 65
recovery_threshold = resting_hr * 1.20 # 78
print("原始数据预览(前10行):")
print(df.head())
print(f"\n数据形状: {df.shape}")
print(f"恢复阈值: {recovery_threshold:.1f} bpm")
# -------------------- 2. 数据预处理与活动分段 --------------------
# 假设跑步开始时间就是数据开始时间,这里简单识别活动结束点
# 在实际中,你需要gps或加速度计检测运动状态,这里简化:
# 认为配速突降的时刻为跑步结束
pace_diff = df['pace_min_per_km'].diff()
# 当配速突然变慢超过0.5 min/km时,认为是运动结束点
end_of_run_idx = df[pace_diff > 0.5].index[0] if any(pace_diff > 0.5) else 400
print(f"\n检测到的跑步结束索引: {end_of_run_idx}(对应时间: {df.loc[end_of_run_idx, 'timestamp']})")
# 截取恢复期数据(从运动结束到数据末尾)
recovery_data = df.iloc[end_of_run_idx:].copy()
recovery_data['time_from_end'] = (recovery_data['timestamp'] - recovery_data['timestamp'].iloc[0]).dt.total_seconds()
# -------------------- 3. 计算恢复时间 --------------------
# 恢复时间 = 心率首次降到阈值以下的时间点
recovery_seconds = None
for i, row in recovery_data.iterrows():
if row['heart_rate'] <= recovery_threshold:
recovery_idx = i
recovery_seconds = row['time_from_end']
print(f"\n心率于 {recovery_seconds:.0f} 秒后降至阈值以下")
print(f"第{recovery_idx}行数据: 心率={row['heart_rate']:.1f}, 时间戳={row['timestamp']}")
break
if recovery_seconds is None:
print("警告:在数据范围内心率未能恢复到阈值以下")
# 更精确的计算(线性插值)
# 找到心率穿越阈值的精确时刻
from scipy.interpolate import interp1d
if recovery_seconds is not None:
# 取阈值附近的两个点进行线性插值
cross_idx = recovery_data[recovery_data['heart_rate'] <= recovery_threshold].index[0]
prev_idx = recovery_data.index.get_loc(cross_idx) - 1
prev_row = recovery_data.iloc[prev_idx]
cross_row = recovery_data.loc[cross_idx]
# 线性插值
t_prev, t_cross = prev_row['time_from_end'], cross_row['time_from_end']
hr_prev, hr_cross = prev_row['heart_rate'], cross_row['heart_rate']
if hr_prev != hr_cross:
t_interp = t_prev + (recovery_threshold - hr_prev) * (t_cross - t_prev) / (hr_cross - hr_prev)
else:
t_interp = t_prev
print(f"\n精确恢复时间(线性插值): {t_interp:.1f} 秒 ({t_interp/60:.2f} 分钟)")
# -------------------- 4. 统计指标计算 --------------------
print("\n--------------- 统计报告 ---------------")
print(f"跑步阶段最大心率: {df.iloc[:end_of_run_idx]['heart_rate'].max():.1f} bpm")
print(f"跑步阶段平均心率: {df.iloc[:end_of_run_idx]['heart_rate'].mean():.1f} bpm")
print(f"恢复阶段平均心率: {recovery_data['heart_rate'].mean():.1f} bpm")
print(f"恢复至阈值心率所需时间: {recovery_seconds:.0f} 秒 ({recovery_seconds/60:.1f} 分钟)" if recovery_seconds else "未恢复")
# 计算心率恢复率(%HRR恢复情况)
peak_hr = df.iloc[:end_of_run_idx]['heart_rate'].max()
hr_reserve = peak_hr - resting_hr
hr_60s = recovery_data[recovery_data['time_from_end'] <= 60]['heart_rate'].iloc[-1] if len(recovery_data) > 60 else recovery_data['heart_rate'].iloc[-1]
hrr_60s = (peak_hr - hr_60s) / hr_reserve * 100
print(f"1分钟心率恢复率: {hrr_60s:.1f}% HRR")
# 心率恢复斜率(前120秒的线性回归斜率)
from scipy import stats
early_recovery = recovery_data[recovery_data['time_from_end'] <= 120]
if len(early_recovery) > 2:
slope, intercept, r_value, p_value, std_err = stats.linregress(early_recovery['time_from_end'], early_recovery['heart_rate'])
print(f"前120秒心率下降斜率: {slope:.3f} bpm/秒 ({slope*60:.2f} bpm/分钟)")
# -------------------- 5. 可视化分析 --------------------
fig, axes = plt.subplots(3, 1, figsize=(12, 9), sharex=True)
# 子图1: 心率曲线
axes[0].plot(df['timestamp'], df['heart_rate'], 'b-', alpha=0.7, label='心率')
axes[0].axhline(y=recovery_threshold, color='r', linestyle='--', label=f'恢复阈值 ({recovery_threshold:.0f} bpm)')
axes[0].axvline(x=df.loc[end_of_run_idx, 'timestamp'], color='gray', linestyle=':', label='运动结束')
if recovery_seconds:
axes[0].axvline(x=df.loc[cross_idx, 'timestamp'], color='green', linestyle='-.', label=f'恢复点 ({t_interp:.0f}s)')
axes[0].set_ylabel('心率 (bpm)')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
axes[0].set_title('慢跑心率恢复曲线')
# 子图2: 配速曲线
axes[1].plot(df['timestamp'], df['pace_min_per_km'], 'g-', alpha=0.7)
axes[1].axvline(x=df.loc[end_of_run_idx, 'timestamp'], color='gray', linestyle=':')
axes[1].set_ylabel('配速 (min/km)')
axes[1].invert_yaxis() # 配速越小越快
axes[1].set_title('配速变化')
axes[1].grid(True, alpha=0.3)
# 子图3: 恢复期心率的指数拟合
axes[2].plot(recovery_data['time_from_end'], recovery_data['heart_rate'], 'b.', alpha=0.5, markersize=2)
axes[2].axhline(y=recovery_threshold, color='r', linestyle='--')
axes[2].axvline(x=t_interp if recovery_seconds else 0, color='green', linestyle='-.', label=f'恢复点 ({t_interp:.0f}s)' if recovery_seconds else '')
axes[2].set_xlabel('恢复时间 (秒)')
axes[2].set_ylabel('心率 (bpm)')
axes[2].set_title(f'恢复期心率衰减 (红色虚线: 阈值{recovery_threshold:.0f} bpm)')
axes[2].legend()
axes[2].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# -------------------- 6. 多日趋势分析(示例) --------------------
# 假设你有5天的数据
print("\n--------------- 多日趋势(模拟) ---------------")
days = 5
daily_recovery_times = [120 + np.random.normal(0, 20) for _ in range(days)] # 秒
dates = pd.date_range('2023-10-01', periods=days)
plt.figure(figsize=(8, 4))
plt.plot(dates, daily_recovery_times, 'bo-', linewidth=2)
plt.xlabel('日期')
plt.ylabel('恢复时间 (秒)')'每日恢复时间趋势')
plt.grid(True, alpha=0.3)
plt.show()
print(f"平均恢复时间: {np.mean(daily_recovery_times):.0f} 秒 ({np.mean(daily_recovery_times)/60:.1f} 分钟)")
print(f"恢复时间变异系数: {np.std(daily_recovery_times)/np.mean(daily_recovery_times)*100:.1f}%")
关键输出解读
运行上述代码后,你将得到:
- 恢复时间:精确到0.1秒的恢复时长。
- 心率恢复率 (HRR):通常1分钟下降越多,心肺功能越好(健康标准>12bpm)。
- 恢复斜率:>0.5 bpm/秒通常表示恢复良好。
- 可视化图表:直观看到心率何时穿越阈值。
如何应用到真实数据?
- 替换数据源:将
df = pd.read_csv('your_watch_data.csv')放在代码开头。 - 数据清洗:处理缺失值、异常心率(如>220或<30)、运动起止点检测(通常使用GPS速度或加速度计)。
- 个性化阈值:将
resting_hr改为你实际的静息心率。
扩展建议
- 与训练负荷关联:计算恢复时间与训练时长、平均心率的相关系数。
- 疲劳指数:如果恢复时间连续几天显著增加(比如增加20%以上),可能表示过度训练。
- 自动化报告:使用
schedule库每天定时运行,发送邮件通知或生成PDF报告。
这个案例涵盖了数据科学在运动医学中的一个典型应用——从原始时间序列中提取有临床意义的指标。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播