Pārlūkot izejas kodu

计算多个模型指标;删除冗余数据(数据表、模型文件)

drggboy 3 mēneši atpakaļ
vecāks
revīzija
0887bfab69

+ 2 - 1
api/.gitignore

@@ -1,4 +1,5 @@
 app/__pycache__
 .idea
 model_optimize/__pycache__
-__pycache__
+__pycache__
+.vscode

BIN
api/SoilAcidification.db


BIN
api/__pycache__/run.cpython-38.pyc


+ 6 - 1
api/app/database_models.py

@@ -31,7 +31,12 @@ class Models(Base):
     DatasetID: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey('Datasets.Dataset_ID'))
     ModelFilePath: Mapped[Optional[str]] = mapped_column(Text)
     Data_type: Mapped[Optional[str]] = mapped_column(Text)
-    Performance_score: Mapped[Optional[float]] = mapped_column(Text)
+    Performance_score: Mapped[Optional[float]] = mapped_column(Float)
+
+    # 新增评分指标字段
+    MAE: Mapped[Optional[float]] = mapped_column(Float)
+    RMSE: Mapped[Optional[float]] = mapped_column(Float)
+    CV_score: Mapped[Optional[float]] = mapped_column(Float)
 
     ModelParameters: Mapped[List['ModelParameters']] = relationship('ModelParameters', back_populates='Models_')
 

+ 58 - 14
api/app/model.py

@@ -4,11 +4,12 @@ import pickle
 import pandas as pd
 from flask_sqlalchemy.session import Session
 from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
-from sklearn.metrics import r2_score
+from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
 from sklearn.model_selection import train_test_split, cross_val_score
 from sqlalchemy import text
 from xgboost import XGBRegressor
 import logging
+import numpy as np
 
 from .database_models import Models, Datasets
 from .config import Config
@@ -97,7 +98,7 @@ def calculate_model_score(model_info):
         model_info: 模型信息对象
         
     Returns:
-        float: 模型的R²评分
+        dict: 包含多种评分指标的字典
     """
     # 加载模型
     with open(model_info.ModelFilePath, 'rb') as f:
@@ -108,22 +109,55 @@ def calculate_model_score(model_info):
         # 加载保存的 X_test 和 Y_test
         X_test = pd.read_csv('uploads/data/X_test_reflux.csv')
         Y_test = pd.read_csv('uploads/data/Y_test_reflux.csv')
-        print(X_test.columns)  # 在测试时使用的数据的列名
+        
+        # 预测测试集
         y_pred = ML_model.predict(X_test)
+        
+        # 计算各种评分指标
+        r2 = r2_score(Y_test, y_pred)
+        mae = mean_absolute_error(Y_test, y_pred)
+        rmse = np.sqrt(mean_squared_error(Y_test, y_pred))
+        
     elif model_info.Data_type == 'reduce':  # 降酸数据集
         # 加载保存的 X_test 和 Y_test
         X_test = pd.read_csv('uploads/data/X_test_reduce.csv')
         Y_test = pd.read_csv('uploads/data/Y_test_reduce.csv')
-        print(X_test.columns)  # 在测试时使用的数据的列名
+        
+        # 预测测试集
         y_pred = ML_model.predict(X_test)
-
-
-    # 计算 R² 分数
-    r2 = r2_score(Y_test, y_pred)
-    return r2
+        
+        # 计算各种评分指标
+        r2 = r2_score(Y_test, y_pred)
+        mae = mean_absolute_error(Y_test, y_pred)
+        rmse = np.sqrt(mean_squared_error(Y_test, y_pred))
+        
+    else:
+        # 不支持的数据类型
+        return {'r2': 0, 'mae': 0, 'rmse': 0}
+    
+    # 返回所有评分指标(不包括交叉验证得分)
+    return {
+        'r2': float(r2),
+        'mae': float(mae),
+        'rmse': float(rmse)
+    }
 
 
 def train_and_save_model(session, model_type, model_name, model_description, data_type, dataset_id=None):
+    """
+    训练并保存模型
+    
+    Args:
+        session: 数据库会话
+        model_type: 模型类型
+        model_name: 模型名称
+        model_description: 模型描述
+        data_type: 数据类型 ('reflux' 或 'reduce')
+        dataset_id: 数据集ID
+        
+    Returns:
+        tuple: (模型名称, 模型ID, 数据集ID)
+    """
     try:
         if not dataset_id:
             # 创建新的数据集并复制数据,此过程将不立即提交
@@ -163,17 +197,27 @@ def train_and_save_model(session, model_type, model_name, model_description, dat
         
         # 训练模型
         model = train_model_by_type(X, y, model_type)
-
+        
+        # 计算交叉验证得分
+        cv_score = cross_val_score(model, X, y, cv=5).mean()
+        
         # 保存模型到数据库
         model_id = save_model(session, model, model_name, model_type, model_description, dataset_id, data_type)
-
+        
+        # 更新模型的交叉验证得分
+        model_info = session.query(Models).filter(Models.ModelID == model_id).first()
+        if model_info:
+            model_info.CV_score = float(cv_score)
+            session.commit()
+        
         # 所有操作成功后,手动提交事务
         session.commit()
-        return model_name, model_id, dataset_id
+        return model_name, model_id, dataset_id, cv_score
+        
     except Exception as e:
-        # 如果在任何阶段出现异常,回滚事务
         session.rollback()
-        raise e  # 可选择重新抛出异常或处理异常
+        logging.error(f"训练和保存模型时发生错误: {str(e)}", exc_info=True)
+        raise
 
 
 

+ 28 - 9
api/app/routes.py

@@ -256,11 +256,22 @@ def train_and_save_model_endpoint():
         if model_id:
             model_info = session.query(Models).filter(Models.ModelID == model_id).first()
             if model_info:
-                score = calculate_model_score(model_info)
+                # 计算多种评分指标
+                score_metrics = calculate_model_score(model_info)
                 # 更新模型评分
-                model_info.Performance_score = score
+                model_info.Performance_score = score_metrics['r2']
+                # 添加新的评分指标到数据库
+                model_info.MAE = score_metrics['mae']
+                model_info.RMSE = score_metrics['rmse']
+                # CV_score 已在 train_and_save_model 中设置,此处不再更新
                 session.commit()
-                result = {'model_id': model_id, 'model_score': score}
+                result = {
+                    'model_id': model_id, 
+                    'model_score': score_metrics['r2'],
+                    'mae': score_metrics['mae'],
+                    'rmse': score_metrics['rmse'],
+                    'cv_score': result[3]
+                }
 
         # 返回成功响应
         return jsonify({
@@ -322,7 +333,7 @@ def predict_route():
         return jsonify({'error': str(e)}), 400
 
 
-# 为指定模型计算评分Performance_score,需要提供model_id
+# 为指定模型计算指标评分,需要提供model_id
 @bp.route('/score-model/<int:model_id>', methods=['POST'])
 def score_model(model_id):
     # 创建 sessionmaker 实例
@@ -334,15 +345,23 @@ def score_model(model_id):
             return jsonify({'error': 'Model not found'}), 404
 
         # 计算模型评分
-        score = calculate_model_score(model_info)
+        score_metrics = calculate_model_score(model_info)
+
+        # 更新模型记录中的评分(不包括交叉验证得分)
+        model_info.Performance_score = score_metrics['r2']
+        model_info.MAE = score_metrics['mae']
+        model_info.RMSE = score_metrics['rmse']
 
-        # 更新模型记录中的评分
-        model_info.Performance_score = score
         session.commit()
 
-        return jsonify({'message': 'Model scored successfully', 'score': score}), 200
+        return jsonify({
+            'message': 'Model scored successfully', 
+            'r2_score': score_metrics['r2'],
+            'mae': score_metrics['mae'],
+            'rmse': score_metrics['rmse'],
+        }), 200
     except Exception as e:
-        logging.error('Failed to process the dataset upload:', exc_info=True)
+        logging.error('Failed to process model scoring:', exc_info=True)
         return jsonify({'error': str(e)}), 400
     finally:
         session.close()

BIN
api/model_optimize/data/Acidity_reduce_new - 1.xlsx


BIN
api/model_optimize/data/Acidity_reduce_new - 2.xlsx


BIN
api/model_optimize/data/Acidity_reduce_new - 3.xlsx


BIN
api/pkl/rf_model_0104_0932.pkl


BIN
api/pkl/rf_model_0107_0123.pkl


BIN
api/pkl/rf_model_0111_1755.pkl


BIN
api/pkl/rf_model_0308_1550.pkl


BIN
api/pkl/rf_model_0308_1619.pkl


BIN
api/pkl/rf_model_0308_1632.pkl


BIN
api/uploads/datasets/dataset_8.xlsx