CostPrediction/docs/dev/debug.md

17 KiB
Raw Blame History

调试记录

特殊参数显示问题

问题描述

在数据管理页面中,装备详情对话框的特殊参数部分显示为空行或不显示。

调试步骤

  1. 后端数据查询
# 测试特殊参数查询
SELECT equipment_id, param_name, param_value, param_unit 
FROM custom_params 
WHERE param_name IS NOT NULL 
AND param_value IS NOT NULL
LIMIT 5
  1. 日志记录
logging.info(f"Getting details for equipment ID: {id}")
logging.info(f"Equipment type: {equipment_type}")
logging.info(f"Found equipment details: {result['name']}")
logging.info(f"Custom params: {result.get('custom_params')}")
  1. 前端调试
console.log('Requesting details for row:', row)
console.log('Details response:', response.data)
console.log('Custom params:', response.data.custom_params)
console.log('Selected data:', selectedData.value)

关键发现

  1. 数据库查询
  • 特殊参数表中有数据
  • JSON_ARRAYAGG 返回的格式需要处理
  • 需要过滤掉 NULL 值
  1. 数据格式
  • 后端返回的特殊参数是 JSON 字符串
  • 需要在前端解析为数组
  • 确保数组不为空
  1. 前端渲染
  • 条件判断需要更严格
  • 需要确保数据类型正确
  • 需要正确格式化显示值

解决方案

  1. 后端查询优化
(
    SELECT JSON_ARRAYAGG(
        JSON_OBJECT(
            'id', csp.id,
            'param_name', csp.param_name,
            'param_value', csp.param_value,
            'param_unit', csp.param_unit,
            'description', csp.description
        )
    )
    FROM custom_params csp
    WHERE csp.equipment_id = e.id
    AND csp.param_name IS NOT NULL
    AND csp.param_value IS NOT NULL
) as custom_params
  1. 前端数据处理
// 确保 custom_params 是数组
if (typeof response.data.custom_params === 'string') {
    response.data.custom_params = JSON.parse(response.data.custom_params)
}
  1. 渲染条件优化
<template v-if="selectedData?.custom_params && Array.isArray(selectedData.custom_params) && selectedData.custom_params.length > 0">

最佳实践

  1. 数据库查询
  • 使用子查询而不是 JOIN 获取特殊参数
  • 确保返回格式统一
  • 过滤无效数据
  1. 数据处理
  • 统一数据格式
  • 处理空值和异常
  • 保持类型一致
  1. 前端显示
  • 严格的条件判断
  • 类型检查
  • 格式化显示
  1. 调试方法
  • 使用日志<EFBFBD><EFBFBD><EFBFBD>踪数据流
  • 检查数据格式和类型
  • 验证每个环节的数据

编辑对话框问题

问题描述

在数据管理页面中,编辑对话框的成本信息分区和特殊参数分区显示不正确。

调试步骤

  1. 检查数据流
console.log('Editing row:', row)
console.log('Edit data response:', response.data)
console.log('Parsed custom params:', data.custom_params)
console.log('Edit form data:', editForm.value)
  1. 检查模板结构
<!-- 错误的嵌套结构 -->
<el-form>
  <template>
    <el-divider>成本信息</el-divider>
  </template>
</el-form>

<!-- 正确的结构 -->
<el-divider>成本信息</el-divider>
<el-form>
  <!-- 表单项 -->
</el-form>

关键发现

  1. 模板结构问题
  • el-divider 不应该嵌套在 template 中
  • 每个分区需要独立的 el-form
  • 避免不必要的 template 嵌套
  1. 数据类型问题
  • 后端返回的数值是字符串类型
  • el-input-number 组件需要数值类型
  • 需要在前端进行类型转换
  1. 条件渲染问题
  • v-if 条件过于严格可能导致内容不显示
  • 某些字段应该始终显示
  • 某些字段只在有值时显示

解决方案

  1. 修改模板结构
<!-- 成本信息 -->
<el-divider content-position="left">成本信息</el-divider>
<el-form :model="editForm" label-width="120px">
  <el-form-item label="实际成本(元)">
    <el-input-number v-model="editForm.actual_cost"></el-input-number>
  </el-form-item>
</el-form>
  1. 数据类型转换
// 转换所有数值类型字段
Object.keys(data).forEach(key => {
  if (isNumberInput(key) && data[key] !== null && data[key] !== undefined) {
    data[key] = Number(data[key])
  }
})
  1. 优化条件渲染
<!-- 始终显示必要字段 -->
<el-form-item label="实际成本(元)">
  <el-input-number v-model="editForm.actual_cost"></el-input-number>
</el-form-item>

<!-- 只在有值时显示可选字段 -->
<el-form-item label="预测成本(元)" v-if="editForm.predicted_cost">
  <el-input-number v-model="editForm.predicted_cost" disabled></el-input-number>
</el-form-item>

最佳实践

  1. 模板结构
  • 保持清晰的分区结构
  • 避免不必要的嵌套
  • 使用合适的组件层级
  1. 数据处理
  • 在获取数据后立即进行类型转换
  • 确保数据类型与组件要求匹配
  • 处理好空值和未定义值
  1. 条件渲染
  • 合理使用 v-if 和 v-show
  • 必要字段始终显示
  • 可选字段根据条件显示
  1. 调试方法
  • 使用 console.log 跟踪数据流
  • 检查组件的属性要求
  • 验证数据类型和结构

特征分析功能问题

问题描述

特征分析页面中,第一次点击分析按钮时,图表不显示,只有标题栏。第二次点击才能正常显示图表。

调试步骤

  1. 检查数据流
console.log('Analysis result:', analysisResult.value)
console.log('Charts not ready:', {
  importanceChartRef: !!importanceChartRef.value,
  correlationChartRef: !!correlationChartRef.value,
  analysisResult: !!analysisResult.value
})
  1. 检查渲染时机
// 使用 watch 监听分析结果变化
watch(() => analysisResult.value, async (newResult) => {
  if (newResult) {
    await nextTick()
    setTimeout(() => {
      renderCharts()
    }, 100)
  }
}, { deep: true })
  1. 检查图表实例管理
// 销毁旧的图表实例
if (importanceChart.value) {
  importanceChart.value.dispose()
}
if (correlationChart.value) {
  correlationChart.value.dispose()
}

关键发现

  1. 渲染时机问题
  • DOM 元素可能还未准备好
  • 数据更新后需要等待 DOM 更新
  • 需要正确管理图表实例
  1. 图表实例管理
  • 需要保存图表实例的引用
  • 重新渲染前需要销毁旧实例
  • 组件卸载时需要清理实例
  1. 数据格式问题
  • 特征名称需<EFBFBD><EFBFBD>中文映射
  • 相关性数据需要保留2位小数
  • 需要正确处理缺失值

解决方案

  1. 优化渲染逻辑
// 使用 nextTick 和延时确保 DOM 已更新
await nextTick()
setTimeout(() => {
  renderCharts()
}, 100)
  1. 完善图表实例管理
// 保存图表实例的引用
const importanceChart = ref(null)
const correlationChart = ref(null)

// 组件卸载时清理
onUnmounted(() => {
  importanceChart.value?.dispose()
  correlationChart.value?.dispose()
})
  1. 优化数据处理
// 使用中文特征名
chinese_feature_names = [self.feature_names_map.get(name, name) for name in feature_names]

// 保留2位小数
correlation_data.append([
  i, j, 
  round(correlation_matrix[i][j], 2)
])

最佳实践

  1. 渲染控制
  • 使用 watch 监听数据变化
  • 使用 nextTick 等待 DOM 更新
  • 添加适当的延时确保渲染
  1. 实例管理
  • 保存图表实例引用
  • 及时销毁旧实例
  • 组件卸载时清理
  1. 数据处理
  • 统一使用中文特征名
  • 控制数值精度
  • 处理好缺失值
  1. 调试方法
  • 添加详细的日志记录
  • 检查 DOM 元素状态
  • 验证数据格式

页面状态保持问题

问题描述

特征分析页面切换到其他页面后<EFBFBD><EFBFBD><EFBFBD>返回页面状态分析结果和图表会丢失需要重新分析。

调试步骤

  1. 检查路由配置
// 错误的配置
<keep-alive include="AnalysisPage">
  <router-view></router-view>
</keep-alive>

// 正确的配置
<router-view v-slot="{ Component }">
  <keep-alive>
    <component :is="Component" :key="$route.fullPath" />
  </keep-alive>
</router-view>
  1. 检查组件定义
// 错误的组件名称定义
<script setup name="AnalysisPage">

// 正确的组件名称定义
const __name = 'AnalysisPage'

关键发现

  1. keep-alive 配置问题
  • 需要使用 v-slot API
  • 需要使用动态组件
  • 需要添加 key 属性
  1. 组件定义问题
  • setup 语法糖不支持直接添加 name
  • 需要使用 __name 或 defineOptions
  1. 缓存范围问题
  • 不需要指定 include 属性
  • 缓存所有路由组件更简单
  • 避免组件名称不匹配的问题

解决方案

  1. 修改路由视图配置
<router-view v-slot="{ Component }">
  <keep-alive>
    <component :is="Component" :key="$route.fullPath" />
  </keep-alive>
</router-view>
  1. 修改组件定义
const __name = 'AnalysisPage'

最佳实践

  1. 路由配置
  • 使用 Vue3 的新 API
  • 保持配置简单清晰
  • 避免不<EFBFBD><EFBFBD><EFBFBD>要的限制
  1. 组件定义
  • 使用推荐的方式定义组件名
  • 避免使用已废弃的语法
  • 保持代码一致性
  1. 状态管理
  • 合理使用 keep-alive
  • 正确处理组件生命周期
  • 注意清理工作
  1. 调试方法
  • 检查组件是否被缓存
  • 验证状态是否保持
  • 确认生命周期钩子的执行

代码修改最佳实践

1. 修改前的准备

  1. 检查相关文件:
前端组件修改时检查:
- 相关的路由配置
- 父子组件关系
- 共用的组件和函数
- API调用

后端接口修改时检查:
- 路由定义
- 数据库查询
- 相关的工具类和函数
- 错误处理
  1. 保持命名一致性:
- 类名ModelTrainer 而不是 ModelTraining
- 文件名train_model.py 对应 ModelTrainer
- 变量名:保持前后端一致的命名规范
  1. 添加日志记录:
# 在关键节点添加日志
logging.info(f"Starting model training for {equipment_type}")
logging.info(f"Training dataset: {train_dataset_id}")
logging.error(f"Error in model training: {str(e)}")

2. 修改过程中

  1. 错误处理:
try:
    # 主要逻辑
except Exception as e:
    logging.error(f"Error: {str(e)}")
    logging.error("Detailed traceback:", exc_info=True)
    return jsonify({'error': str(e)}), 500
  1. 数据验证:
# 验证输入
if not formData.value.type:
    throw new Error('请选择装备类型')
if not formData.value.train_dataset_id:
    throw new Error('请选择训练数据集')
  1. 状态管理:
// 重置状态
formData.value.train_dataset_id = null
formData.value.validation_dataset_id = null
trainingResult.value = null

3. 修改后的验证

  1. 功能测试:
- 验证主要功能
- 测试边界条件
- 检查错误处理
  1. 性能检查:
- 检查数据库查询性能
- 验证前端渲染性能
- 确认内存使用情况
  1. 代码质量:
- 检查代码风格
- 确保注释完整
- 验证类型定义

4. 文档更新

  1. 更新调试文档:
- 记录问题原因
- 描述解决方案
- 添加最佳实践
  1. 更新设计文档:
- 更新接口定义
- 修改数据结构
- 补充新功能说明
  1. 更新注释:
- 添加函数说明
- 说明参数用途
- 解释复杂逻辑

模型训练结果

从最新的训练结果来看:

  1. XGBoost 表现最好:
    • 训练集 R² = 0.4346,没有过拟合
    • 验证集 R² = 0.3625,表现最稳定
    • MAE = 0.60RMSE = 0.61,预测误差较小
  2. LightGBM 表现次之:
    • 训练集 R² = 0.5277,轻微过拟合
    • 验证集 R² = 0.1101,泛化能力一般
    • MAE = 0.55RMSE = 0.72,预测误差适中
  3. Random Forest
    • 训练集 R² = 0.7756,存在过拟合
    • 验证集 R² = 0.3189,泛化能力还可以
    • MAE = 0.47RMSE = 0.63,预测误差较小
  4. GBDT 过拟合严重:
    • 训练集 R² = 0.9700,严重过拟合
    • 验证集 R² = -1.3133,泛化能力很差
    • MAE = 0.96RMSE = 1.17,预测误差大

建议

  1. 使用 XGBoost 作为主要模型
  2. 可以考虑集成 XGBoost 和 Random Forest
  3. 继续调整 LightGBM 的参数
  4. 暂时不使用 GBDT

数据集存在的问题

火箭炮数据集:

  • Feature length_m missing rate: 0.00%
  • Feature width_m missing rate: 9.09%
  • Feature height_m missing rate: 9.09%
  • Feature weight_kg missing rate: 0.00%
  • Feature max_range_km missing rate: 45.45%
  • Feature firing_angle_horizontal missing rate: 45.45%
  • Feature firing_angle_vertical missing rate: 45.45%
  • Feature rocket_length_m missing rate: 72.73%
  • Feature rocket_diameter_mm missing rate: 0.00%
  • Feature rocket_weight_kg missing rate: 72.73%
  • Feature rate_of_fire missing rate: 54.55%

巡飞弹数据集:

  • Feature length_m missing rate: 27.78%
  • Feature width_m missing rate: 50.00%
  • Feature height_m missing rate: 50.00%
  • Feature weight_kg missing rate: 22.22%
  • Feature max_range_km missing rate: 44.44%
  • Feature wingspan_m missing rate: 50.00%
  • Feature warhead_weight_kg missing rate: 77.78%
  • Feature max_speed_ms missing rate: 77.78%
  • Feature cruise_speed_kmh missing rate: 61.11%
  • Feature flight_time_min missing rate: 33.33%

前端特征分析页面未正确显示相关性分析数据(常见问题)

  • 确保相关性分析数据的正确格式化和返回
  • 添加了详细的日志记录
  • 增加了数据验证步骤
  • 处理了可能的NaN值
  • 确保所有数值都转换为Python原生类型使用float()

巡飞弹数据整理问题总结

1. 最小飞行高度数据问题

问题描述

  • 所有巡飞弹的最小飞行高度都被设置为相同值50米
  • 在特征相关性分析中由于数据完全相同导致该特征与其他特征的相关性无法计算出现NaN

解决方案

  1. 根据巡飞弹的类型和性能特点,设置不同的最小飞行高度:

    • 大型巡飞弹(如 HAROP/Harpy、Shahed系列150米
    • 中型巡飞弹(如 Mini Harpy、高端Hero系列100米
    • 中小型巡飞弹(如 Hero-120、Switchblade 60080米
    • 小型巡飞弹(如 Hero-30/70、Switchblade 30050米
    • 超小型巡飞弹(如 Kargu/Alpagu、Rotem系列30米
  2. 在特征分析中处理常量特征:

    • 检测标准差为0的特征
    • 对于常量特征设置与自身的相关性为1
    • 与其他特征的相关性设置为0
    • 添加相应的日志记录和警告信息

2. 特征分析图表显示问题

问题描述

  1. 特征工程参数分析和发动机性能分析图表中由于空间限制x轴上的装备型号名称显示不完整
  2. 相关性热力图单元格高度过小,不易查看

解决方案

  1. 图表标签显示优化:

    • 在 tooltip 中显示完整的装备型号名称
    • 添加数据点的详细信息显示
    tooltip: {
      formatter: function(params) {
        const equipmentName = chartData.names[params[0].dataIndex]
        let result = `${equipmentName}<br/>`
        params.forEach(param => {
          result += `${param.seriesName}: ${param.value.toFixed(2)}<br/>`
        })
        return result
      }
    }
    
  2. 热力图显示优化:

    • 增加图表容器高度800px
    • 调整 grid 配置,增加显示区域
    • 优化标签间距和旋转角度
    grid: {
      height: '75%',
      top: '10%',
      bottom: '15%',
      left: '10%',
      right: '10%',
      containLabel: true
    }
    

3. 数据完整性问题

问题描述

部分巡飞弹数据字段存在缺失:

  • 宽度、高度50% 缺失
  • 弹头重量77.78% 缺失
  • 最大速度77.78% 缺失
  • 巡航速度61.11% 缺失

解决方案

  1. 数据补充和验证:

    • 根据装备的物理特性和性能参数推算缺失值
    • 使用相似型号的数据作为参考
    • 添加数据验证和完整性检查
  2. 特征工程:

    • 添加新的组合特征:长宽比、重量射程比等
    • 计算衍生参数:有效载荷、最小作战半径等
    • 设计评分系统:制导系统评分、战斗部威力评分等

4. 数据一致性问题

问题描述

  • 不同型号之间的参数单位不统一
  • 部分参数的计算方式不一致
  • 分类特征(如制导系统、战斗部类型)的表述不统一

解决方案

  1. 统一数据标准:

    • 统一使用国际单位制SI
    • 标准化参数计算方法
    • 规范分类特征的表述方式
  2. 添加数据转换和验证:

    # 单位转换
    l.max_speed_ms = l.max_speed_kmh / 3.6
    l.engine_thrust_n = l.engine_thrust_kgf * 9.81
    
    # 分类特征编码
    l.guidance_system_code = 
      CASE 
        WHEN l.guidance_system = 'GPS/INS' THEN 1
        WHEN l.guidance_system = 'GPS/INS/光电' THEN 2
        # ... 其他情况
      END
    

最佳实践建议

  1. 数据收集和整理:

    • 建立完整的数据采集标准
    • 确保数据的一致性和可比性
    • 及时记录数据来源和处理方法
  2. 特征工程:

    • 根据领域知识设计特征
    • 考虑特征之间的关系
    • 注意特征的可解释性
  3. 数据验证:

    • 实施多层次的数据验证
    • 添加完整的日志记录
    • 建立数据质量监控机制
  4. 可视化展示:

    • 确保图表的可读性
    • 提供详细的数据说明
    • 支持交互式数据探索