【2025年泰迪杯数据挖掘挑战赛】B题 详细解题思路+数据预处理+代码分享

2025年泰迪杯B题详细解题思路

初步分析整理了B题的赛题分析与解题思路,后面还会更新详细的建模论文与解题代码,明天完成!

问题一

问题分析

需要从附件1的加速度数据中提取MET值,并按强度分类统计时长。核心在于正确处理时间戳间隔和MET区间分类。由于时间戳为毫秒级,需计算相邻时间差并累加至对应活动类别。需注意时间差计算的精度及MET区间的边界条件。

数学模型

在这里插入图片描述

Python代码

import pandas as pd
import re
import os

def process_volunteer(file_path):
    df = pd.read_csv(file_path)
    df['日期'] = pd.to_numeric(df['日期'])
    df = df.sort_values('日期')
    df['delta'] = df['日期'].diff().shift(-1) / (3600 * 1000)  # 转换为小时
    df = df.dropna(subset=['delta'])
    
    # 提取MET值
    df['MET'] = df['标签'].apply(lambda x: float(re.search(r'MET值\s*([0-9.]+)', x).group(1)))
    
    # 分类统计
    bins = [-float('inf'), 1, 1.6, 3, 6, float('inf')]
    labels = ['睡眠', '静态活动', '低等强度', '中等强度', '高等强度']
    df['category'] = pd.cut(df['MET'], bins=bins, labels=labels, right=False)
    result = df.groupby('category')['delta'].sum().to_dict()
    
    return {
        '志愿者ID': os.path.basename(file_path).split('.')[0],
        '记录总时长(小时)': round(df['delta'].sum(), 4),
        '睡眠总时长(小时)': round(result.get('睡眠', 0), 4),
        '高等强度运动总时长(小时)': round(result.get('高等强度', 0), 4),
        '中等强度运动总时长(小时)': round(result.get('中等强度', 0), 4),
        '低等强度运动总时长(小时)': round(result.get('低等强度', 0), 4),
        '静态活动总时长(小时)': round(result.get('静态活动', 0), 4)
    }

# 主程序
metadata = pd.read_csv('Metadatal.csv')
results = []
for vid in metadata['志愿者ID']:
    file_path = f'附件1/P{vid}.csv'
    if os.path.exists(file_path):
        res = process_volunteer(file_path)
        results.append(res)

pd.DataFrame(results).to_excel('result_1.xlsx', index=False)

Matlab代码

function B1()
    dataDir = '附件1/';
    meta = readtable('Metadatal.csv');
    results = cell(height(meta), 7);
    
    for i = 1:height(meta)
        vid = meta.志愿者ID{i};
        file = [dataDir 'P' vid '.csv'];
        if ~exist(file, 'file'), continue; end
        
        % 读取数据并排序
        tbl = readtable(file);
        tbl.日期 = str2double(tbl.日期);
        [~, idx] = sort(tbl.日期);
        tbl = tbl(idx, :);
        
        % 计算时间差
        delta = diff(tbl.日期) / (3600 * 1000); % 转换为小时
        met = zeros(length(delta), 1);
        for j = 1:length(delta)
            metStr = tbl.标签{j};
            metVal = regexp(metStr, 'MET值\s*([0-9.]+)', 'tokens', 'once');
            met(j) = str2double(metVal{1});
        end
        
        % 分类统计
        edges = [-inf, 1, 1.6, 3, 6, inf];
        [~, bin] = histc(met, edges);
        total = sum(delta);
        counts = accumarray(bin, delta, [5, 1], @sum, 0);
        
        % 保存结果
        results(i, :) = {vid, total, counts(1), counts(5), counts(4), counts(3), counts(2)};
    end
    
    % 输出到Excel
    T = cell2table(results, 'VariableNames', {'志愿者ID', '总时长', '睡眠', '高等', '中等', '低等', '静态'});
    writetable(T, 'result_1.xlsx');
end

问题二

问题分析

需构建回归模型预测MET值。输入特征包括三轴加速度的时域、频域统计量及元数据(年龄、性别)。模型需捕捉加速度与MET值的非线性关系。

数学模型

在这里插入图片描述
在这里插入图片描述

Python代码

import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score

def extract_features(data):
    x = data['X'].values
    y = data['Y'].values
    z = data['Z'].values
    vm = np.sqrt(x**2 + y**2 + z**2)
    
    # 时域特征
    features = {
        'x_mean': np.mean(x), 'x_std': np.std(x),
        'y_mean': np.mean(y), 'y_std': np.std(y),
        'z_mean': np.mean(z), 'z_std': np.std(z),
        'vm_mean': np.mean(vm), 'vm_std': np.std(vm),
        'vm_rms': np.sqrt(np.mean(vm**2))
    }
    
    # 频域特征
    for axis, sig in zip(['x', 'y', 'z'], [x, y, z]):
        fft = np.abs(np.fft.rfft(sig))
        features[f'{axis}_energy'] = np.sum(fft**2)
    
    return features

# 训练数据准备
metadata = pd.read_csv('Metadatal.csv')
X, y = [], []
for vid in metadata['志愿者ID']:
    df = pd.read_csv(f'附件1/P{vid}.csv')
    df['MET'] = df['标签'].str.extract(r'MET值\s*([0-9.]+)').astype(float)
    
    # 滑动窗口处理(窗口5秒)
    window_size = 5
    for i in range(0, len(df
) - window_size, window_size):
        window = df.iloc[i:i+window_size]
        feat = extract_features(window)
        feat['age'] = metadata.loc[metadata['志愿者ID'] == vid, '年龄'].values[0]
        feat['gender'] = 1 if metadata.loc[metadata['志愿者ID'] == vid, '性别'].values[0] == '男' else 0
        X.append(feat)
        y.append(window['MET'].mean())

# 训练模型
model = RandomForestRegressor(n_estimators=100)
scores = cross_val_score(model, pd.DataFrame(X), y, cv=5, scoring='r2')
print(f'交叉验证R²得分: {np.mean(scores):.4f}')
model.fit(pd.DataFrame(X), y)

# 预测附件2数据

Matlab代码

function B2()
    % 特征提取函数
    function feat = extractFeatures(x, y, z)
        vm = sqrt(x.^2 + y.^2 + z.^2);
        feat = [mean(x), std(x), mean(y), std(y), mean(z), std(z), ...
                mean(vm), std(vm), rms(vm), sum(abs(fft(x)).^2), ...
                sum(abs(fft(y)).^2), sum(abs(fft(z)).^2)];
    end

    % 加载数据
    meta = readtable('Metadatal.csv');
    X = []; y = [];
    for i = 1:height(meta)
        file = ['附件1/P' meta.志愿者ID{i} '.csv'];
        tbl = readtable(file);
        met = cellfun(@(s) str2double(regexp(s, 'MET值\s*([0-9.]+)', 'tokens', 'once')), tbl.标签);
        
        % 滑动窗口处理
        winSize = 5;  % 5秒窗口
        for j = 1:winSize:height(tbl)-winSize
            x = tbl.X(j:j+winSize-1);
            y_axis = tbl.Y(j:j+winSize-1);
            z = tbl.Z(j:j+winSize-1);
            feat = extractFeatures(x, y_axis, z);
            X = [X; feat meta.年龄(i) strcmp(meta.性别{i}, '男')];
            y = [y; mean(met(j:j+winSize-1))];
        end
    end
    
    % 训练随机森林
    model = TreeBagger(100, X, y, 'Method', 'regression');
    
    % 预测附件2
end

问题三

问题分析

睡眠阶段通过低活动量时段检测。计算向量幅度(VM)的滑动窗口均值,低于阈值视为睡眠候选,进一步聚类划分模式。

数学模型

活动量计算:
[
VM(t) = \sqrt{x(t)^2 + y(t)^2 + z(t)^2}
]
睡眠窗口检测:
[
W_{\text{sleep}} = { t \mid \overline{VM}(t) < \theta }
]
K-means聚类:
目标函数为最小化类内平方和:
[
\min \sum_{k=1}^K \sum_{\mathbf{x} \in C_k} | \mathbf{x} - \mathbf{\mu}_k |^2
]
其中 ( \mathbf{\mu}_k ) 为窗口特征 ( \mathbf{x} ) 的聚类中心。

Python代码

from sklearn.cluster import KMeans

def detect_sleep(file_path):
    df = pd.read_csv(file_path)
    df['vm'] = np.sqrt(df['X']**2 + df['Y']**2 + df['Z']**2)
    
    # 滑动窗口检测低活动(30秒窗口)
    window_size = 30
    df['window'] = df.index // window_size
    activity = df.groupby('window')['vm'].mean()
    sleep_windows = activity[activity < 0.1].index
    
    # 提取窗口特征
    features = []
    for win in sleep_windows:
        win_data = df[df['window'] == win]
        vm_mean = win_data['vm'].mean()
        vm_std = win_data['vm'].std()
        features.append([vm_mean, vm_std])
    
    # K-means聚类
    if len(features) == 0:
        return {'睡眠总时长': 0.0, '模式一': 0.0, '模式二': 0.0, '模式三': 0.0}
    kmeans = KMeans(n_clusters=3).fit(features)
    labels = kmeans.labels_
    counts = np.bincount(labels, minlength=3)
    hours = counts * window_size / 3600  # 转换为小时
    
    return {
        '睡眠总时长': round(np.sum(hours), 4),
        '模式一': round(hours[0], 4),
        '模式二': round(hours[1], 4),
        '模式三': round(hours[2], 4)
    }

# 处理附件2并保存结果

Matlab代码

function B3()
    function [total, modes] = detectSleep(file)
        tbl = readtable(file);
        vm = sqrt(tbl.X.^2 + tbl.Y.^2 + tbl.Z.^2);
        
        % 检测低活动窗口(30秒窗口)
        winSize = 30;
        numWin = floor(height(tbl)/winSize);
        act = zeros(numWin, 1);
        for i = 1:numWin
            idx = (i-1)*winSize + 1 : i*winSize;
            act(i) = mean(vm(idx));
        end
        sleepWins = find(act < 0.1);
        
        % 提取特征并聚类
        features = zeros(length(sleepWins), 2);
        for j = 1:length(sleepWins)
            idx = (sleepWins(j)-1)*winSize + 1 : sleepWins(j)*winSize;
            vmWin = vm(idx);
            features(j, :) = [mean(vmWin), std(vmWin)];
        end
        
        if isempty(features)
            total = 0; modes = zeros(1,3);
        else
            [~, C] = kmeans(features, 3);
            counts = histcounts(C, 1:4);
            total = sum(counts) * winSize / 3600;
            modes = counts * winSize / 3600;
        end
    end
    
    % 应用至附件2(略)
end

问题四

问题分析

检测连续静态活动(MET<1.6)超过30分钟的时段。遍历预测的MET序列,记录连续满足条件的时段。

数学模型

设MET序列为 ( MET(t) ),窗口步长 ( \Delta t )(单位:分钟),久坐判定条件为:
[
\sum_{i=t}^{t+\Delta t} MET(i) < 1.6 \quad \text{且} \quad \Delta t \geq 30
]

Python代码

def sedentary_alert(met_series, window_min=5):
    delta = window_min / 60  # 转换为小时
    sedentary = []
    current_duration = 0.0
    start_idx = None
    
    for i, met in enumerate(met_series):
        if met < 1.6:
            current_duration += delta
            if start_idx is None:
                start_idx = i
        else:
            if current_duration >= 0.5:  # 0.5小时=30分钟
                end_idx = i - 1
                sedentary.append((start_idx, end_idx, current_duration))
            current_duration = 0.0
            start_idx = None
    
    if current_duration >= 0.5:
        sedentary.append((start_idx, len(met_series)-1, current_duration))
    
    return sedentary

# 应用至附件2预测结果

Matlab代码

function B4()
    function alerts = detectSedentary(met, winSize)
        delta = winSize / 60;  % 窗口分钟转小时
        alerts = [];
        start = 1; count = 0;
        
        for i = 1:length(met)
            if met(i) < 1.6
                count = count + delta;
                if isempty(start), start = i; end
            else
                if count >= 0.5  % 0.5小时=30分钟
                    alerts = [alerts; [start, i-1, count]];
                end
                count = 0;
                start = [];
            end
        end
        
        if count >= 0.5
            alerts = [alerts; [start, length(met), count]];
        end
    end
    
    % 应用至附件2(略)
end

完整论文代码获取,请看下方~ 可直接指导比赛,冲国奖

【标】第十届泰迪数据挖掘挑战赛B是一个以数据分析和挖掘为核心的竞赛项目,参赛者需要通过解决一系列问来展示他们的技能和创新思维。这个压缩包包含了参赛者对B的完整解答以及实现这些解答的源代码。 【描述】这个描述简单明了,表明压缩包中的内容是关于“第十届泰迪数据挖掘挑战赛”的B解决方案。"完整解题代码"意味着文件中不仅有分析思路和方法论,还有实际的编程实现,这对于学习数据挖掘和机器学习的初学者或爱好者来说是非常宝贵的资源。 【标签】虽然没有提供具体的标签,但我们可以根据标和描述推断出一些关键标签,如“数据挖掘”、“数据分析”、“机器学习”、“Python编程”、“挑战赛”、“比赛策略”。 【压缩包子文件的文件名称列表】 1. 第一问第一小问.zip:这可能是参赛者对B第一部分的第一小问的解答和代码,可能涉及到数据预处理、探索性数据分析(EDA)和初步模型构建。 2. 第一问第二小问.zip:这涵盖了第一部分的第二个问,可能涉及更复杂的数据建模、特征工程或者模型优化。 3. 第二问第一小问.zip:这是针对B第二部分的第一个问,可能涉及到不同的数据挖掘任务,如分类、聚类或预测。 4. 第二问第二小问.zip:对应第二部分的第二个问,可能需要参赛者进行更深入的分析,如异常检测、关联规则学习或者时间序列分析。 5. 问二-异常时间点分析 (1).ipynb:这是一个Jupyter Notebook文件,专门针对问二中的异常时间点分析,可能包含了数据可视化、统计测试和异常检测算法的实现。 综合以上信息,我们可以了解到这个压缩包是围绕数据挖掘挑战赛解题过程,涉及到多个阶段的问解决,涵盖数据预处理、建模、模型评估和异常检测等核心步骤。参赛者可能使用了Python等编程语言,利用了如Pandas、Numpy、Scikit-learn等库进行数据分析和建模。通过研究这些文件,学习者可以深入理解如何在实际问中应用数据挖掘技术,并且能学习到如何组织和呈现一个完整的数据挖掘项目。
<think>好的,我需要解决用户的问,即根据加速度记录数据和MET值范围,统计不同强度活动的时间占比,并导出到Excel。首先,我得理清楚整个处理流程。 用户的需求是处理志愿者的加速度数据,计算不同强度活动的时间占比,然后生成指定格式的Excel文件。首先,我需要明确几个关键点:MET值的分类标准、数据的时间分辨率、数据的结构以及如何处理这些数据。 首先,确定MET值的分类范围。通常,MET(代谢当量)用来表示活动的强度。例如,睡眠可能对应MET < 1,静态活动1 ≤ MET < 1.5,低强度1.5 ≤ MET < 3,中强度3 ≤ MET < 6,高强度MET ≥ 6。用户可能需要根据具体研究调整这些阈值,但假设这里使用常见的分类。 接下来,数据格式方面,加速度数据可能以时间戳和对应的MET值记录。例如,每秒或每分钟一个数据点。需要确保数据包含志愿者ID、时间戳和MET值这三列。 处理步骤大致如下: 1. 读取数据:使用Python的pandas库读取原始数据,比如CSV文件。 2. 分类统计:根据MET值将每个时间点归类到对应的活动强度。 3. 计算时长:按志愿者分组,统计每个类别的总时间。 4. 计算占比:将时长转换为占总时间的百分比。 5. 导出结果:将结果整理为指定格式并写入Excel文件。 可能遇到的问包括数据的时间间隔不一致,需要确认每个数据点代表的时间长度(如1分钟一个数据点,则每个点计为1分钟)。此外,缺失值或异常值的处理也需要考虑,比如填充或剔除。 代码方面,可以使用pandas进行数据处理。例如,用pd.read_csv读取数据,用pd.cut进行MET区间的分类,再用groupby和agg进行统计。最后用to_excel导出结果。 需要验证数据的正确性,比如检查总时间是否合理,各分类占比之和是否为100%。此外,导出Excel时要注意格式,确保列名正确,如志愿者ID、睡眠时长、静态时长等。 可能还需要处理多个志愿者的数据,每个志愿者的数据可能存储在不同的文件或同一个文件的不同行中。需要确保按志愿者ID正确分组统计。 总结步骤: 1. 确定MET分类阈值。 2. 读取并清洗数据。 3. 分类并统计时长。 4. 计算占比。 5. 导出到Excel。 现在需要将这些步骤转化为具体的Python代码,并确保处理效率和准确性。</think>### 分步解决方案 1. **数据预处理** - 假设数据格式为CSV,包含`志愿者ID`、`时间戳`、`MET值`三列 - 读取数据并验证完整性: ```python import pandas as pd df = pd.read_csv('accelerometer_data.csv') df['时间戳'] = pd.to_datetime(df['时间戳']) # 转换为时间格式 ``` 2. **定义强度分类标准** ```python bins = [-float('inf'), 1, 1.5, 3, 6, float('inf')] labels = ['睡眠', '静态活动', '低强度运动', '中强度运动', '高强度运动'] ``` 3. **分类与时长统计** ```python # 添加分类列 df['活动类型'] = pd.cut(df['MET值'], bins=bins, labels=labels, right=False) # 按志愿者和活动类型统计 result = df.groupby(['志愿者ID', '活动类型']).size().unstack(fill_value=0) # 计算总时间(假设数据间隔为1分钟) result['总时长(分钟)'] = result.sum(axis=1) # 计算时间占比 for col in labels: result[f'{col}占比(%)'] = result[col] / result['总时长(分钟)'] * 100 ``` 4. **导出Excel文件** ```python # 按指定格式整理列 output_cols = ['总时长(分钟)'] + [f'{col}占比(%)' for col in labels] final_output = result[output_cols].reset_index() # 导出到Excel final_output.to_excel('result_1.xlsx', index=False, float_format='%.2f') ``` 5. **验证数据完整性** - 检查每个志愿者的总时长是否合理 - 验证各分类占比之和是否为100%(允许±0.01%的浮点误差) ### 代码示例 ```python import pandas as pd # 读取数据 df = pd.read_csv("accelerometer_data.csv") df['时间戳'] = pd.to_datetime(df['时间戳']) # 定义分类标准 bins = [-float('inf'), 1, 1.5, 3, 6, float('inf')] labels = ['睡眠', '静态活动', '低强度运动', '中强度运动', '高强度运动'] # 分类统计 df['活动类型'] = pd.cut(df['MET值'], bins=bins, labels=labels, right=False) result = df.groupby(['志愿者ID', '活动类型']).size().unstack(fill_value=0) # 计算总时长和占比 result['总时长(分钟)'] = result.sum(axis=1) for col in labels: result[f'{col}占比(%)'] = result[col] / result['总时长(分钟)'] * 100 # 导出结果 output_cols = ['总时长(分钟)'] + [f'{col}占比(%)' for col in labels] result[output_cols].reset_index().to_excel("result_1.xlsx", index=False, float_format="%.2f") ``` ### 输出文件格式示例 | 志愿者ID | 总时长(分钟) | 睡眠占比(%) | 静态活动占比(%) | 低强度运动占比(%) | 中强度运动占比(%) | 高强度运动占比(%) | |----------|--------------|-------------|-----------------|-------------------|-------------------|-------------------| | 001 | 1440 | 33.33 | 40.00 | 15.00 | 8.33 | 3.33 | ### 注意事项 1. 数据时间间隔:假设数据为每分钟一条记录,若实际采样频率不同需调整时长计算逻辑[^1] 2. MET阈值:可根据具体研究需求调整`bins`的划分标准 3. 异常值处理:建议在数据预处理阶段增加`df = df[(df['MET值'] >= 0) & (df['MET值'] <= 20)]`过滤不合理值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值