295. Find Median from Data Stream

本文介绍了一种使用优先队列(最大堆和最小堆)动态维护数据流中位数的算法。通过Stefan大神的思路,我们将数据分为两部分,较小的部分放入最大堆,较大的部分放入最小堆。当数据流中有新数加入时,我们将其添加到最大堆,然后将最大堆的顶部元素移动到最小堆,以保持两个堆之间的平衡。这样,我们可以确保任何时候都能快速找到中位数。

1. 思路

思路参考自Stefan大神。需要动态地知道数组中间的两个数的大小,优先队列正好在push一个数的时候可以动态地调整 数的位置,每次插入操作是O(logn)。考虑把当前插入的数分成两份,小的一份放在small队列里,大的一份放在large队列里。small是个最大堆,large是个最小堆,addnum时把收到的数先放到small,再把small中的最大数pop出来放到large。若large的元素个数大于small元素的个数,则把large中最小的数放到small,此时small中最大的数即为所求;若两个队列元素数目相等,将large最小和small的最大取平均即可。

2. AC代码

注意两个队列是全局变量,要定义在函数外面。

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    priority_queue<int> small, large;
    void addNum(int num) {
        small.push(num);
        large.push(-small.top());
        small.pop();
        if(small.size() < large.size()){
            small.push(-large.top());
            large.pop();
        }
    }
    
    double findMedian() {
        return small.size() > large.size() ? small.top() : (small.top() - large.top()) / 2.0;
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */

 

import os import re import pandas as pd import numpy as np import tensorflow as tf from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.model_selection import train_test_split from tensorflow.keras.layers import Input, Dense, Concatenate, Multiply, GlobalAveragePooling1D, Conv1D from tensorflow.keras.models import Model from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau import matplotlib.pyplot as plt import seaborn as sns from sklearn.metrics import confusion_matrix # --------------------------- # 1. 数据加载与完整性验证 (支持Excel) # --------------------------- def find_gait_data_files(data_dir='gait_data'): """自动发现所有步态数据文件(支持Excel和CSV)""" file_map = {} patterns = [ r'koa_?(\w+)\.(xlsx|xls|csv|npy)', # koa_t25.xlsx 或 koat25.csv r'KOA_?(\w+)\.(xlsx|xls|csv|npy)', # KOA_T25.xlsx r'patient_?(\w+)\.(xlsx|xls|csv|npy)', # patient_t25.xlsx r'(\w+)_gait\.(xlsx|xls|csv|npy)' # t25_gait.xlsx ] for filename in os.listdir(data_dir): for pattern in patterns: match = re.match(pattern, filename, re.IGNORECASE) if match: patient_id = match.group(1) file_ext = match.group(2).lower() file_map[patient_id.lower()] = os.path.join(data_dir, filename) break return file_map def load_gait_data(file_path): """从文件加载步态数据(支持Excel、CSV和NPY)""" if file_path.endswith('.npy'): return np.load(file_path) # 处理Excel和CSV文件 try: if file_path.endswith(('.xlsx', '.xls')): df = pd.read_excel(file_path, header=None) elif file_path.endswith('.csv'): df = pd.read_csv(file_path, header=None) else: raise ValueError(f"不支持的步态文件格式: {file_path}") # 转换为NumPy数组并确保数值类型 gait_data = df.values.astype(np.float32) # 验证数据维度(至少10列) if gait_data.shape[1] < 10: raise ValueError(f"步态数据列数不足(需要至少10列): {file_path}") return gait_data except Exception as e: print(f"加载步态数据错误: {file_path} - {str(e)}") return None def load_and_validate_data(metadata_path='patient_metadata.csv', data_dir='gait_data'): """加载并验证数据完整性(支持Excel步态数据)""" # 加载元数据 metadata = pd.read_csv(metadata_path, encoding='utf-8-sig') # 清理患者ID metadata['clean_id'] = metadata['patient_id'].apply( lambda x: re.sub(r'[^\w]', '', str(x)).lower() ) # 获取步态文件映射 gait_file_map = find_gait_data_files(data_dir) # 添加文件路径到元数据 metadata['gait_path'] = metadata['clean_id'].map(gait_file_map) # 标记缺失数据 metadata['data_complete'] = metadata['gait_path'].notnull() # 分离完整和不完整数据 complete_data = metadata[metadata['data_complete']].copy() incomplete_data = metadata[~metadata['data_complete']].copy() print(f"总患者数: {len(metadata)}") print(f"完整数据患者: {len(complete_data)}") print(f"缺失步态数据患者: {len(incomplete_data)}") if not incomplete_data.empty: print("\n缺失步态数据的患者:") print(incomplete_data[['patient_id', 'koa_grade']].to_string(index=False)) incomplete_data.to_csv('incomplete_records.csv', index=False) return complete_data # --------------------------- # 2. 特征工程 (支持Excel步态数据) # --------------------------- def preprocess_static_features(metadata): """预处理静态元数据特征""" # 定义特征类型 numeric_features = ['age', 'height_cm', 'weight_kg', 'bmi'] categorical_features = ['gender', 'dominant_leg', 'affected_side'] # 确保所有列存在 for col in numeric_features + categorical_features: if col not in metadata.columns: metadata[col] = np.nan # 填充缺失值 metadata[numeric_features] = metadata[numeric_features].fillna(metadata[numeric_features].median()) metadata[categorical_features] = metadata[categorical_features].fillna('unknown') # 创建预处理管道 preprocessor = ColumnTransformer( transformers=[ ('num', StandardScaler(), numeric_features), ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features) ], remainder='drop' # 只处理指定特征 ) # 应用预处理 static_features = preprocessor.fit_transform(metadata) feature_names = ( numeric_features + list(preprocessor.named_transformers_['cat'].get_feature_names_out(categorical_features)) ) return static_features, feature_names def extract_gait_features(gait_path): """从步态数据中提取特征(支持Excel)""" gait_data = load_gait_data(gait_path) if gait_data is None: raise ValueError(f"无法加载步态数据: {gait_path}") # 1. 时域特征 mean_values = np.mean(gait_data, axis=0) std_values = np.std(gait_data, axis=0) max_values = np.max(gait_data, axis=0) min_values = np.min(gait_data, axis=0) # 2. 频域特征 (FFT) fft_values = np.abs(np.fft.rfft(gait_data, axis=0)) dominant_freq = np.argmax(fft_values, axis=0) spectral_energy = np.sum(fft_values ** 2, axis=0) # 3. 生物力学特征 # 左右腿不对称性 (假设前5列为右腿,后5列为左腿) num_columns = gait_data.shape[1] if num_columns >= 10: # 标准情况:10列数据 asymmetry_index = np.mean(np.abs(gait_data[:, :5] - gait_data[:, 5:10]), axis=0) else: # 非标准情况:使用可用列 half_cols = num_columns // 2 asymmetry_index = np.mean(np.abs(gait_data[:, :half_cols] - gait_data[:, half_cols:half_cols * 2]), axis=0) # 关节协调性 (髋-膝相位差) if num_columns >= 8: hip_knee_phase_diff = np.arctan2(gait_data[:, 2], gait_data[:, 1]) - np.arctan2(gait_data[:, 7], gait_data[:, 6]) phase_diff_mean = np.mean(hip_knee_phase_diff) phase_diff_std = np.std(hip_knee_phase_diff) else: phase_diff_mean = 0.0 phase_diff_std = 0.0 # 步态周期对称性 if num_columns >= 10: gait_cycle_symmetry = np.corrcoef(gait_data[:, :5].flatten(), gait_data[:, 5:10].flatten())[0, 1] elif num_columns >= 4: gait_cycle_symmetry = np.corrcoef(gait_data[:, :2].flatten(), gait_data[:, 2:4].flatten())[0, 1] else: gait_cycle_symmetry = 0.0 # 组合所有特征 gait_features = np.concatenate([ mean_values, std_values, max_values, min_values, dominant_freq, spectral_energy, asymmetry_index, [phase_diff_mean, phase_diff_std, gait_cycle_symmetry] ]) # 特征名称 base_names = [f'Ch_{i}' for i in range(num_columns)] feature_names = [] for prefix in ['mean_', 'std_', 'max_', 'min_']: feature_names.extend([prefix + name for name in base_names]) feature_names.extend(['dom_freq_' + name for name in base_names]) feature_names.extend(['spec_energy_' + name for name in base_names]) if num_columns >= 10: asym_names = ['R.Hip_AP', 'R.Knee_Moment', 'R.KneeFlex', 'R.Gluteus', 'R.Vastus', 'L.Hip_AP', 'L.Knee_Moment', 'L.KneeFlex', 'L.Gluteus', 'L.Vastus'] feature_names.extend(['asym_' + name for name in asym_names]) else: feature_names.extend([f'asym_{i}' for i in range(len(asymmetry_index))]) feature_names.extend(['phase_diff_mean', 'phase_diff_std', 'gait_symmetry']) return gait_features, feature_names def biomechanical_feature_enhancement(static_df, gait_features): """基于临床知识的特征增强""" enhanced_features = gait_features.copy() # 获取BMI值(如果存在) if 'bmi' in static_df.columns: bmi = static_df['bmi'].values[0] bmi_factor = 1 + (bmi - 25) * 0.01 # 每增加1 BMI单位增加1%肌肉力量 else: bmi_factor = 1.0 # 肌肉力量通道索引 num_features = len(gait_features) if num_features > 50: # 标准特征数量 muscle_indices = [3, 4, 8, 9] # 肌肉相关特征索引 else: # 非标准特征数量,使用启发式方法 muscle_indices = [i for i in range(40, 50) if i < num_features] for idx in muscle_indices: # 应用BMI调整 enhanced_features[idx] *= bmi_factor # 获取年龄(如果存在) if 'age' in static_df.columns: age = static_df['age'].values[0] stability_factor = max(0.8, 1 - (age - 60) * 0.005) # 60岁以上每岁减少0.5%稳定性 else: stability_factor = 1.0 # 稳定性相关特征 stability_indices = [] if num_features > 50: stability_indices = [1, 6, 40, 45, 50, 55, num_features - 3, num_features - 2, num_features - 1] else: # 尝试找到稳定性相关特征 stability_indices = [i for i in range(num_features - 5, num_features)] for idx in stability_indices: enhanced_features[idx] *= stability_factor return enhanced_features # --------------------------- # 3. 特征融合模型 (保持不变) # --------------------------- def create_fusion_model(static_dim, gait_dim, num_classes): """创建特征融合模型""" # 输入层 static_input = Input(shape=(static_dim,), name='static_input') gait_input = Input(shape=(gait_dim,), name='gait_input') # 静态特征处理 static_stream = Dense(64, activation='relu')(static_input) static_stream = Dense(32, activation='relu')(static_stream) # 步态特征处理 gait_stream = Dense(128, activation='relu')(gait_input) gait_stream = Dense(64, activation='relu')(gait_stream) # 注意力融合机制 attention_scores = Dense(64, activation='sigmoid')(gait_stream) attended_static = Multiply()([static_stream, attention_scores]) # 特征融合 fused = Concatenate()([attended_static, gait_stream]) # 分类层 x = Dense(128, activation='relu')(fused) x = Dense(64, activation='relu')(x) output = Dense(num_classes, activation='softmax', name='koa_grade')(x) return Model(inputs=[static_input, gait_input], outputs=output) def create_1d_cnn_fusion_model(static_dim, gait_timesteps, gait_channels, num_classes): """创建包含原始时间序列的融合模型""" # 输入层 static_input = Input(shape=(static_dim,), name='static_input') gait_input = Input(shape=(gait_timesteps, gait_channels), name='gait_input') # 静态特征处理 static_stream = Dense(64, activation='relu')(static_input) static_stream = Dense(32, activation='relu')(static_stream) # 时间序列特征提取 gait_stream = Conv1D(64, 7, activation='relu', padding='same')(gait_input) gait_stream = Conv1D(128, 5, activation='relu', padding='same')(gait_stream) gait_stream = GlobalAveragePooling1D()(gait_stream) # 特征融合 fused = Concatenate()([static_stream, gait_stream]) # 分类层 x = Dense(128, activation='relu')(fused) x = Dense(64, activation='relu')(x) output = Dense(num_classes, activation='softmax', name='koa_grade')(x) return Model(inputs=[static_input, gait_input], outputs=output) # --------------------------- # 4. 训练与评估 (支持Excel步态数据) # --------------------------- def train_model(metadata, model_type='features'): """训练特征融合模型(支持Excel步态数据)""" # 预处理静态特征 static_features, static_feature_names = preprocess_static_features(metadata) # 提取步态特征 gait_features_list = [] gait_feature_names = None gait_data_list = [] # 原始时间序列数据 for idx, row in metadata.iterrows(): gait_path = row['gait_path'] try: gait_features, gait_feature_names = extract_gait_features(gait_path) # 应用生物力学增强 enhanced_features = biomechanical_feature_enhancement(row.to_frame().T, gait_features) gait_features_list.append(enhanced_features) # 保存原始时间序列数据(用于CNN模型) gait_data = load_gait_data(gait_path) gait_data_list.append(gait_data) except Exception as e: print(f"处理患者 {row['patient_id']} 的步态数据时出错: {str(e)}") continue if not gait_features_list: raise ValueError("无法提取任何步态特征,请检查数据格式") gait_features = np.array(gait_features_list) # 目标变量 y = metadata['koa_grade'].values num_classes = len(np.unique(y)) # 划分训练测试集 X_static_train, X_static_test, X_gait_train, X_gait_test, y_train, y_test = train_test_split( static_features, gait_features, y, test_size=0.2, random_state=42, stratify=y ) # 创建模型 if model_type == 'features': model = create_fusion_model( static_dim=static_features.shape[1], gait_dim=gait_features.shape[1], num_classes=num_classes ) train_input = [X_static_train, X_gait_train] test_input = [X_static_test, X_gait_test] else: # 使用原始时间序列 # 填充时间序列到相同长度 max_timesteps = max(len(data) for data in gait_data_list) X_gait_padded = np.array([np.pad(data, ((0, max_timesteps - len(data)), (0, 0)), 'constant') for data in gait_data_list]) # 重新划分数据集 X_static_train, X_static_test, X_gait_train, X_gait_test, y_train, y_test = train_test_split( static_features, X_gait_padded, y, test_size=0.2, random_state=42, stratify=y ) model = create_1d_cnn_fusion_model( static_dim=static_features.shape[1], gait_timesteps=X_gait_padded.shape[1], gait_channels=X_gait_padded.shape[2], num_classes=num_classes ) train_input = [X_static_train, X_gait_train] test_input = [X_static_test, X_gait_test] # 编译模型 model.compile( optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'] ) # 训练模型 history = model.fit( train_input, y_train, validation_split=0.1, epochs=100, batch_size=16, callbacks=[ EarlyStopping(patience=20, restore_best_weights=True), ReduceLROnPlateau(factor=0.5, patience=10) ] ) # 评估模型 test_loss, test_acc = model.evaluate(test_input, y_test) print(f"\n测试准确率: {test_acc:.4f}") # 特征重要性分析 if model_type == 'features': analyze_feature_importance(model, X_static_test, X_gait_test, y_test, static_feature_names, gait_feature_names) return model, history def analyze_feature_importance(model, X_static, X_gait, y_true, static_names, gait_names): """分析特征重要性""" # 获取模型预测 y_pred = model.predict([X_static, X_gait]) y_pred_classes = np.argmax(y_pred, axis=1) # 计算混淆矩阵 cm = confusion_matrix(y_true, y_pred_classes) plt.figure(figsize=(10, 8)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=["G0", "G1", "G2", "G3", "G4"], yticklabels=["G0", "G1", "G2", "G3", "G4"]) plt.xlabel('预测分级') plt.ylabel('真实分级') plt.title('KL分级混淆矩阵') plt.savefig('confusion_matrix.png', dpi=300) plt.close() # SHAP特征重要性分析 try: import shap # 创建解释器 background = [X_static[:50], X_gait[:50]] explainer = shap.KernelExplainer(model.predict, background) # 计算SHAP值 shap_values = explainer.shap_values(background) # 组合特征名称 all_feature_names = static_names + gait_names # 可视化 plt.figure(figsize=(12, 8)) shap.summary_plot(shap_values, features=np.hstack(background), feature_names=all_feature_names, plot_type='bar') plt.tight_layout() plt.savefig('feature_importance.png', dpi=300) plt.close() except ImportError: print("SHAP库未安装,跳过特征重要性分析") # --------------------------- # 5. 主工作流程 (支持Excel步态数据) # --------------------------- def main(): print("=" * 50) print("KOA分级诊疗平台 - 特征融合系统 (支持Excel步态数据)") print("=" * 50) # 步骤1: 加载并验证数据 print("\n[步骤1] 加载数据并验证完整性...") complete_data = load_and_validate_data() if len(complete_data) < 20: print("\n错误: 完整数据样本不足,无法训练模型") return # 步骤2: 训练特征融合模型 print("\n[步骤2] 训练特征融合模型...") print("选项1: 使用提取的特征 (更快)") print("选项2: 使用原始时间序列 (更准确)") choice = input("请选择模型类型 (1/2): ").strip() model_type = 'features' if choice == '1' else 'time_series' model, history = train_model(complete_data, model_type) # 保存模型 model.save(f'koa_fusion_model_{model_type}.h5') print(f"模型已保存为 koa_fusion_model_{model_type}.h5") # 绘制训练历史 plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.plot(history.history['accuracy'], label='训练准确率') plt.plot(history.history['val_accuracy'], label='验证准确率') plt.title('模型准确率') plt.ylabel('准确率') plt.xlabel('Epoch') plt.legend() plt.subplot(1, 2, 2) plt.plot(history.history['loss'], label='训练损失') plt.plot(history.history['val_loss'], label='验证损失') plt.title('模型损失') plt.ylabel('损失') plt.xlabel('Epoch') plt.legend() plt.tight_layout() plt.savefig('training_history.png', dpi=300) print("训练历史图已保存为 training_history.png") print("\n特征融合模型训练完成!") if __name__ == "__main__": main() 上面是源代码,下面是报错,我是小白,你尽可能简单的手把手教我在原代码上怎么修改File "C:\Users\14816\Desktop\untitled1\yuchuli.py", line 524, in <module> main() File "C:\Users\14816\Desktop\untitled1\yuchuli.py", line 479, in main complete_data = load_and_validate_data() ^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\14816\Desktop\untitled1\yuchuli.py", line 80, in load_and_validate_data gait_file_map = find_gait_data_files(data_dir) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\14816\Desktop\untitled1\yuchuli.py", line 31, in find_gait_data_files for filename in os.listdir(data_dir): ^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'gait_data' ================================================== KOA分级诊疗平台 - 特征融合系统 (支持Excel步态数据) ==================================================
最新发布
07-25
<think>我们遇到了一个错误:FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'gait_data' 这个错误发生在函数`find_gait_data_files`中,当尝试遍历`data_dir`目录时。错误的原因是目录`gait_data`不存在。 解决方案: 1. 确保在运行脚本的目录下存在名为`gait_data`的文件夹,并且里面包含步态数据文件。 2. 或者,我们可以修改代码,使用绝对路径来指定`gait_data`目录的位置。 由于之前我们讨论过路径问题,并且知道项目在`C:\Users\14816\Desktop\untitled1\`,我们可以将`gait_data`目录的路径设置为绝对路径。 修改`load_and_validate_data`函数中的`data_dir`参数,使其为绝对路径。或者,我们可以修改`find_gait_data_files`函数,使其能够处理相对路径并转换为绝对路径。 但是,为了确保代码的健壮性,我们可以使用当前脚本所在的目录来构建`gait_data`目录的绝对路径。 具体修改如下: 在`load_and_validate_data`函数中,我们将`data_dir`参数默认值改为使用绝对路径。同时,我们也修改`find_gait_data_files`函数,使其能够处理绝对路径。 然而,错误发生在`find_gait_data_files`函数内部,因为它尝试遍历的`data_dir`目录不存在。因此,我们需要在调用`os.listdir(data_dir)`之前检查目录是否存在。 但是,更根本的问题是,我们传递给`find_gait_data_files`的`data_dir`是相对路径,而当前工作目录可能不是我们期望的。 因此,我们将修改整个项目,使用基于脚本所在目录的绝对路径。 具体步骤: 1. 在`main`函数中,我们获取当前脚本所在的目录(`__file__`的目录)。 2. 然后,构建`gait_data`目录的绝对路径。 3. 将构建的绝对路径传递给`load_and_validate_data`函数。 但是,我们也可以修改`load_and_validate_data`函数,使其接受一个绝对路径,或者自己构建绝对路径。 由于代码中`load_and_validate_data`函数有一个`data_dir`参数,我们可以修改这个参数的默认值,但为了灵活性,我们将在`main`函数中构建绝对路径并传递。 修改`main`函数: 在`main`函数中,我们首先获取当前脚本所在的目录,然后构建`gait_data`目录和`patient_metadata.csv`文件的绝对路径。 修改后的`main`函数如下: ```python def main(): print("=" * 50) print("KOA分级诊疗平台 - 特征融合系统 (支持Excel步态数据)") print("=" * 50) # 获取当前脚本所在的目录 script_dir = os.path.dirname(os.path.abspath(__file__)) # 构建数据目录的绝对路径 data_dir = os.path.join(script_dir, "gait_data") metadata_path = os.path.join(script_dir, "patient_metadata.csv") print(f"当前工作目录: {os.getcwd()}") print(f"脚本所在目录: {script_dir}") print(f"步态数据目录: {data_dir}") print(f"元数据文件: {metadata_path}") # 步骤1: 加载并验证数据 print("\n[步骤1] 加载数据并验证完整性...") # 将绝对路径传递给函数 complete_data = load_and_validate_data(metadata_path=metadata_path, data_dir=data_dir) # ... 其余代码保持不变 ... ``` 同时,我们需要修改`load_and_validate_data`函数,使其接受两个参数:`metadata_path`和`data_dir`,并且不再使用默认值(或者保留默认值但使用我们传递的绝对路径)。 另外,在`find_gait_data_files`函数中,我们添加目录存在性检查: ```python def find_gait_data_files(data_dir): """自动发现所有步态数据文件(支持Excel和CSV)""" # 检查目录是否存在 if not os.path.exists(data_dir): raise FileNotFoundError(f"步态数据目录不存在: {data_dir}") if not os.path.isdir(data_dir): raise NotADirectoryError(f"指定的路径不是目录: {data_dir}") file_map = {} patterns = [ r'koa_?(\w+)\.(xlsx|xls|csv|npy)', # koa_t25.xlsx 或 koat25.csv r'KOA_?(\w+)\.(xlsx|xls|csv|npy)', # KOA_T25.xlsx r'patient_?(\w+)\.(xlsx|xls|csv|npy)', # patient_t25.xlsx r'(\w+)_gait\.(xlsx|xls|csv|npy)' # t25_gait.xlsx ] for filename in os.listdir(data_dir): # ... 匹配模式 ... ``` 但是,我们已经在`load_and_validate_data`函数中调用了`find_gait_data_files`,所以如果目录不存在,我们需要捕获异常并处理。 另外,在`load_and_validate_data`函数中,我们使用传递的`metadata_path`来加载元数据。 修改`load_and_validate_data`函数: ```python def load_and_validate_data(metadata_path, data_dir): """加载并验证数据完整性(支持Excel步态数据)""" # 加载元数据 metadata = pd.read_csv(metadata_path, encoding='utf-8-sig') # ... 其余代码保持不变 ... ``` 这样,我们就将路径都转换为绝对路径,并且确保在目录不存在时给出明确的错误信息。 由于修改涉及多个函数,下面是需要修改的代码部分: 1. 修改`main`函数,获取脚本目录并构建路径。 2. 修改`load_and_validate_data`函数,去掉默认值,使用传递的参数。 3. 修改`find_gait_data_files`函数,添加目录存在性检查。 注意:原代码中`load_and_validate_data`函数有两个参数,但调用时只传递了`data_dir`,现在我们要传递两个参数:`metadata_path`和`data_dir`。 另外,原代码中`load_and_validate_data`函数的定义是: def load_and_validate_data(metadata_path='patient_metadata.csv', data_dir='gait_data'): 现在我们要去掉默认值,因为我们在`main`函数中已经构建了绝对路径,并显式传递。 但是,为了保持代码的灵活性(比如在其他地方调用时),我们可以保留默认值,但将默认值改为基于当前目录的绝对路径?或者我们就在`main`函数中传递绝对路径。 考虑到我们已经在`main`函数中构建了绝对路径,我们修改`load_and_validate_data`函数,使其接受两个参数,并且不改变函数签名(即保留默认值)可能会更好,因为其他地方可能调用。但为了修复错误,我们直接传递绝对路径,所以默认值不会被使用。 因此,我们选择: 在`main`函数中构建绝对路径,然后传递给`load_and_validate_data`。 修改后的`main`函数如上所述。 同时,我们修改`find_gait_data_files`函数,在开始处添加目录存在性检查。 由于代码较长,我们只修改相关部分。 请按照以下步骤修改代码: 1. 在`main`函数中,添加获取脚本目录和构建绝对路径的代码。 2. 修改`load_and_validate_data`的调用,传递两个绝对路径参数。 3. 在`find_gait_data_files`函数开头,添加目录存在性检查。 我们尝试运行,如果目录不存在,程序会抛出异常并提示。 另外,我们还可以在`load_and_validate_data`函数中,如果发现目录不存在,则创建目录(但需要根据实际需求,因为可能是路径错误,所以创建目录可能不是最佳选择)。这里我们选择抛出异常。 修改后的代码部分如下(只展示修改部分): 在`main`函数中: ```python def main(): print("=" * 50) print("KOA分级诊疗平台 - 特征融合系统 (支持Excel步态数据)") print("=" * 50) # 获取当前脚本所在的目录 script_dir = os.path.dirname(os.path.abspath(__file__)) # 构建数据目录的绝对路径 data_dir = os.path.join(script_dir, "gait_data") metadata_path = os.path.join(script_dir, "patient_metadata.csv") # 步骤1: 加载并验证数据 print("\n[步骤1] 加载数据并验证完整性...") complete_data = load_and_validate_data(metadata_path=metadata_path, data_dir=data_dir) # ... 其余代码 ... ``` 在`find_gait_data_files`函数开头添加: ```python def find_gait_data_files(data_dir): """自动发现所有步态数据文件(支持Excel和CSV)""" # 检查目录是否存在 if not os.path.exists(data_dir): raise FileNotFoundError(f"步态数据目录不存在: {data_dir}") if not os.path.isdir(data_dir): raise NotADirectoryError(f"指定的路径不是目录: {data_dir}") # ... 原有的模式匹配代码 ... ``` 这样修改后,如果`gait_data`目录不存在,程序会立即报错并停止,避免后续错误。 另外,请确保在项目目录下存在`gait_data`文件夹,并且里面有步态数据文件。 同时,元数据文件`patient_metadata.csv`也应该放在项目目录(即脚本所在目录)下。 如果目录结构如下: ``` C:\Users\14816\Desktop\untitled1\ ├── yuchuli.py ├── patient_metadata.csv └── gait_data\ ├── koa_t25.xlsx ├── patient_123.xlsx └── ... ``` 这样修改后,程序应该能正确找到目录。 如果还有问题,我们可以添加打印语句来调试路径。 注意:在`load_and_validate_data`函数中,我们打印缺失数据时,可能会因为路径错误而找不到文件。现在使用绝对路径,应该能正确匹配。 让我们修改代码并运行。 由于代码较长,我无法直接运行你的环境,所以请按照上述说明修改。 修改后,如果仍然报错,请检查打印出的路径是否正确。 另外,在`load_and_validate_data`函数中,我们使用`pd.read_csv`加载元数据,如果`metadata_path`不存在,也会报错。所以我们在`main`函数中打印路径,方便调试。 如果元数据文件也不在脚本目录,请将其放在脚本目录,或者修改`metadata_path`为正确的路径。 修改后,重新运行程序。</think>您的代码报错是因为 `gait_data` 目录不存在。让我帮您修复这个问题,并提供完整的解决方案: ### 问题分析 错误发生在 `find_gait_data_files()` 函数中: ```python for filename in os.listdir(data_dir): ``` 原因是 `data_dir='gait_data'` 这个相对路径不存在。我们需要使用绝对路径来确保程序能找到数据目录。 ### 完整修复方案 ```python import os import re import pandas as pd import numpy as np import tensorflow as tf from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.model_selection import train_test_split from tensorflow.keras.layers import Input, Dense, Concatenate, Multiply, GlobalAveragePooling1D, Conv1D from tensorflow.keras.models import Model from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau import matplotlib.pyplot as plt import seaborn as sns from sklearn.metrics import confusion_matrix # 获取当前脚本所在的绝对路径 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) # --------------------------- # 1. 数据加载与完整性验证 (支持Excel) # --------------------------- def find_gait_data_files(data_dir=None): """自动发现所有步态数据文件(支持Excel和CSV)""" # 如果未指定目录,使用默认路径 if data_dir is None: data_dir = os.path.join(SCRIPT_DIR, "gait_data") # 确保目录存在 if not os.path.exists(data_dir): os.makedirs(data_dir, exist_ok=True) print(f"创建了数据目录: {data_dir}") file_map = {} patterns = [ r'koa_?(\w+)\.(xlsx|xls|csv|npy)', # koa_t25.xlsx 或 koat25.csv r'KOA_?(\w+)\.(xlsx|xls|csv|npy)', # KOA_T25.xlsx r'patient_?(\w+)\.(xlsx|xls|csv|npy)', # patient_t25.xlsx r'(\w+)_gait\.(xlsx|xls|csv|npy)' # t25_gait.xlsx ] # 检查目录是否存在 if not os.path.exists(data_dir): raise FileNotFoundError(f"目录不存在: {data_dir}") for filename in os.listdir(data_dir): for pattern in patterns: match = re.match(pattern, filename, re.IGNORECASE) if match: patient_id = match.group(1) file_ext = match.group(2).lower() file_map[patient_id.lower()] = os.path.join(data_dir, filename) break return file_map def load_gait_data(file_path): """从文件加载步态数据(支持Excel、CSV和NPY)""" # 确保文件存在 if not os.path.exists(file_path): raise FileNotFoundError(f"文件不存在: {file_path}") if file_path.endswith('.npy'): return np.load(file_path) # 处理Excel和CSV文件 try: if file_path.endswith(('.xlsx', '.xls')): df = pd.read_excel(file_path, header=None) elif file_path.endswith('.csv'): df = pd.read_csv(file_path, header=None) else: raise ValueError(f"不支持的步态文件格式: {file_path}") # 转换为NumPy数组并确保数值类型 gait_data = df.values.astype(np.float32) # 验证数据维度(至少10列) if gait_data.shape[1] < 10: raise ValueError(f"步态数据列数不足(需要至少10列): {file_path}") return gait_data except Exception as e: print(f"加载步态数据错误: {file_path} - {str(e)}") return None def load_and_validate_data(metadata_path=None, data_dir=None): """加载并验证数据完整性(支持Excel步态数据)""" # 设置默认元数据路径 if metadata_path is None: metadata_path = os.path.join(SCRIPT_DIR, "patient_metadata.csv") # 确保元数据文件存在 if not os.path.exists(metadata_path): raise FileNotFoundError(f"元数据文件不存在: {metadata_path}") # 加载元数据 metadata = pd.read_csv(metadata_path, encoding='utf-8-sig') # 清理患者ID metadata['clean_id'] = metadata['patient_id'].apply( lambda x: re.sub(r'[^\w]', '', str(x)).lower() ) # 获取步态文件映射 gait_file_map = find_gait_data_files(data_dir) # 添加文件路径到元数据 metadata['gait_path'] = metadata['clean_id'].map(gait_file_map) # 标记缺失数据 metadata['data_complete'] = metadata['gait_path'].notnull() # 分离完整和不完整数据 complete_data = metadata[metadata['data_complete']].copy() incomplete_data = metadata[~metadata['data_complete']].copy() print(f"总患者数: {len(metadata)}") print(f"完整数据患者: {len(complete_data)}") print(f"缺失步态数据患者: {len(incomplete_data)}") if not incomplete_data.empty: print("\n缺失步态数据的患者:") print(incomplete_data[['patient_id', 'koa_grade']].to_string(index=False)) incomplete_data.to_csv(os.path.join(SCRIPT_DIR, 'incomplete_records.csv'), index=False) return complete_data # ... 以下代码保持不变(从特征工程部分开始)... ``` ### 关键修改点: 1. **添加全局路径变量**: ```python SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) ``` 这会获取当前脚本所在的绝对路径,确保所有相对路径都基于此位置 2. **修复路径处理**: - 所有路径都使用 `os.path.join(SCRIPT_DIR, ...)` 构建绝对路径 - 添加目录存在性检查 - 自动创建缺失的目录 3. **增强错误处理**: ```python # 确保文件存在 if not os.path.exists(file_path): raise FileNotFoundError(f"文件不存在: {file_path}") ``` 4. **设置默认路径**: ```python # 设置默认元数据路径 if metadata_path is None: metadata_path = os.path.join(SCRIPT_DIR, "patient_metadata.csv") ``` ### 使用说明: 1. **目录结构**: ``` C:\Users\14816\Desktop\untitled1\ ├── yuchuli.py # 主脚本 ├── patient_metadata.csv # 患者元数据 └── gait_data\ # 步态数据目录 ├── koa_t25.xlsx ├── patient_123.csv └── ... ``` 2. **运行步骤**: - 将上面的完整代码保存为 `yuchuli.py` - 创建 `gait_data` 文件夹并放入步态数据文件 - 确保 `patient_metadata.csv` 文件存在 - 运行脚本 3. **如果文件缺失**: - 脚本会自动创建 `gait_data` 目录 - 如果元数据文件缺失,会明确报错提示 ### 常见问题解决: **Q: 我如何知道脚本在哪个目录下运行?** A: 在 `main()` 函数开头添加: ```python print(f"当前工作目录: {os.getcwd()}") print(f"脚本所在目录: {SCRIPT_DIR}") ``` **Q: 如果我的数据文件不在默认位置怎么办?** A: 可以手动指定路径: ```python # 在 main() 函数中 data_dir = r"C:\MyCustomPath\gait_data" metadata_path = r"C:\MyCustomPath\patient_data.csv" complete_data = load_and_validate_data(metadata_path, data_dir) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值