Python时型聚类分析教程:识别用户的昼夜节律类型
概述
时型(Chronotype)是指个体昼夜节律的偏好类型,主要分为:
- 早起型(百灵鸟型):早睡早起
- 夜猫子型:晚睡晚起
- 中间型:介于两者之间
通过分析用户的睡眠数据、活动数据和其他时间序列数据,我们可以识别其时型,并提供个性化的健康建议。
数据准备
示例数据结构
code
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# 模拟用户活动数据
def generate_user_activity_data(num_days=30):
"""生成模拟的活动数据"""
dates = pd.date_range(start='2026-01-01', periods=num_days)
data = []
for date in dates:
for hour in range(24):
# 模拟活动水平(0-100)
activity = np.random.normal(loc=50, scale=20)
activity = np.clip(activity, 0, 100)
data.append({
'date': date,
'hour': hour,
'activity': activity,
'timestamp': datetime.combine(date, datetime.min.time()) + timedelta(hours=hour)
})
return pd.DataFrame(data)
# 生成数据
activity_data = generate_user_activity_data(30)
print(activity_data.head())
Code collapsed
特征工程
1. 计算时型特征
code
def calculate_chronotype_features(df):
"""计算时型相关特征"""
features = {}
# 1. 中点时间(活动峰值的中间点)
hourly_activity = df.groupby('hour')['activity'].mean()
peak_hour = hourly_activity.idxmax()
features['midpoint'] = peak_hour
# 2. 活动开始时间(活动>阈值的最早时间)
threshold = 50
active_hours = hourly_activity[hourly_activity > threshold].index
features['activity_start'] = active_hours.min() if len(active_hours) > 0 else 7
# 3. 活动结束时间
features['activity_end'] = active_hours.max() if len(active_hours) > 0 else 22
# 4. 活动持续时间
features['active_duration'] = features['activity_end'] - features['activity_start']
# 5. 上午活动比例 (6-12点)
morning_activity = hourly_activity[6:13].sum()
total_activity = hourly_activity.sum()
features['morning_ratio'] = morning_activity / total_activity
# 6. 下午活动比例 (12-18点)
afternoon_activity = hourly_activity[12:19].sum()
features['afternoon_ratio'] = afternoon_activity / total_activity
# 7. 晚间活动比例 (18-24点)
evening_activity = hourly_activity[18:25].sum()
features['evening_ratio'] = evening_activity / total_activity
# 8. 活动规律性(标准差)
features['activity_regularity'] = hourly_activity.std()
return features
# 计算特征
chronotype_features = calculate_chronotype_features(activity_data)
print(chronotype_features)
Code collapsed
聚类分析
K-means聚类
code
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
def cluster_users(user_data_dict):
"""对多个用户进行聚类分析"""
# 提取特征矩阵
features_list = []
user_ids = []
for user_id, user_data in user_data_dict.items():
features = calculate_chronotype_features(user_data)
features_list.append(list(features.values()))
user_ids.append(user_id)
feature_matrix = np.array(features_list)
# 标准化
scaler = StandardScaler()
features_scaled = scaler.fit_transform(feature_matrix)
# K-means聚类
kmeans = KMeans(n_clusters=3, random_state=42)
clusters = kmeans.fit_predict(features_scaled)
# 分类结果
cluster_mapping = {
0: '早起型',
1: '中间型',
2: '夜猫子型'
}
results = pd.DataFrame({
'user_id': user_ids,
'cluster': clusters,
'chronotype': [cluster_mapping[c] for c in clusters]
})
return results, kmeans, scaler
# 模拟多个用户数据
user_data_dict = {
f'user_{i}': generate_user_activity_data(30)
for i in range(100)
}
# 执行聚类
results, kmeans_model, scaler = cluster_users(user_data_dict)
print(results.head())
Code collapsed
可视化分析
时型分布可视化
code
import matplotlib.pyplot as plt
import seaborn as sns
def visualize_chronotype_distribution(results):
"""可视化时型分布"""
plt.figure(figsize=(12, 5))
# 子图1:时型分布饼图
plt.subplot(1, 2, 1)
chronotype_counts = results['chronotype'].value_counts()
colors = ['#FFD700', '#87CEEB', '#9370DB']
plt.pie(chronotype_counts.values,
labels=chronotype_counts.index,
autopct='%1.1f%%',
colors=colors)
plt.title('用户时型分布')
# 子图2:各时型的活动曲线
plt.subplot(1, 2, 2)
for cluster in results['cluster'].unique():
cluster_users = results[results['cluster'] == cluster]['user_id'].values
# 计算该类别的平均活动曲线
cluster_activity = []
for user_id in cluster_users[:5]: # 采样
user_data = user_data_dict[user_id]
hourly_avg = user_data.groupby('hour')['activity'].mean()
cluster_activity.append(hourly_avg)
avg_activity = pd.concat(cluster_activity, axis=1).mean(axis=0)
plt.plot(avg_activity.index, avg_activity.values,
label=f'类别{cluster}', linewidth=2)
plt.xlabel('小时')
plt.ylabel('活动水平')
plt.title('不同时型的活动曲线')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
visualize_chronotype_distribution(results)
Code collapsed
时型评估问卷
MCTQ问卷数据分析
code
def analyze_mctq_questionnaire(responses):
"""
分析Munich Chronotype Questionnaire (MCTQ)问卷数据
参数:
responses: DataFrame, 包含MCTQ问卷答案
"""
# MCTQ主要问题
mctq_questions = {
'sleep_duration': '平均睡眠时长',
'mid_sleep': '睡眠中点时间',
'activity_peak': '活动峰值时间',
'morningness': '早晨清醒度'
}
# 计算时型分数
# 早晨清醒度分数越高 = 早起型
morningness_score = responses['morningness'].mean()
# 分类标准
if morningness_score >= 4:
chronotype = '早起型'
elif morningness_score <= 2:
chronotype = '夜猫子型'
else:
chronotype = '中间型'
return {
'chronotype': chronotype,
'morningness_score': morningness_score,
'sleep_duration': responses['sleep_duration'].mean()
}
Code collapsed
关键要点
- 时型识别基于多种特征:活动模式、睡眠时间、问卷数据
- K-means聚类是常用方法:可无监督学习用户时型
- 特征工程很重要:需要设计有区分度的时型特征
- 考虑季节性和日常变化:工作日和周末可能不同
- 时型与健康相关:时型错位可能影响睡眠质量和代谢健康
常见问题
如何处理不规律的作息?
使用活动传感器的连续监测数据,而非单日数据。计算7-14天的平均模式。
时型会改变吗?
是的,时型可能随年龄、工作性质、季节而变化。建议定期重新评估。
聚类数量如何确定?
使用肘部法则(Elbow Method)或轮廓系数(Silhouette Score)确定最佳聚类数。
参考资料
- Roenneberg T, et al. Munich Chronotype Questionnaire.
- Wang Y, et al. Chronotype and health outcomes: A systematic review.
- scikit-learn documentation: https://scikit-learn.org/stable/modules/clustering.html
发布日期:2026年3月8日 最后更新:2026年3月8日