Files
AIclinicalresearch/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能开发计划.md
HaHafeng f4f1d09837 feat(dc/tool-c): Add pivot column ordering and NA handling features
Major features:
1. Pivot transformation enhancements:
   - Add option to keep unselected columns with 3 aggregation methods
   - Maintain original column order after pivot (aligned with source file)
   - Preserve pivot value order (first appearance order)

2. NA handling across 4 core functions:
   - Recode: Support keep/map/drop for NA values
   - Filter: Already supports is_null/not_null operators
   - Binning: Support keep/label/assign for NA values (fix nan display)
   - Conditional: Add is_null/not_null operators

3. UI improvements:
   - Enable column header tooltips with custom header component
   - Add closeable alert for 50-row preview
   - Fix page scrollbar issues

Modified files:
Python: pivot.py, recode.py, binning.py, conditional.py, main.py
Backend: SessionController, QuickActionController, QuickActionService
Frontend: PivotDialog, RecodeDialog, BinningDialog, ConditionalDialog, DataGrid, index

Status: Ready for testing
2025-12-09 14:40:14 +08:00

26 KiB
Raw Blame History

工具C - 缺失值处理功能开发计划

📋 概述

目标:将现有的"删除缺失值"功能升级为综合的"缺失值处理"功能,包括删除、填补、高级填补三种策略。

设计方案方案B - 合并对话框 + Tab切换

核心原则

  • 填补操作创建新列(保留原始数据,便于对比)
  • 新列紧邻原列(方便用户查看和比较)
  • MICE功能必须实现(医学研究核心需求)
  • 无需撤销功能(原始数据未被修改)

🎯 功能需求

Phase 1必备功能本次开发

Tab 1删除缺失值 已有

  • 保留现有功能
  • 删除包含缺失值的行
  • 删除缺失率过高的列

Tab 2填补缺失值 新增

  1. 均值填补Mean Imputation

    • 适用于:数值型变量,正态分布
    • 实现:df[column].fillna(df[column].mean())
  2. 中位数填补Median Imputation

    • 适用于:数值型变量,偏态分布
    • 实现:创建新列,填充中位数
  3. 众数填补Mode Imputation

    • 适用于:分类变量、离散型数值
    • 实现:创建新列,填充众数
  4. 固定值填补Constant Imputation

    • 适用于:任何类型,用户指定值
    • 实现:创建新列,填充指定值

注意:所有填补方法都会创建新列(如体重_填补),新列紧邻原列,便于对比验证。

Tab 3高级填补 新增

  1. MICE多重插补Multivariate Imputation by Chained Equations
    • 适用于缺失率5%-30%,需要考虑变量间关系
    • 实现:使用 sklearn.impute.IterativeImputer

Phase 2未来扩展本次不开发

  • 前向/后向填充Forward/Backward Fill
  • 分组填补Grouped Imputation
  • 线性插值Linear Interpolation
  • KNN填补KNN Imputation

🎨 UI设计

1. 按钮重命名

[删除缺失值]
[缺失值处理]

2. 对话框结构

┌───────────────────────────────────────────────────────┐
│  缺失值处理                                    [X]    │
├───────────────────────────────────────────────────────┤
│  ┌────────┬────────┬──────────┐                      │
│  │ 删除   │ 填补   │ 高级填补 │  ← Ant Design Tabs   │
│  └────────┴────────┴──────────┘                      │
├───────────────────────────────────────────────────────┤
│                                                        │
│  【Tab内容区域】                                       │
│                                                        │
│                                                        │
│                    [取消]    [执行处理]               │
└───────────────────────────────────────────────────────┘

3. Tab 2填补详细设计

┌───────────────────────────────────────────────────────┐
│  【Tab 2: 填补缺失值】                                 │
│                                                        │
│  原始列:[体重kg▼]                                │
│           ⚠️ 仅支持单列填补                           │
│                                                        │
│  新列名:[体重_填补           ] ← 用户可修改          │
│          💡 新列将创建在原列旁边,便于对比            │
│                                                        │
│  📊 缺失值统计:                                      │
│  ┌──────────────────────────────────────────────┐   │
│  │ • 当前缺失125个15.6%                   │   │
│  │ • 有效值675个84.4%                     │   │
│  │ • 数据类型:数值型                           │   │
│  │ • 有效值范围45.2 - 98.5 kg               │   │
│  │ • 有效值均值70.3 kg                        │   │
│  │ • 有效值中位数68.5 kg                      │   │
│  │ • 推荐方法:中位数填补(数据偏态)⭐         │   │
│  └──────────────────────────────────────────────┘   │
│                                                        │
│  填补方法:                                            │
│  ⚪ 均值填补(适合正态分布的数值变量)                │
│  ⚪ 中位数填补(适合偏态分布的数值变量)⭐            │
│  ⚪ 众数填补(适合分类变量或离散数值)                │
│  ⚪ 固定值填补:[_______] ← 用户输入                 │
│                                                        │
│  📈 填补预览:                                        │
│  ┌──────────────────────────────────────────────┐   │
│  │ • 填补值68.5 kg                            │   │
│  │ • 填补后均值70.2 kg原75.3 kg          │   │
│  │ • 填补后标准差12.5 kg原10.8 kg        │   │
│  │ • 将创建新列:"体重_填补"                   │   │
│  │ • 原列"体重kg"保持不变 ✅               │   │
│  └──────────────────────────────────────────────┘   │
│                                                        │
│  ✅ 优势:原始数据保留,可随时对比验证                │
│                                                        │
│                    [取消]    [执行填补]               │
└───────────────────────────────────────────────────────┘

4. Tab 3高级填补详细设计

┌───────────────────────────────────────────────────────┐
│  【Tab 3: 高级填补 - MICE多重插补】⭐ 必须实现        │
│                                                        │
│  ⭐ MICE多重插补                                       │
│  Multivariate Imputation by Chained Equations     │
│                                                        │
│  选择要填补的列(可多选):                            │
│  ┌──────────────────────────────────────────────┐   │
│  │ ☑ 体重kg         缺失12515.6%     │   │
│  │ ☑ 收缩压mmHg     缺失8210.3%      │   │
│  │ ☐ BMI               缺失30.4%         │   │
│  │ ☐ 舒张压mmHg     缺失00%          │   │
│  └──────────────────────────────────────────────┘   │
│                                                        │
│  新列命名规则:                                        │
│  ☑ 自动命名:原列名 + "_MICE"                         │
│     示例体重kg → 体重kg_MICE                │
│            收缩压mmHg → 收缩压mmHg_MICE       │
│                                                        │
│  参数设置:                                            │
│  迭代次数:[10▼] 默认10次范围5-50               │
│  随机种子:[42  ] (确保结果可重复)                  │
│                                                        │
│  📊 MICE说明                                        │
│  ┌──────────────────────────────────────────────┐   │
│  │ MICE会根据其他变量的值来预测缺失值。         │   │
│  │                                               │   │
│  │ ✅ 适用场景:                                │   │
│  │   • 缺失率5%-30%                             │   │
│  │   • 需要考虑变量间的相关性                   │   │
│  │   • 多个变量同时有缺失                       │   │
│  │   • 医学研究高质量填补的首选方法 ⭐          │   │
│  │                                               │   │
│  │ ⚠️ 注意:                                    │   │
│  │   • 计算时间较长10万行约1分钟            │   │
│  │   • 需要足够的有效样本(建议>50%有效)       │   │
│  │   • 新列将创建在各原列旁边,便于对比         │   │
│  └──────────────────────────────────────────────┘   │
│                                                        │
│  💡 新列位置:每个新列紧邻其原列,便于逐列验证        │
│                                                        │
│                    [取消]    [执行MICE填补]           │
└───────────────────────────────────────────────────────┘

🛠️ 技术实现方案

1. Python端extraction_service

新增文件:operations/fillna.py

"""
缺失值填补 - 预写函数
支持均值、中位数、众数、固定值、MICE填补
"""

import pandas as pd
import numpy as np
from typing import Literal, Optional, List, Union, Any
from sklearn.impute import IterativeImputer


def fillna_simple(
    df: pd.DataFrame,
    column: str,
    new_column_name: str,
    method: Literal['mean', 'median', 'mode', 'constant'],
    fill_value: Any = None
) -> dict:
    """
    简单填补缺失值(创建新列)
    
    Args:
        df: 输入数据框
        column: 原始列名
        new_column_name: 新列名(如"体重_填补"
        method: 填补方法
            - 'mean': 均值填补
            - 'median': 中位数填补
            - 'mode': 众数填补
            - 'constant': 固定值填补
        fill_value: 固定值method='constant'时必填)
    
    Returns:
        {
            'df': 包含新列的数据框(新列紧邻原列),
            'stats': {
                'original_column': 原列名,
                'new_column': 新列名,
                'missing_before': 缺失数量,
                'fill_value': 填补的值,
                'mean_after': 填补后均值,
                'std_after': 填补后标准差
            }
        }
    
    实现细节:
        1. 复制原列数据
        2. 执行填补
        3. 使用 df.insert() 将新列插入到原列旁边
        4. 返回包含新列的完整数据框
    """
    
def get_column_missing_stats(
    df: pd.DataFrame,
    column: str
) -> dict:
    """
    获取列的缺失值统计信息
    
    Returns:
        {
            'missing_count': 缺失数量,
            'missing_rate': 缺失率,
            'valid_count': 有效值数量,
            'data_type': 数据类型,
            'value_range': [min, max],  # 仅数值型
            'mean': 均值,               # 仅数值型
            'median': 中位数,           # 仅数值型
            'mode': 众数,
            'recommended_method': 推荐的填补方法
        }
    """
    
def fillna_mice(
    df: pd.DataFrame,
    columns: List[str],
    n_iterations: int = 10,
    random_state: int = 42
) -> dict:
    """
    MICE多重插补创建新列⭐ 必须实现
    
    Args:
        df: 输入数据框
        columns: 要填补的列名列表(如["体重kg", "收缩压mmHg"]
        n_iterations: 迭代次数默认10范围5-50
        random_state: 随机种子默认42确保结果可重复
    
    Returns:
        {
            'df': 包含所有新列的数据框(每个新列紧邻其原列),
            'stats': {
                column: {
                    'original_column': 原列名,
                    'new_column': 新列名原名_MICE,
                    'missing_before': 缺失数量,
                    'filled_count': 填补数量,
                    'mean_before': 填补前均值,
                    'mean_after': 填补后均值
                }
            }
        }
    
    实现细节:
        1. 对所选列执行MICE填补
        2. 为每列创建新列命名原列名_MICE
        3. 使用 df.insert() 将每个新列插入到其原列旁边
        4. 返回包含所有新列的完整数据框
    
    示例:
        原列体重kg、收缩压mmHg
        新列体重kg_MICE、收缩压mmHg_MICE
        结果顺序体重kg、体重kg_MICE、收缩压mmHg、收缩压mmHg_MICE、...
    """

修改文件:main.py

# 新增API端点

@app.post("/fillna-simple")
async def operation_fillna_simple(request: FillnaSimpleRequest):
    """简单填补缺失值"""
    
@app.post("/fillna-stats")
async def get_fillna_stats(request: FillnaStatsRequest):
    """获取列的缺失值统计"""
    
@app.post("/fillna-mice")
async def operation_fillna_mice(request: FillnaMiceRequest):
    """MICE多重插补"""

2. Node.js后端backend

修改文件:services/QuickActionService.ts

// 新增方法

async executeFillnaSimple(params: {
  sessionId: string;
  column: string;
  method: 'mean' | 'median' | 'mode' | 'constant';
  fillValue?: any;
}): Promise<any>

async getFillnaStats(params: {
  sessionId: string;
  column: string;
}): Promise<any>

async executeFillnaMice(params: {
  sessionId: string;
  columns: string[];
  nIterations: number;
}): Promise<any>

修改文件:controllers/QuickActionController.ts

// 新增处理方法

async handleFillnaSimple(request, reply)
async getFillnaStats(request, reply)
async handleFillnaMice(request, reply)

3. 前端frontend-v2

重命名文件

  • DropnaDialog.tsxMissingValueDialog.tsx

修改文件:MissingValueDialog.tsx

interface MissingValueDialogProps {
  open: boolean;
  onClose: () => void;
  sessionId: string;
  columns: Array<{ id: string; name: string; type?: string }>;
  onSuccess: () => void;
}

// 新增状态
const [activeTab, setActiveTab] = useState<'delete' | 'fill' | 'mice'>('fill');
const [selectedColumn, setSelectedColumn] = useState<string>('');
const [fillMethod, setFillMethod] = useState<'mean' | 'median' | 'mode' | 'constant'>('median');
const [fillValue, setFillValue] = useState<any>(null);
const [columnStats, setColumnStats] = useState<any>(null);

// Tab 1: 删除(保留原有逻辑)
// Tab 2: 填补(新增)
// Tab 3: MICE新增

修改文件:index.tsx

// 更新按钮组
const actionButtons = [
  // ...
  {
    key: 'missing',
    icon: <DeleteOutlined />,
    label: '缺失值处理',  // ← 重命名
    onClick: () => setMissingValueDialogOpen(true),
  },
  // ...
];

📂 文件修改清单

新增文件

  1. extraction_service/operations/fillna.py - 填补功能实现
  2. docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能开发计划.md - 本文档

修改文件

Python端

  1. extraction_service/main.py
    • 新增 /fillna-simple 端点
    • 新增 /fillna-stats 端点
    • 新增 /fillna-mice 端点

Node.js后端

  1. backend/src/modules/dc/tool-c/services/QuickActionService.ts

    • 新增 executeFillnaSimple 方法
    • 新增 getFillnaStats 方法
    • 新增 executeFillnaMice 方法
  2. backend/src/modules/dc/tool-c/controllers/QuickActionController.ts

    • 新增 handleFillnaSimple 处理方法
    • 新增 getFillnaStats 处理方法
    • 新增 handleFillnaMice 处理方法

前端

  1. frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx

    • 重命名为 MissingValueDialog.tsx
    • 新增 Tabs 组件(删除/填补/高级填补)
    • Tab 1: 保留原有删除功能
    • Tab 2: 新增简单填补功能(均值/中位数/众数/固定值)
    • Tab 3: 新增MICE填补功能
  2. frontend-v2/src/modules/dc/pages/tool-c/index.tsx

    • 更新按钮标签:删除缺失值缺失值处理
    • 更新 Dialog 组件引用
  3. frontend-v2/src/modules/dc/api/index.ts

    • 新增 fillnaSimple API
    • 新增 getFillnaStats API
    • 新增 fillnaMice API

🔄 开发步骤

Step 1: Python端基础功能30min

  1. 创建 fillna.py
  2. 实现 fillna_simple 函数
  3. 实现 get_column_missing_stats 函数
  4. main.py 添加对应端点
  5. 测试使用Postman或curl测试API

Step 2: Python端高级功能30min

  1. 实现 fillna_mice 函数
  2. main.py 添加对应端点
  3. 测试使用Postman测试MICE功能

Step 3: Node.js后端20min

  1. 修改 QuickActionService.ts
  2. 修改 QuickActionController.ts
  3. 测试确保API转发正常

Step 4: 前端UI重构40min

  1. 重命名 DropnaDialog.tsxMissingValueDialog.tsx
  2. 实现Tabs结构
  3. Tab 1: 迁移原有删除功能
  4. Tab 2: 实现简单填补UI
  5. Tab 3: 实现MICE填补UI
  6. 更新 index.tsx 中的引用和按钮标签

Step 5: 前端API集成20min

  1. api/index.ts 添加新API
  2. 集成到 MissingValueDialog.tsx
  3. 实现实时统计获取
  4. 实现填补预览

Step 6: 端到端测试30min

  1. 测试均值填补
  2. 测试中位数填补
  3. 测试众数填补
  4. 测试固定值填补
  5. 测试MICE填补
  6. 测试删除功能(确保未破坏原有功能)

Step 7: 优化和文档20min

  1. 添加错误处理
  2. 优化加载状态
  3. 更新用户提示
  4. 记录开发总结

总计约3小时


🧪 测试计划

功能测试用例

测试数据准备

- 数值列正态分布年龄缺失15%
- 数值列偏态分布体重缺失20%
- 分类列婚姻状况缺失10%
- 多列缺失收缩压15%+ 舒张压12%

测试用例

编号 功能 测试场景 预期结果
TC-1 均值填补 对"年龄"列使用均值填补,新列名"年龄_填补" 创建新列,缺失值被均值填充,原列不变
TC-2 中位数填补 对"体重"列使用中位数填补 创建新列,缺失值被中位数填充
TC-3 众数填补 对"婚姻状况"列使用众数填补 创建新列,缺失值被众数填充
TC-4 固定值填补(数值) 对"年龄"列填充固定值"0" 创建新列所有缺失值变为0
TC-5 固定值填补(文本) 对"婚姻状况"列填充"未知" 创建新列,所有缺失值变为"未知"
TC-6 MICE填补 选择"收缩压"+"舒张压"执行MICE 创建2个新列_MICE后缀缺失值被预测
TC-7 新列位置验证 对"列A"填补,查看新列位置 新列"列A_填补"紧邻原列"列A"右侧
TC-8 MICE新列位置 对"列A"+"列C"执行MICE 列A_MICE在列A旁列C_MICE在列C旁
TC-9 统计信息准确性 选择任意列,查看统计信息 显示正确的缺失数、均值、中位数等
TC-10 删除功能保留 Tab 1删除缺失行 功能正常,与原功能一致
TC-11 空列处理 对完全无缺失的列执行填补 提示"该列无缺失值"或复制原列
TC-12 全缺失列处理 对全部缺失的列执行填补 提示警告,仍创建新列(全部为填补值)
TC-13 重复新列名处理 新列名已存在 自动添加后缀(如"体重_填补_1")或提示
TC-14 原始数据保留 填补后,检查原列 原列数据完全不变

边界测试

测试项 场景 预期
超大数据集 10万行数据执行MICE 显示进度,不崩溃
特殊字符列名 列名带括号、等号 正常处理使用columnMapping
数据类型混合 对文本列执行均值填补 提示错误或自动跳过
并发处理 同时打开多个Dialog 状态隔离,不互相影响

📊 性能要求

操作 数据量 目标响应时间
简单填补(均值/中位数/众数) 1万行 < 1秒
简单填补 10万行 < 5秒
MICE填补 1万行 < 10秒
MICE填补 10万行 < 60秒
统计信息获取 任意 < 0.5秒

🚨 风险和注意事项

1. 数据安全 已解决

  • 填补操作创建新列,原始数据完全保留
  • 新列紧邻原列,便于对比验证
  • 无需撤销功能(原始数据未被修改)
  • 用户可随时删除填补后的列,或重新填补

2. MICE性能 重点关注

  • ⚠️ MICE在大数据集上可能很慢10万行约1分钟
  • 必须显示进度条或加载动画
  • 添加"预计耗时"提示(基于数据量估算)
  • 提供"取消执行"按钮(长时间任务)
  • 💡 优化建议考虑使用Web Worker或后台任务队列

3. 数据类型兼容性

  • ⚠️ 均值/中位数只适用于数值列
  • 需要前端验证列的数据类型
  • 后端也需要校验并返回友好错误

4. 列名特殊字符

  • ⚠️ 列名可能包含特殊字符
  • 使用现有的 columnMapping 机制
  • 确保与compute列功能一致

5. 全部缺失的列

  • ⚠️ 如果列全部为空,均值/中位数为NaN
  • 需要特殊处理并提示用户

📝 依赖项

Python依赖需要确认

pandas >= 1.5.0
numpy >= 1.23.0
scikit-learn >= 1.2.0  # ← MICE需要

前端依赖

  • 无新增依赖使用现有的Ant Design组件

🎯 验收标准

必须满足

  1. MICE功能完全实现(非常重要!)
  2. 新列位置正确(紧邻原列右侧)
  3. 原始数据完全保留(填补不修改原列)
  4. 所有测试用例通过特别是TC-7, TC-8, TC-14
  5. 无Breaking Changes原有删除功能不受影响
  6. UI符合设计稿3个Tab切换流畅
  7. 代码通过Linter检查
  8. 添加适当的日志和错误处理
  9. MICE显示进度条或加载动画

加分项

  1. 性能优于预期
  2. UI动画流畅
  3. 错误提示友好且具体
  4. 添加单元测试

📅 时间估算(已更新)

阶段 预计时间 备注
Python后端 - 简单填补 40分钟 fillna.py基础功能
Python后端 - MICE填补 50分钟 必须实现包括sklearn集成
Python后端 - 新列插入逻辑 30分钟 df.insert()实现,确保新列紧邻原列
Python - main.py端点 20分钟 新增3个API端点
Node.js后端 20分钟 简单转发
前端UI - Tab结构 30分钟 3个Tab切换
前端UI - Tab 2简单填补 40分钟 表单 + 统计 + 新列名输入
前端UI - Tab 3MICE 40分钟 多选列 + 参数 + 进度条
API集成 30分钟 前端调用后端,处理新列名
测试 40分钟 14个测试用例重点测试新列位置
优化和文档 20分钟 错误处理 + 文档
总计 约5-6小时 包含完整MICE实现

说明

  • MICE是医学研究的核心需求必须完整实现
  • 新列插入逻辑需要仔细处理,确保位置正确
  • 前端需要额外时间处理新列名输入和预览

📚 参考资料

缺失值填补理论

医学研究中的缺失值处理

  • 均值/中位数填补:最常用,简单快速
  • MICE高质量研究首选考虑变量间关系
  • 分组填补:不同人群特征差异大时使用

开发前确认清单

已确认事项

  • MICE功能必须开发(医学研究核心需求)
  • 填补方式:创建新列(保留原始数据)
  • 新列位置:紧邻原列(便于对比验证)
  • 无需撤销功能(原始数据未被修改)
  • UI设计符合预期3个Tab切换
  • 功能范围合理Phase 1不包括分组填补、插值等
  • 性能要求合理MICE 10万行<60秒
  • 测试用例完整14个测试用例
  • 时间估算可接受约3-4小时

🚀 准备开始开发

所有确认清单已完成,随时可以开始实施!


📝 更新记录

2025-12-09 更新(根据用户确认)

核心变更

  1. MICE功能必须实现(医学研究核心需求)
  2. 填补方式改为创建新列(保留原始数据)
  3. 新列位置:紧邻原列右侧(便于对比验证)
  4. 取消撤销功能(原始数据未被修改,无需撤销)

影响

  • Python函数签名新增 new_column_name 参数
  • UI新增"新列名"输入框
  • 实现逻辑使用 df.insert() 确保位置正确
  • 测试用例新增新列位置验证TC-7, TC-8
  • 开发时间从3小时增加到5-6小时MICE+新列逻辑)

优势

  • 原始数据完全保留,数据安全性更高
  • 新旧数据并列显示,便于验证填补效果
  • 用户可多次尝试不同填补方法对比
  • 符合医学研究的严谨性要求

已确认,准备开始开发! 🚀