vr中风--数据处理模型搭建与训练2

news2025/7/21 7:15:24

位置http://localhost:8888/notebooks/Untitled1-Copy1.ipynb

# -*- coding: utf-8 -*-
"""
MUSED-I康复评估系统(增强版)
包含:多通道sEMG数据增强、混合模型架构、标准化处理
"""
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from collections import defaultdict
import tensorflow as tf


# 随机种子设置
SEED = 42
np.random.seed(SEED)
tf.random.set_seed(SEED)
# -------------------- 第一部分:数据增强器 --------------------
class SEMGDataGenerator:
    """
    sEMG数据增强器(支持多通道)
    增强策略:
    - 分通道时间扭曲
    - 通道独立噪声添加
    - 幅度缩放
    - 通道偏移
    """
    def __init__(self, noise_scale=0.2, stretch_range=(0.6, 1.4)):
        # 增强噪声强度和时间扭曲范围
        self.noise_scale = noise_scale
        self.stretch_range = stretch_range
    def channel_dropout(self, signals, max_drop=2):
        """随机屏蔽部分通道"""
        drop_mask = np.random.choice(signals.shape[1], max_drop, replace=False)
        signals[:, drop_mask] = 0
        return signals
    def time_warp(self, signals):
        """时间扭曲(分通道处理)"""
        orig_length = signals.shape[0]
        scale = np.random.uniform(*self.stretch_range)
        new_length = int(orig_length * scale)
        x_orig = np.linspace(0, 1, orig_length)
        x_new = np.linspace(0, 1, new_length)
        
        warped = np.zeros_like(signals)
        for c in range(signals.shape[1]):  # 分通道处理
            warped_single = np.interp(x_new, x_orig, signals[:, c])
            if new_length >= orig_length:
                warped[:, c] = warped_single[:orig_length]
            else:
                padded = np.zeros(orig_length)
                padded[:new_length] = warped_single
                warped[:, c] = padded
        return warped

    def add_noise(self, signals):
        """添加高斯噪声(通道独立)"""
        # 每个通道独立生成噪声
        noise = np.zeros_like(signals)
        for c in range(signals.shape[1]):
            channel_std = np.std(signals[:, c])
            noise[:, c] = np.random.normal(
                scale=self.noise_scale*channel_std, 
                size=signals.shape[0]
            )
        return signals + noise

    def amplitude_scale(self, signals):
        """幅度缩放(全通道同步)"""
        scale = np.random.uniform(0.7, 1.3)
        return signals * scale

    def channel_shift(self, signals):
        """通道偏移(循环平移)"""
        shift = np.random.randint(-3, 3)
        return np.roll(signals, shift, axis=1)  # 沿通道轴偏移

    def augment(self, window):
        """应用至少一种增强策略"""
        aug_window = window.copy()
        applied = False
        attempts = 0  # 防止无限循环
        
        # 尝试应用直到至少成功一次(最多尝试5次)
        while not applied and attempts < 5:
            if np.random.rand() > 0.5:
                aug_window = self.time_warp(aug_window)
                applied = True
            if np.random.rand() > 0.5:
                aug_window = self.add_noise(aug_window)
                applied = True
            if np.random.rand() > 0.5:
                aug_window = self.amplitude_scale(aug_window)
                applied = True
            if np.random.rand() > 0.5:
                window = np.flip(window, axis=0)                
            if np.random.rand() > 0.5:
                aug_window = self.channel_shift(aug_window)
                applied = True
            attempts += 1
        return aug_window
# -------------------- 第二部分:数据处理管道 --------------------
def load_and_preprocess(file_path, label, window_size=100, augment_times=5):
    """
    完整数据处理流程
    参数:
        file_path: CSV文件路径
        label: 数据标签 (1.0=健康人, 0.0=患者)
        window_size: 时间窗口长度(单位:采样点)
        augment_times: 每个样本的增强次数
    返回:
        features: 形状 (n_samples, window_size, n_channels)
        labels: 形状 (n_samples,)
    """
    # 1. 数据加载
    df = pd.read_csv(file_path, usecols=range(8))
    #df = df.dropna()  # 确保只读取前8列
    print("前8列统计描述:\n", df.describe())
    
    # 检查是否存在非数值或缺失值
    if df.isnull().any().any():
        print("发现缺失值,位置:\n", df.isnull().sum())
        df.fillna(method='ffill', inplace=True) # 可以考虑前向填充或均值填充,而非直接删除
        if df.isnull().any().any(): # 如果仍有NaN(例如开头就是NaN),再删除
            df.dropna(inplace=True)
            print("删除含缺失值的行后形状:", df.shape)
    
    # 检查无穷大值
    if np.isinf(df.values).any():
        print("发现无穷大值,将其替换为NaN并删除行。")
        df = df.replace([np.inf, -np.inf], np.nan).dropna()
        print("删除含无穷大值的行后形状:", df.shape)
    df = df.astype(np.float64) # 确保数据类型正确
    print(f"[1/5] 数据加载完成 | 原始数据形状: {df.shape}")
    
    # 2. 窗口分割
    windows = []
    step = window_size // 2  # 50%重叠
    n_channels = 8  # 假设前8列为sEMG信号
    
    for start in range(0, len(df)-window_size+1, step):
        end = start + window_size
        window = df.iloc[start:end, :n_channels].values  # (100,8)
        
        # 维度校验
        if window.ndim == 1:
            window = window.reshape(-1, 1)
        elif window.shape[1] != n_channels:
            raise ValueError(f"窗口通道数异常: {window.shape}")
            
        windows.append(window)
    print(f"[2/5] 窗口分割完成 | 总窗口数: {len(windows)} | 窗口形状: {windows[0].shape}")

    # 3. 数据增强
    generator = SEMGDataGenerator(noise_scale=0.05)
    augmented = []
    for w in windows:
        augmented.append(w)
        for _ in range(augment_times):
            try:
                aug_w = generator.augment(w)
                # 检查增强结果
                if not np.isfinite(aug_w).all():
                    raise ValueError("增强生成无效值")
                augmented.append(aug_w)
            except Exception as e:
                print(f"增强失败: {e}")
                continue
    print(f"[3/5] 数据增强完成 | 总样本数: {len(augmented)} (原始x{augment_times+1})")

    # 4. 形状一致性校验
    expected_window_shape = (window_size, n_channels) # 明确期望的形状
    filtered = [arr for arr in augmented if arr.shape == expected_window_shape]
    if len(filtered) < len(augmented):
        print(f"警告: 过滤掉 {len(augmented) - len(filtered)} 个形状不符合 {expected_window_shape} 的增强样本。")
    print(f"[4/5] 形状过滤完成 | 有效样本率: {len(filtered)}/{len(augmented)}")
    
    # 转换为数组
    features = np.stack(filtered)
    assert not np.isnan(features).any(), "增强数据中存在NaN"
    assert not np.isinf(features).any(), "增强数据中存在Inf"
    labels = np.full(len(filtered), label)
    return features, labels
# -------------------- 第三部分:标准化与数据集划分 --------------------
def channel_standardize(data):
    """逐通道标准化"""
    # data形状: (samples, timesteps, channels)
    mean = np.nanmean(data, axis=(0,1), keepdims=True)
    std = np.nanstd(data, axis=(0,1), keepdims=True)
    
    # 防止除零错误:若标准差为0,设置为1
    std_fixed = np.where(std == 0, 1.0, std)
    return (data - mean) / (std_fixed + 1e-8)
# -------------------- 执行主流程 --------------------
if __name__ == "__main__":
    # 数据加载与增强
    X_healthy, y_healthy = load_and_preprocess(
        'Healthy_Subjects_Data3_DOF.csv', 
        label=1.0,
        window_size=100,
        augment_times=5
    )
    
    X_patient, y_patient = load_and_preprocess(
        'Stroke_Patients_DataPatient1_3DOF.csv',
        label=0.0,
        window_size=100,
        augment_times=5
    )

    # 合并数据集
    X = np.concatenate([X_healthy, X_patient], axis=0)
    y = np.concatenate([y_healthy, y_patient], axis=0)
    print(f"\n合并数据集形状: X{X.shape} y{y.shape}")

    # 数据标准化
    X = channel_standardize(X)
    
    # 数据集划分
    X_train, X_val, y_train, y_val = train_test_split(
        X, y, 
        test_size=0.2, 
        stratify=y,
        random_state=SEED
    )
    
    print("\n最终数据集:")
    print(f"训练集: {X_train.shape} | 0类样本数: {np.sum(y_train==0)}")
    print(f"验证集: {X_val.shape} | 1类样本数: {np.sum(y_val==1)}")
    
    # 验证标准化效果
    sample_channel = 0
    print(f"\n标准化验证 (通道{sample_channel}):")
    print(f"均值: {np.mean(X_train[:, :, sample_channel]):.2f} (±{np.std(X_train[:, :, sample_channel]):.2f})")
from tensorflow.keras import layers, optimizers, callbacks, Model
# -------------------- 第三部分:模型架构 --------------------
def build_model(input_shape):
    """混合CNN+BiGRU模型"""
    inputs = layers.Input(shape=input_shape)
    
    # 特征提取分支
    x = layers.Conv1D(32, 15, activation='relu', padding='same', kernel_regularizer='l2')(inputs)  # 添加L2正则化
    x = layers.MaxPooling1D(2)(x)
    x = layers.Dropout(0.3)(x)  # 添加Dropout
    x = layers.Conv1D(64, 7, activation='relu', padding='same')(x)
    x = layers.MaxPooling1D(2)(x)
    x = layers.Bidirectional(layers.GRU(32, return_sequences=True))(x)
    x = layers.Dropout(0.3)(x)  # 第二层Dropout
    
    # 差异注意力机制
    attention = layers.Attention()([x, x])
    x = layers.Concatenate()([x, attention])
    
    # 回归输出层
    x = layers.GlobalAveragePooling1D()(x)
    x = layers.Dense(16, activation='relu')(x)
    outputs = layers.Dense(1, activation='sigmoid')(x)
    
    model = tf.keras.Model(inputs, outputs)
    return model

# 初始化模型
model = build_model(input_shape=(100, 8))
model.compile(
    optimizer=optimizers.Adam(learning_rate=0.001),
    loss='binary_crossentropy',
    metrics=['accuracy', tf.keras.metrics.AUC(name='auc')]
)
model.summary()
import matplotlib.pyplot as plt
# -------------------- 第四部分:模型训练 --------------------
# 定义回调
early_stop = callbacks.EarlyStopping(
    monitor='val_auc', 
    patience=10,
    mode='max',
    restore_best_weights=True
)

# 训练模型
history = model.fit(
    X_train, y_train,
    validation_data=(X_val, y_val),
    epochs=100,
    batch_size=32,
    callbacks=[early_stop],
    verbose=1
)
# -------------------- 第五部分:康复评估与可视化 --------------------
# 改进后的可视化和报告生成
# ... (训练过程可视化部分不变) ...

# 确保在调用 generate_report 之前有足够的子图空间
# 比如在 train_test_split 之后或者在 model.fit 之后
# 可以将整体可视化逻辑放到一个主函数中,或者明确创建 figure 和 axes
plt.figure(figsize=(18, 6)) # 增加figure大小以容纳更多图表
plt.subplot(1, 3, 1)
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.title('Loss Curve')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()

plt.subplot(1, 3, 2)
plt.plot(history.history['accuracy'], label='Train Accuracy') # 也可以加上准确率
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.plot(history.history['auc'], label='Train AUC')
plt.plot(history.history['val_auc'], label='Validation AUC')
plt.title('Performance Metrics')
plt.xlabel('Epoch')
plt.ylabel('Value')
plt.legend()

# 生成康复报告
def generate_report(model, patient_data):
    """生成定量康复评估报告"""
    # 预测所有窗口
    #predictions = model.predict(patient_data).flatten()
    # 计算康复指数(0-100%)
    #recovery_index = np.mean(predictions) * 100
    predictions = model.predict(patient_data).flatten()
    recovery_index = (1 - np.mean(predictions)) * 100  
    
    # 可视化预测分布
    plt.subplot(133)
    plt.hist(predictions, bins=20, alpha=0.7)
    plt.axvline(x=np.mean(predictions), color='red', linestyle='--')
    plt.title('Prediction Distribution\nMean R-index: %.1f%%' % recovery_index)
    # 可视化预测分布到传入的ax上

    
    # 生成文字报告
    print(f"""
    ======== 智能康复评估报告 ========
    分析窗口总数:{len(patient_data)}
    平均康复指数:{recovery_index:.1f}%
    最佳窗口表现:{np.max(predictions)*100:.1f}%
    最弱窗口表现:{np.min(predictions)*100:.1f}%
    --------------------------------
    临床建议:
    { "建议加强基础动作训练" if recovery_index <40 else 
      "建议进行中等强度康复训练" if recovery_index <70 else 
      "建议开展精细动作训练" if recovery_index <90 else 
      "接近健康水平,建议维持训练"}
    """)
X_patient
# 使用患者数据生成报告
generate_report(model, X_patient)

plt.tight_layout()
plt.show()
前8列统计描述:
                   0            -2          -2.1            -3            -1  \
count  14970.000000  14970.000000  14970.000000  14970.000000  14970.000000   
mean      -0.867602     -1.022044     -1.174883     -1.057315     -0.926921   
std        4.919823      8.380565     20.082498     11.550257      6.344825   
min     -128.000000   -128.000000   -128.000000   -128.000000    -92.000000   
25%       -3.000000     -3.000000     -3.000000     -3.000000     -3.000000   
50%       -1.000000     -1.000000     -1.000000     -1.000000     -1.000000   
75%        1.000000      2.000000      1.000000      2.000000      1.000000   
max       80.000000     79.000000    127.000000    127.000000    116.000000   

               -2.2          -1.1          -2.3  
count  14970.000000  14970.000000  14970.000000  
mean      -0.824916     -0.888377     -0.901804  
std       10.461558      7.863457     12.304696  
min     -128.000000   -128.000000   -128.000000  
25%       -3.000000     -3.000000     -3.000000  
50%       -1.000000     -1.000000     -1.000000  
75%        1.000000      1.000000      1.000000  
max      127.000000    127.000000    127.000000  
发现缺失值,位置:
 0       354
-2      354
-2.1    354
-3      354
-1      354
-2.2    354
-1.1    354
-2.3    354
dtype: int64
[1/5] 数据加载完成 | 原始数据形状: (15324, 8)
[2/5] 窗口分割完成 | 总窗口数: 305 | 窗口形状: (100, 8)
[3/5] 数据增强完成 | 总样本数: 1830 (原始x6)
[4/5] 形状过滤完成 | 有效样本率: 1830/1830
前8列统计描述:
                  -1          -1.1             2          -1.2          -1.3  \
count  14970.000000  14970.000000  14970.000000  14970.000000  14970.000000   
mean      -1.065531     -0.838009     -2.973747     -0.028925     -0.857916   
std       33.651163     17.704589     49.101199     34.155909     13.400751   
min     -128.000000   -128.000000   -128.000000   -128.000000   -128.000000   
25%       -8.000000     -6.000000    -13.000000     -7.000000     -5.000000   
50%       -1.000000     -1.000000     -1.000000     -1.000000     -1.000000   
75%        6.000000      5.000000      6.000000      6.000000      4.000000   
max      127.000000    127.000000    127.000000    127.000000     89.000000   

                  3             0            -6  
count  14970.000000  14970.000000  14970.000000  
mean      -0.868003     -0.794990     -0.784636  
std       12.125684     12.950926     20.911681  
min      -73.000000   -128.000000   -128.000000  
25%       -6.000000     -6.000000     -5.000000  
50%        0.000000     -1.000000     -1.000000  
75%        5.000000      4.000000      4.000000  
max       85.000000    127.000000    127.000000  
发现缺失值,位置:
 -1      10
-1.1    10
2       10
-1.2    10
-1.3    10
3       10
0       10
-6      10
dtype: int64
[1/5] 数据加载完成 | 原始数据形状: (14980, 8)
[2/5] 窗口分割完成 | 总窗口数: 298 | 窗口形状: (100, 8)
C:\Users\guoxi\AppData\Local\Temp\ipykernel_32276\2631219684.py:22: FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
  df.fillna(method='ffill', inplace=True) # 可以考虑前向填充或均值填充,而非直接删除
C:\Users\guoxi\AppData\Local\Temp\ipykernel_32276\2631219684.py:22: FutureWarning: DataFrame.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
  df.fillna(method='ffill', inplace=True) # 可以考虑前向填充或均值填充,而非直接删除
[3/5] 数据增强完成 | 总样本数: 1788 (原始x6)
[4/5] 形状过滤完成 | 有效样本率: 1788/1788

合并数据集形状: X(3618, 100, 8) y(3618,)

最终数据集:
训练集: (2894, 100, 8) | 0类样本数: 1430
验证集: (724, 100, 8) | 1类样本数: 366

标准化验证 (通道0):
均值: -0.00 (±1.00)

Epoch 1/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 3s 11ms/step - accuracy: 0.6770 - auc: 0.7914 - loss: 0.6707 - val_accuracy: 0.8550 - val_auc: 0.9253 - val_loss: 0.4116
Epoch 2/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.8780 - auc: 0.9416 - loss: 0.3534 - val_accuracy: 0.9047 - val_auc: 0.9750 - val_loss: 0.2717
Epoch 3/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 10ms/step - accuracy: 0.9208 - auc: 0.9734 - loss: 0.2469 - val_accuracy: 0.9171 - val_auc: 0.9774 - val_loss: 0.2604
Epoch 4/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9331 - auc: 0.9800 - loss: 0.2262 - val_accuracy: 0.9240 - val_auc: 0.9843 - val_loss: 0.2364
Epoch 5/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9407 - auc: 0.9854 - loss: 0.2024 - val_accuracy: 0.8950 - val_auc: 0.9773 - val_loss: 0.3147
Epoch 6/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 7ms/step - accuracy: 0.9476 - auc: 0.9869 - loss: 0.1952 - val_accuracy: 0.9475 - val_auc: 0.9922 - val_loss: 0.1946
Epoch 7/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9603 - auc: 0.9913 - loss: 0.1624 - val_accuracy: 0.9365 - val_auc: 0.9888 - val_loss: 0.1864
Epoch 8/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9688 - auc: 0.9949 - loss: 0.1349 - val_accuracy: 0.9461 - val_auc: 0.9916 - val_loss: 0.2021
Epoch 9/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9573 - auc: 0.9940 - loss: 0.1433 - val_accuracy: 0.9530 - val_auc: 0.9930 - val_loss: 0.1688
Epoch 10/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9686 - auc: 0.9961 - loss: 0.1302 - val_accuracy: 0.9586 - val_auc: 0.9923 - val_loss: 0.1617
Epoch 11/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9790 - auc: 0.9965 - loss: 0.1094 - val_accuracy: 0.9392 - val_auc: 0.9856 - val_loss: 0.2092
Epoch 12/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9577 - auc: 0.9913 - loss: 0.1587 - val_accuracy: 0.9544 - val_auc: 0.9940 - val_loss: 0.1531
Epoch 13/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9806 - auc: 0.9967 - loss: 0.1031 - val_accuracy: 0.9475 - val_auc: 0.9821 - val_loss: 0.2452
Epoch 14/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9724 - auc: 0.9960 - loss: 0.1222 - val_accuracy: 0.9489 - val_auc: 0.9899 - val_loss: 0.1961
Epoch 15/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9761 - auc: 0.9973 - loss: 0.1089 - val_accuracy: 0.9544 - val_auc: 0.9881 - val_loss: 0.1804
Epoch 16/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9769 - auc: 0.9974 - loss: 0.1057 - val_accuracy: 0.9461 - val_auc: 0.9922 - val_loss: 0.1801
Epoch 17/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9799 - auc: 0.9970 - loss: 0.1063 - val_accuracy: 0.9503 - val_auc: 0.9909 - val_loss: 0.1773
Epoch 18/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9765 - auc: 0.9982 - loss: 0.1010 - val_accuracy: 0.9599 - val_auc: 0.9907 - val_loss: 0.1759
Epoch 19/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9850 - auc: 0.9987 - loss: 0.0890 - val_accuracy: 0.9641 - val_auc: 0.9941 - val_loss: 0.1507
Epoch 20/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 10ms/step - accuracy: 0.9823 - auc: 0.9970 - loss: 0.1011 - val_accuracy: 0.9599 - val_auc: 0.9937 - val_loss: 0.1587
Epoch 21/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9855 - auc: 0.9992 - loss: 0.0807 - val_accuracy: 0.9655 - val_auc: 0.9944 - val_loss: 0.1463
Epoch 22/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9782 - auc: 0.9980 - loss: 0.0978 - val_accuracy: 0.9599 - val_auc: 0.9914 - val_loss: 0.1650
Epoch 23/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9918 - auc: 0.9992 - loss: 0.0749 - val_accuracy: 0.9530 - val_auc: 0.9963 - val_loss: 0.1473
Epoch 24/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9896 - auc: 0.9991 - loss: 0.0774 - val_accuracy: 0.9599 - val_auc: 0.9959 - val_loss: 0.1497
Epoch 25/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 7ms/step - accuracy: 0.9851 - auc: 0.9988 - loss: 0.0828 - val_accuracy: 0.9627 - val_auc: 0.9921 - val_loss: 0.1506
Epoch 26/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9861 - auc: 0.9989 - loss: 0.0844 - val_accuracy: 0.9544 - val_auc: 0.9846 - val_loss: 0.2111
Epoch 27/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9689 - auc: 0.9974 - loss: 0.1095 - val_accuracy: 0.9682 - val_auc: 0.9963 - val_loss: 0.1233
Epoch 28/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9904 - auc: 0.9994 - loss: 0.0685 - val_accuracy: 0.9613 - val_auc: 0.9930 - val_loss: 0.1476
Epoch 29/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9885 - auc: 0.9993 - loss: 0.0767 - val_accuracy: 0.9572 - val_auc: 0.9852 - val_loss: 0.2071
Epoch 30/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9867 - auc: 0.9993 - loss: 0.0733 - val_accuracy: 0.9489 - val_auc: 0.9862 - val_loss: 0.2118
Epoch 31/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9886 - auc: 0.9989 - loss: 0.0845 - val_accuracy: 0.9627 - val_auc: 0.9915 - val_loss: 0.1829
Epoch 32/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9878 - auc: 0.9989 - loss: 0.0802 - val_accuracy: 0.9586 - val_auc: 0.9929 - val_loss: 0.1528
Epoch 33/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9937 - auc: 0.9998 - loss: 0.0601 - val_accuracy: 0.9558 - val_auc: 0.9923 - val_loss: 0.1799
Epoch 34/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9878 - auc: 0.9972 - loss: 0.0796 - val_accuracy: 0.9489 - val_auc: 0.9874 - val_loss: 0.2116
Epoch 35/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 10ms/step - accuracy: 0.9819 - auc: 0.9981 - loss: 0.0874 - val_accuracy: 0.9586 - val_auc: 0.9904 - val_loss: 0.1581
Epoch 36/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 7ms/step - accuracy: 0.9881 - auc: 0.9983 - loss: 0.0767 - val_accuracy: 0.9724 - val_auc: 0.9960 - val_loss: 0.1170
Epoch 37/100
91/91 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.9895 - auc: 0.9995 - loss: 0.0708 - val_accuracy: 0.9599 - val_auc: 0.9914 - val_loss: 0.1595

智能康复评估报告核心分析


​1. 康复效果评估​
  • ​平均康复指数​​:​​99.8%​​,表明患者的整体运动功能已接近健康水平,康复效果显著。
  • ​最佳窗口表现​​:​​20.2%​​(局部动作表现优异,可能为特定动作的极限恢复)。
  • ​最弱窗口表现​​:​​0.0%​​(存在个别动作或时间段的功能未恢复,需针对性分析)。

​2. 模型性能分析​
  • ​验证集指标​​:
    • ​准确率(Accuracy)​​:稳定在 ​​1.00​​(完全正确分类)。
    • ​AUC​​:​​1.00​​(完美区分健康与患者动作)。
    • ​损失值(Loss)​​:趋近于 ​​0​​(模型收敛彻底)。
  • ​过拟合风险​​:
    • 训练集与验证集指标完全一致(AUC=1.0),提示模型可能过度依赖训练数据特征,需警惕对未知数据的泛化能力。

​3. 关键建议​
  1. ​临床建议​​:
    • ✅ ​​维持现有训练计划​​(当前康复效果已达最佳状态)。
    • 🔍 ​​重点监测最弱窗口​​(0.0%动作):需排查是否为传感器异常、患者疲劳或特定动作的神经控制障碍。
  2. ​模型优化方向​​:
    • 增加 ​​异常动作样本​​ 的采集与训练,提升对低康复指数窗口的识别能力。
    • 引入 ​​不确定性评估​​(如预测置信度),避免对极端值过度敏感。

​4. 潜在问题预警​
  • ​数据偏差​​:最弱窗口(0.0%)与最佳窗口(20.2%)差异显著,可能反映数据采集或标注异常(如动作未正确执行)。
  • ​模型泛化瓶颈​​:完美指标可能掩盖对真实场景复杂性的适应不足,建议在独立测试集上补充验证。

总结

当前康复效果已达到顶尖水平(99.8%),但需关注局部异常动作的成因。模型性能优秀但存在过拟合风险,建议持续监控患者动作多样性并优化数据采集流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2396634.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙next系统以后会取代安卓吗?

点击上方关注 “终端研发部” 设为“星标”&#xff0c;和你一起掌握更多数据库知识 官方可没说过取代谁谁&#xff0c;三足鼎立不好吗&#xff1f;三分天下&#xff0c;并立共存。 鸿蒙基于Linux&#xff0c;有人说套壳&#xff1b;ios/macos基于Unix&#xff0c;说它ios开源了…

PolyGen:一个用于 3D 网格的自回归生成模型 论文阅读

[2002.10880] PolyGen&#xff1a;一个用于 3D 网格的自回归生成模型 --- [2002.10880] PolyGen: An Autoregressive Generative Model of 3D Meshes 图 2&#xff1a;PolyGen 首先生成网格顶点&#xff08;左侧&#xff09;&#xff0c;然后基于这些顶点生成网格面&#xff0…

系统思考:成长与投资不足

最近认识了一位95后年轻创业者&#xff0c;短短2年时间&#xff0c;他的公司从十几个人发展到几百人&#xff0c;规模迅速扩大。随着团队壮大&#xff0c;用户池也在持续扩大&#xff0c;但令人困惑的是&#xff0c;业绩增长却没有明显提升&#xff0c;甚至人效持续下滑。尽管公…

快手可灵视频V1.6模型API如何接入免费AI开源项目工具

全球领先的视频生成大模型&#xff1a;可灵是首个效果对标 Sora 、面向用户开放的视频生成大模型&#xff0c;目前在国内及国际上均处于领先地位。快手视频生成大模型“可灵”&#xff08;Kling&#xff09;&#xff0c;是全球首个真正用户可用的视频生成大模型&#xff0c;自面…

数学建模期末速成 最短路径

关键词&#xff1a;Dijkstra算法 Floyd算法 例题 已知有6个村庄&#xff0c;各村的小学生人数如表所列&#xff0c;各村庄间的距离如图所示。现在计划建造一所医院和一所小学&#xff0c;问医院应建在哪个村庄才能使最远村庄的人到医院看病所走的路最短&#xff1f;又问小学建…

Java开发经验——阿里巴巴编码规范实践解析7

摘要 本文主要解析了阿里巴巴 Java 开发中的 SQL 编码规范&#xff0c;涉及 SQL 查询优化、索引建立、字符集选择、分页查询处理、外键与存储过程的使用等多个方面&#xff0c;旨在帮助开发者提高代码质量和数据库操作性能&#xff0c;避免常见错误和性能陷阱。 1. 【强制】业…

权威认证与质量保障:第三方检测在科技成果鉴定测试中的核心作用

科技成果鉴定测试是衡量科研成果技术价值与应用潜力的关键环节&#xff0c;其核心目标在于通过科学验证确保成果的可靠性、创新性和市场适配性。第三方检测机构凭借其独立性、专业性和权威性&#xff0c;成为科技成果鉴定测试的核心支撑主体。本文从测试流程、第三方检测的价值…

Perforce P4产品简介:无限扩展+全球协作+安全管控+工具集成(附下载)

本产品简介由Perforce中国授权合作伙伴——龙智编辑整理&#xff0c;旨在带您快速了解Perforce P4版本控制系统的强大之处。 世界级无限可扩展的版本控制系统 Perforce P4&#xff08;原Helix Core&#xff09;是业界领先的版本控制平台&#xff0c;备受19家全球Top20 AAA级游…

网络协议入门:TCP/IP五层模型如何实现全球数据传输?

&#x1f50d; 开发者资源导航 &#x1f50d;&#x1f3f7;️ 博客主页&#xff1a; 个人主页&#x1f4da; 专栏订阅&#xff1a; JavaEE全栈专栏 内容&#xff1a; 网络初识什么是网络&#xff1f;关键概念认识协议五元组 协议分层OSI七层模型TCP/IP五层&#xff08;四层&…

Docker安装Redis集群(3主3从+动态扩容、缩容)保姆级教程含踩坑及安装中遇到的问题解决

前言 部署集群前&#xff0c;我们需要先掌握Redis分布式存储的核心算法。了解这些算法能帮助我们在实际工作中做出合理选择&#xff0c;同时清晰认识各方案的优缺点。 一、分布式存储算法 我们通过一道大厂面试题来进行阐述。 如下&#xff1a;1-2亿条数据需要缓存&#xff…

企业级 AI 开发新范式:Spring AI 深度解析与实践

一、Spring AI 的核心架构与设计哲学 1.1 技术定位与价值主张 Spring AI 作为 Spring 生态系统的重要组成部分&#xff0c;其核心使命是将人工智能能力无缝注入企业级 Java 应用。它通过标准化的 API 抽象和 Spring Boot 的自动装配机制&#xff0c;让开发者能够以熟悉的 Spr…

如何用docker部署ELK?

环境&#xff1a; ELK 8.8.0 Ubuntu20.04 问题描述&#xff1a; 如何用docker部署ELK&#xff1f; 解决方案&#xff1a; 一、环境准备 &#xff08;一&#xff09;主机设置 安装 Docker Engine &#xff1a;版本需为 18.06.0 或更新。可通过命令 docker --version 检查…

Redis最佳实践——安全与稳定性保障之高可用架构详解

全面详解 Java 中 Redis 在电商应用的高可用架构设计 一、高可用架构核心模型 1. 多层级高可用体系 #mermaid-svg-Ffzq72Onkv7wgNKQ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Ffzq72Onkv7wgNKQ .error-icon{f…

【Python 算法零基础 4.排序 ⑥ 快速排序】

既有锦绣前程可奔赴&#xff0c;亦有往日岁月可回首 —— 25.5.25 选择排序回顾 ① 遍历数组&#xff1a;从索引 0 到 n-1&#xff08;n 为数组长度&#xff09;。 ② 每轮确定最小值&#xff1a;假设当前索引 i 为最小值索引 min_index。从 i1 到 n-1 遍历&#xff0c;若找到…

Go 即时通讯系统:日志模块重构,并从main函数开始

重构logger 上次写的logger.go过于繁琐&#xff0c;有很多没用到的功能&#xff1b;重构后只提供了简洁的日志接口&#xff0c;支持日志轮转、多级别日志记录等功能&#xff0c;并采用单例模式确保全局只有一个日志实例 全局变量 var (once sync.Once // 用于实现…

MYSQL MGR高可用

1&#xff0c;MYSQL MGR高可用是什么 简单来说&#xff0c;MySQL MGR 的核心目标就是&#xff1a;确保数据库服务在部分节点&#xff08;服务器&#xff09;发生故障时&#xff0c;整个数据库集群依然能够继续提供读写服务&#xff0c;最大限度地减少停机时间。 2. 核心优势 v…

阿里通义实验室突破空间音频新纪元!OmniAudio让360°全景视频“声”临其境

在虚拟现实和沉浸式娱乐快速发展的今天&#xff0c;视觉体验已经远远不够&#xff0c;声音的沉浸感成为打动用户的关键。然而&#xff0c;传统的视频配音技术往往停留在“平面”的音频层面&#xff0c;难以提供真正的空间感。阿里巴巴通义实验室&#xff08;Qwen Lab&#xff0…

异步上传石墨文件进度条前端展示记录(采用Redis中String数据结构实现-苏东坡版本)

昔者&#xff0c;有客临门&#xff0c;亟需自石墨文库中撷取卷帙若干。此等文册&#xff0c;非止一卷&#xff0c;乃累牍连篇&#xff0c;亟需批量转置。然吾辈虑及用户体验&#xff0c;当效东坡"腹有诗书气自华"之雅意&#xff0c;使操作如行云流水&#xff0c;遂定…

处理知识库文件_编写powershell脚本文件_批量转换其他格式文件到pdf文件---人工智能工作笔记0249

最近在做部门知识库&#xff0c;选用的dify&#xff0c;作为rag的工具&#xff0c;但是经过多个对比&#xff0c;最后发现&#xff0c; 比较好用的是&#xff0c;纳米搜索&#xff0c;但是可惜纳米搜索无法在内网使用&#xff0c;无法把知识库放到本地&#xff0c;导致 有信息…

rtpmixsound:实现音频混音攻击!全参数详细教程!Kali Linux教程!

简介 一种将预先录制的音频与指定目标音频流中的音频&#xff08;即 RTP&#xff09;实时混合的工具。 一款用于将预先录制的音频与指定目标音频流中的音频&#xff08;即 RTP&#xff09;实时混合的工具。该工具创建于 2006 年 8 月至 9 月之间。该工具名为 rtpmixsound。它…