Python案例:统计慢跑恢复时间数据
下面用一个完整的案例演示如何用 Python 统计慢跑恢复时间数据,恢复时间通常指运动后心率恢复到静息水平所需的时间。

数据准备
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 模拟 15 次慢跑的恢复时间数据(单位:分钟)
data = {
'日期': pd.date_range('2024-01-01', periods=15, freq='3D'),
'跑步距离_km': [5, 5, 6, 5, 7, 5, 6, 5, 5, 8, 5, 6, 5, 5, 7],
'平均配速_min': [6.5, 6.3, 6.8, 6.2, 7.0, 6.4, 6.6, 6.1, 6.3, 7.2, 6.2, 6.5, 6.0, 6.4, 6.9],
'恢复时间_min': [12, 11, 15, 10, 18, 11, 14, 9, 10, 20, 10, 13, 8, 11, 16]
}
df = pd.DataFrame(data)
print(df)
基础统计描述
# 恢复时间的描述性统计
print("=== 恢复时间统计描述 ===")
print(df['恢复时间_min'].describe())
print(f"\n平均值: {df['恢复时间_min'].mean():.2f} 分钟")
print(f"中位数: {df['恢复时间_min'].median():.2f} 分钟")
print(f"标准差: {df['恢复时间_min'].std():.2f} 分钟")
print(f"方差: {df['恢复时间_min'].var():.2f}")
print(f"最小值: {df['恢复时间_min'].min()} 分钟")
print(f"最大值: {df['恢复时间_min'].max()} 分钟")
print(f"极差: {df['恢复时间_min'].max() - df['恢复时间_min'].min()} 分钟")
输出示例:
count 15.000000
mean 12.533333
std 3.461...
min 8.000000
25% 10.500000
50% 11.000000
75% 14.500000
max 20.000000
分组统计
# 按距离分组统计恢复时间
print("\n=== 按跑步距离统计恢复时间 ===")
group_stats = df.groupby('跑步距离_km')['恢复时间_min'].agg(
['count', 'mean', 'median', 'std', 'min', 'max']
).round(2)
print(group_stats)
# 按配速区间分组
df['配速区间'] = pd.cut(df['平均配速_min'],
bins=[6.0, 6.5, 7.0, 7.5],
labels=['快(6-6.5)', '中(6.5-7.0)', '慢(7.0-7.5)'])
print("\n=== 按配速区间统计恢复时间 ===")
print(df.groupby('配速区间')['恢复时间_min'].agg(['count', 'mean', 'std']).round(2))
相关性分析
# 分析恢复时间与其他因素的相关性
print("\n=== 相关性分析 ===")
corr = df[['跑步距离_km', '平均配速_min', '恢复时间_min']].corr()
print(corr)
# 距离与恢复时间的相关系数
corr_dist = df['跑步距离_km'].corr(df['恢复时间_min'])
print(f"\n距离 vs 恢复时间相关性: {corr_dist:.3f}")
corr_pace = df['平均配速_min'].corr(df['恢复时间_min'])
print(f"配速 vs 恢复时间相关性: {corr_pace:.3f}")
异常值检测
# 使用 IQR 方法检测异常值
Q1 = df['恢复时间_min'].quantile(0.25)
Q3 = df['恢复时间_min'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df['恢复时间_min'] < lower_bound) | (df['恢复时间_min'] > upper_bound)]
print(f"\n异常值范围: < {lower_bound:.2f} 或 > {upper_bound:.2f}")
print(f"发现异常值 {len(outliers)} 个:")
print(outliers[['日期', '跑步距离_km', '恢复时间_min']])
# 使用 Z-score 方法
df['z_score'] = np.abs((df['恢复时间_min'] - df['恢复时间_min'].mean()) / df['恢复时间_min'].std())
z_outliers = df[df['z_score'] > 2]
print(f"\nZ-score > 2 的异常点: {len(z_outliers)} 个")
可视化分析
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. 恢复时间趋势
axes[0, 0].plot(df['日期'], df['恢复时间_min'], marker='o', color='steelblue')
axes[0, 0].axhline(df['恢复时间_min'].mean(), color='red', linestyle='--', label='平均值')
axes[0, 0].set_title('慢跑恢复时间趋势')
axes[0, 0].set_xlabel('日期')
axes[0, 0].set_ylabel('恢复时间(分钟)')
axes[0, 0].legend()
axes[0, 0].tick_params(axis='x', rotation=45)
# 2. 距离 vs 恢复时间
axes[0, 1].scatter(df['跑步距离_km'], df['恢复时间_min'], color='green', s=80)
axes[0, 1].set_title('跑步距离 vs 恢复时间')
axes[0, 1].set_xlabel('距离(km)')
axes[0, 1].set_ylabel('恢复时间(分钟)')
# 3. 恢复时间分布直方图
axes[1, 0].hist(df['恢复时间_min'], bins=8, color='orange', edgecolor='black')
axes[1, 0].axvline(df['恢复时间_min'].mean(), color='red', linestyle='--', label='均值')
axes[1, 0].set_title('恢复时间分布')
axes[1, 0].set_xlabel('恢复时间(分钟)')
axes[1, 0].legend()
# 4. 各配速区间箱线图
df.boxplot(column='恢复时间_min', by='配速区间', ax=axes[1, 1])
axes[1, 1].set_title('不同配速区间的恢复时间')
axes[1, 1].set_xlabel('配速区间')
axes[1, 1].set_ylabel('恢复时间(分钟)')
plt.tight_layout()
plt.show()
综合报告函数
def analyze_recovery(df, col='恢复时间_min'):
"""生成恢复时间分析报告"""
print("=" * 50)
print(" 慢跑恢复时间分析报告")
print("=" * 50)
s = df[col]
print(f"样本数量: {len(s)}")
print(f"平均恢复时间: {s.mean():.2f} 分钟")
print(f"中位数: {s.median():.2f} 分钟")
print(f"标准差: {s.std():.2f} 分钟")
print(f"波动范围: {s.min()} - {s.max()} 分钟")
# 恢复等级评价
mean = s.mean()
if mean < 10:
level = "优秀 ✅ 恢复能力强"
elif mean < 15:
level = "良好 👍 恢复能力正常"
elif mean < 20:
level = "一般 ⚠️ 建议适当休息"
else:
level = "较差 ❌ 建议检查身体状况"
print(f"\n综合评价: {level}")
# 趋势分析
if len(s) >= 3:
recent = s.tail(3).mean()
overall = s.mean()
if recent < overall * 0.9:
trend = "📉 近期恢复速度变快"
elif recent > overall * 1.1:
trend = "📈 近期恢复速度变慢,注意休息"
else:
trend = "➡️ 恢复速度保持稳定"
print(f"趋势分析: {trend}")
print("=" * 50)
analyze_recovery(df)
输出示例:
==================================================
慢跑恢复时间分析报告
==================================================
样本数量: 15
平均恢复时间: 12.53 分钟
中位数: 11.00 分钟
标准差: 3.46 分钟
波动范围: 8 - 20 分钟
综合评价: 良好 👍 恢复能力正常
趋势分析: 📉 近期恢复速度变快
==================================================
关键统计指标说明
| 指标 | 含义 | 参考值 |
|---|---|---|
| 平均恢复时间 | 整体恢复能力 | <15 分钟良好 |
| 标准差 | 恢复稳定性 | 越小越稳定 |
| 最大恢复时间 | 最差状态 | 关注是否异常 |
| 相关系数 | 距离/配速影响 | >0.5 显著相关 |
进阶:连续恢复时间监控
# 计算滚动平均(3次慢跑窗口)
df['滚动平均'] = df['恢复时间_min'].rolling(window=3).mean()
# 检测连续上升趋势(疲劳累积)
df['变化'] = df['恢复时间_min'].diff()
df['连续上升'] = (df['变化'] > 0).astype(int)
df['连续上升次数'] = df['连续上升'].groupby(
(df['连续上升'] != df['连续上升'].shift()).cumsum()
).cumsum()
print(df[['日期', '恢复时间_min', '滚动平均', '连续上升次数']].tail(10))
本案例演示了慢跑恢复时间的完整统计流程:
- 描述统计:均值、中位数、标准差、极值
- 分组分析:按距离、配速分组对比
- 相关性分析:找出影响恢复的关键因素
- 异常检测:IQR 和 Z-score 方法
- 可视化:趋势图、散点图、箱线图
- 报告输出:自动评价恢复等级和趋势
这套方法也可用于跑步、骑行等其他运动的恢复时间监控,如果需要处理真实心率数据(如从运动手表导出的 CSV),只需将 pd.read_csv() 替换模拟数据即可。