【实战】Python数据分析+机器学习:睡眠质量关联性研究完整流程

基于pandas、matplotlib、scikit-learn的完整数据分析案例,从数据预处理到模型部署,一篇搞定!

📊 前言

睡眠质量对健康和生活质量至关重要。在数字化时代,如何利用数据科学方法分析睡眠影响因素,成为热门研究话题。

本文将带你完成一个完整的数据分析项目,涵盖:

  • ✅ 数据加载与预处理
  • ✅ 数据可视化
  • ✅ 特征工程
  • ✅ 机器学习建模
  • ✅ 结果分析与文档生成

🎯 项目概述

数据集介绍

我们使用包含400名受试者的睡眠数据集,包含13个特征:

特征分类 具体特征 数据类型
基本信息 性别、年龄、职业 分类/数值
睡眠数据 睡眠时长、睡眠质量 数值
身体状况 身体活动、压力、BMI、血压、心率 数值/分类
生活方式 每日步数 数值
睡眠障碍 睡眠障碍类型 分类

技术栈

pandas          # 数据处理
matplotlib       # 数据可视化
scikit-learn    # 机器学习

🔧 第一步:环境配置与中文字体设置

常见问题:matplotlib中文显示乱码

Windows环境下,matplotlib默认不支持中文显示,这是新手最常遇到的问题

解决方案

import matplotlib.pyplot as plt

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.size'] = 10
plt.style.use('default')

字体优先级

  1. Microsoft YaHei(微软雅黑)- 推荐
  2. SimHei(黑体)- 备选

测试字体是否可用

创建测试程序验证字体配置:

import matplotlib.pyplot as plt

plt.figure(figsize=(8, 6))
plt.text(0.5, 0.5, '汉字测试\n数值: 123.45', 
         ha='center', va='center', fontsize=20)
plt.title('中文字体测试')
plt.show()

经验提示:在每个图表创建前重新设置字体参数,避免设置丢失。


📥 第二步:数据加载与探索

加载数据

import pandas as pd

# 加载CSV数据
df = pd.read_csv('sleep.csv')

print(f"数据集: {df.shape[0]}条记录, {df.shape[1]}个特征")
print("\n数据概览:")
print(df.head())

数据探索

# 查看数据类型
print(df.info())

# 查看统计信息
print(df.describe())

# 检查缺失值
print(df.isnull().sum())

输出结果

数据集: 400条记录, 13个特征
数据完整性: 100% (无缺失值)

🛠️ 第三步:特征工程

3.1 血压数据分离

血压数据格式为"收缩压/舒张压",需要拆分:

# 分离血压字段
df['systolic_bp'] = df['blood_pressure'].apply(
    lambda x: int(x.split('/')[0])
)
df['diastolic_bp'] = df['blood_pressure'].apply(
    lambda x: int(x.split('/')[1])
)

代码解释

  • apply(): 对每行数据应用函数
  • split('/'): 按’/'分割字符串
  • int(): 转换为整数类型

3.2 分类变量编码

机器学习模型需要数值型输入:

from sklearn.preprocessing import LabelEncoder

le_dict = {}
categorical_cols = ['gender', 'occupation', 'bmi_category', 'sleep_disorder']

for col in categorical_cols:
    le = LabelEncoder()
    df[f'{col}_encoded'] = le.fit_transform(df[col])
    le_dict[col] = le  # 保存编码器便于后续解码

编码结果示例

gender: Male -> 1, Female -> 0
occupation: Doctor -> 0, Nurse -> 1, ...

3.3 创建二分类标签

# 是否存在睡眠障碍(0=无,1=有)
df['has_disorder'] = df['sleep_disorder_encoded'].apply(
    lambda x: 1 if x > 0 else 0
)

3.4 数据标准化

消除不同特征量纲的影响:

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

# 选择特征
features = ['age', 'gender_encoded', 'sleep_quality', 
            'physical_activity_level', 'stress_level',
            'bmi_category_encoded', 'heart_rate', 'daily_steps',
            'systolic_bp', 'diastolic_bp']
X = df[features]
y = df['sleep_duration']

# 标准化
X_scaled = StandardScaler().fit_transform(X)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.2, random_state=42
)

参数说明

  • test_size=0.2: 80%训练,20%测试
  • random_state=42: 随机种子,确保结果可复现

📊 第四步:数据可视化

4.1 创建多子图布局

fig, axes = plt.subplots(2, 3, figsize=(18, 12))

4.2 绘制睡眠时长直方图

# 睡眠时长分布
axes[0, 0].hist(df['sleep_duration'], bins=20, 
                 color='skyblue', edgecolor='black', alpha=0.7)
axes[0, 0].axvline(df['sleep_duration'].mean(), 
                    color='red', linestyle='--', linewidth=2)
axes[0, 0].set_xlabel('睡眠时长(小时)')
axes[0, 0].set_ylabel('频数')
axes[0, 0].set_title('睡眠时长分布', fontweight='bold')

效果图

直方图显示:大部分人的睡眠时长在7-9小时
红色虚线:标记均值位置(8.04小时)

4.3 绘制散点图(彩色编码)

# 年龄与睡眠时长关系(按睡眠质量着色)
scatter = axes[1, 1].scatter(
    df['age'], df['sleep_duration'], 
    c=df['sleep_quality'], cmap='viridis', 
    alpha=0.6, s=50
)
axes[1, 1].set_xlabel('年龄')
axes[1, 1].set_ylabel('睡眠时长(小时)')
axes[1, 1].set_title('年龄与睡眠时长关系', fontweight='bold')

# 添加颜色条
plt.colorbar(scatter, ax=axes[1, 1], label='睡眠质量')

技巧

  • cmap='viridis': 使用viridis颜色映射
  • alpha=0.6: 设置透明度
  • colorbar: 添加图例说明

4.4 绘制饼图

# BMI分类分布
bmi_counts = df['bmi_category'].value_counts()
axes[0, 2].pie(
    bmi_counts.values, 
    labels=bmi_counts.index, 
    autopct='%1.1f%%',
    colors=['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
)
axes[0, 2].set_title('BMI分类分布', fontweight='bold')

4.5 自定义相关性热图

import numpy as np

# 选择数值型特征
numeric_cols = ['age', 'sleep_duration', 'sleep_quality', 
                'physical_activity_level', 'stress_level', 
                'heart_rate', 'daily_steps']
corr = df[numeric_cols].corr()

# 绘制热图
im = axes[0, 0].imshow(corr, cmap='coolwarm', 
                         aspect='auto', vmin=-1, vmax=1)
axes[0, 0].set_xticks(range(len(numeric_cols)))
axes[0, 0].set_yticks(range(len(numeric_cols)))
axes[0, 0].set_xticklabels(numeric_cols, rotation=45, ha='right')
axes[0, 0].set_yticklabels(numeric_cols)
axes[0, 0].set_title('特征相关性热图', fontweight='bold')

# 添加数值标注
for i in range(len(numeric_cols)):
    for j in range(len(numeric_cols)):
        axes[0, 0].text(j, i, f'{corr.iloc[i, j]:.2f}',
                        ha='center', va='center', fontsize=8)

# 添加颜色条
plt.colorbar(im, ax=axes[0, 0], shrink=0.8).set_label(
    '相关系数', rotation=270, labelpad=20
)

核心技巧

  • vmin=-1, vmax=1: 设置颜色范围为完全负相关到完全正相关
  • 双重循环添加相关系数数值
  • rotation=270: 旋转颜色条标签

4.6 保存图表

plt.tight_layout()  # 自动调整布局
plt.savefig('figure1_overview.png', dpi=300, bbox_inches='tight')
plt.close()

参数说明

  • dpi=300: 高分辨率,适合论文发表
  • bbox_inches='tight': 紧凑布局,避免内容被裁剪

🤖 第五步:机器学习建模

5.1 随机森林回归(预测睡眠时长)

from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score

# 定义特征
features_reg = ['age', 'gender_encoded', 'sleep_quality', 
                'physical_activity_level', 'stress_level',
                'bmi_category_encoded', 'heart_rate', 'daily_steps',
                'systolic_bp', 'diastolic_bp']

# 准备数据
X_reg = df[features_reg]
y_reg = df['sleep_duration']
X_reg_scaled = StandardScaler().fit_transform(X_reg)
X_train, X_test, y_train, y_test = train_test_split(
    X_reg_scaled, y_reg, test_size=0.2, random_state=42
)

# 训练模型
rf_reg = RandomForestRegressor(n_estimators=100, random_state=42)
rf_reg.fit(X_train, y_train)

# 预测
y_pred_reg = rf_reg.predict(X_test)

# 评估
mse = mean_squared_error(y_test, y_pred_reg)
r2 = r2_score(y_test, y_pred_reg)

print(f"随机森林回归 MSE: {mse:.4f}")
print(f"随机森林回归 R2: {r2:.4f}")

输出结果

随机森林回归 MSE: 4.9658
随机森林回归 R2: -0.0657

5.2 随机森林分类(预测睡眠障碍)

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# 定义特征(包含睡眠时长)
features_clf = ['age', 'gender_encoded', 'sleep_duration', 
                 'sleep_quality', 'physical_activity_level',
                 'stress_level', 'bmi_category_encoded',
                 'heart_rate', 'daily_steps', 
                 'systolic_bp', 'diastolic_bp']

# 准备数据
X_clf = df[features_clf]
y_clf = df['has_disorder']
X_train_clf, X_test_clf, y_train_clf, y_test_clf = train_test_split(
    X_clf, y_clf, test_size=0.2, random_state=42
)

# 训练模型
rf_clf = RandomForestClassifier(n_estimators=100, random_state=42)
rf_clf.fit(X_train_clf, y_train_clf)

# 预测
y_pred_clf = rf_clf.predict(X_test_clf)

# 评估
acc = accuracy_score(y_test_clf, y_pred_clf)
print(f"随机森林分类 准确率: {acc:.4f}")

输出结果

随机森林分类 准确率: 0.7875

5.3 特征重要性分析

import pandas as pd

# 回归模型特征重要性
feature_imp = pd.DataFrame({
    '特征': features_reg,
    '重要性': rf_reg.feature_importances_
})
feature_imp = feature_imp.sort_values('重要性', ascending=False)

print("特征重要性TOP 5:")
print(feature_imp.head(5))

输出结果

特征重要性TOP 5:
              特征      重要性
9        daily_steps  0.1772
2      sleep_quality  0.1477
6  physical_activity_level  0.1452
7         heart_rate  0.1265
10    diastolic_bp  0.0984

📈 第六步:模型结果可视化

6.1 预测值vs实际值

fig, axes = plt.subplots(2, 2, figsize=(16, 12))

# 预测vs实际
axes[0, 0].scatter(y_test, y_pred_reg, alpha=0.6, s=50, color='blue')
axes[0, 0].plot([y_test.min(), y_test.max()], 
                  [y_test.min(), y_test.max()], 'r--', lw=2)
axes[0, 0].set_xlabel('实际睡眠时长')
axes[0, 0].set_ylabel('预测睡眠时长')
axes[0, 0].set_title('回归预测vs实际', fontweight='bold')
axes[0, 0].legend(['完美预测'])
axes[0, 0].grid(True, alpha=0.3)

6.2 残差图

# 残差图
residuals = y_test - y_pred_reg
axes[0, 1].scatter(y_pred_reg, residuals, alpha=0.6, s=50, color='green')
axes[0, 1].axhline(y=0, color='red', linestyle='--', lw=2)
axes[0, 1].set_xlabel('预测值')
axes[0, 1].set_ylabel('残差')
axes[0, 1].set_title('回归残差图', fontweight='bold')
axes[0, 1].grid(True, alpha=0.3)

6.3 特征重要性条形图

# 回归特征重要性
top_reg = feature_imp.head(8)
axes[1, 0].barh(top_reg['特征'], top_reg['重要性'], color='coral')
axes[1, 0].set_xlabel('重要性')
axes[1, 0].set_ylabel('特征')
axes[1, 0].set_title('回归特征重要性', fontweight='bold')
axes[1, 0].invert_yaxis()

# 分类特征重要性
clf_imp = pd.DataFrame({
    '特征': features_clf,
    '重要性': rf_clf.feature_importances_
})
clf_imp = clf_imp.sort_values('重要性', ascending=False)
top_clf = clf_imp.head(8)
axes[1, 1].barh(top_clf['特征'], top_clf['重要性'], color='skyblue')
axes[1, 1].set_xlabel('重要性')
axes[1, 1].set_ylabel('特征')
axes[1, 1].set_title('分类特征重要性', fontweight='bold')
axes[1, 1].invert_yaxis()

plt.tight_layout()
plt.savefig('figure3_model_results.png', dpi=300, bbox_inches='tight')
plt.close()

💡 第七步:结果分析与建议

核心发现

1. 每日步数是最重要的影响因素 🏃
  • 回归模型重要性: 17.72%
  • 分类模型重要性: 14.21%

建议: 每天保持8000-10000步的活动量

2. 身体活动水平次重要 🏋️
  • 与睡眠质量呈正相关
  • 中高强度运动效果更佳

建议: 每周至少150分钟中等强度有氧运动

3. 睡眠质量与时长相互影响 😴
  • 形成良性循环
  • 高质量睡眠延长睡眠时长

建议: 建立规律作息,固定上床和起床时间

4. 心率反映健康状态 ❤️
  • 较低静息心率与更好睡眠相关
  • 通过运动和压力管理可改善

建议: 学习冥想、深呼吸等放松技巧

模型性能分析

模型 任务 指标 结果 评价
随机森林回归 预测睡眠时长 MSE: 4.97 预测能力有限
随机森林回归 预测睡眠时长 R²: -0.07 解释性差
随机森林分类 预测睡眠障碍 准确率: 78.75% 表现良好

📚 完整代码下载

代码文件

  • sleep_analysis.py - 主分析程序(342行)
  • test_chinese_font.py - 字体测试程序(160行)

可视化结果

  • figure1_overview.png - 数据概览
  • figure2_correlation.png - 相关性分析
  • figure3_model_results.png - 模型结果

数据文件

  • sleep.csv - 原始数据集

🎓 学习要点总结

技术要点

  1. 数据预处理

    • 分类变量编码(LabelEncoder)
    • 特征转换(lambda函数)
    • 数据标准化(StandardScaler)
  2. 数据可视化

    • 中文字体配置
    • 多子图布局
    • 自定义热图实现
    • 高清图表保存
  3. 机器学习

    • 随机森林算法
    • 回归vs分类任务
    • 特征重要性分析
    • 模型评估指标

常见问题

问题 解决方案
中文显示乱码 设置字体:plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
负号显示异常 设置:plt.rcParams['axes.unicode_minus'] = False
图片被裁剪 保存时加参数:bbox_inches='tight'
代码复现性差 设置随机种子:random_state=42

🚀 扩展方向

短期优化

  • 添加超参数调优(GridSearchCV)
  • 使用交叉验证
  • 尝试更多算法(XGBoost、LightGBM)

中期扩展

  • 交互式可视化(Dash、Streamlit)
  • 增加数据量(1000+样本)
  • 添加更多特征(饮食、心理健康)

长期规划

  • 开发Web应用
  • 部署为API服务
  • 深度学习模型(神经网络)

💬 交流讨论

欢迎评论区留言讨论

  • 💡 数据分析经验分享
  • 🐛 代码问题咨询
  • 📈 模型改进建议
  • 🎯 学习心得交流

相关推荐


📖 参考资料

  1. scikit-learn官方文档
  2. matplotlib中文显示教程
  3. 随机森林算法详解

如果本文对你有帮助,请点赞、收藏、转发支持!

关注我,获取更多Python数据分析、机器学习实战教程!


Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐