# 工具C - 缺失值处理功能开发计? ## 📋 概述 **目标**:将现有?删除缺失?功能升级为综合的"缺失值处?功能,包括删除、填补、高级填补三种策略? **设计方案**:方案B - 合并对话?+ Tab切换 **核心原则**?- ?**填补操作创建新列**(保留原始数据,便于对比?- ?**新列紧邻原列**(方便用户查看和比较?- ?**MICE功能必须实现**(医学研究核心需求) - ?**无需撤销功能**(原始数据未被修改) --- ## 🎯 功能需? ### Phase 1:必备功能(本次开发) #### Tab 1:删除缺失??已有 - 保留现有功能 - 删除包含缺失值的?- 删除缺失率过高的? #### Tab 2:填补缺失??新增 1. **均值填?*(Mean Imputation? - 适用于:数值型变量,正态分? - 实现:创建新列,填充均? 2. **中位数填?*(Median Imputation? - 适用于:数值型变量,偏态分? - 实现:创建新列,填充中位? 3. **众数填补**(Mode Imputation? - 适用于:分类变量、离散型数? - 实现:创建新列,填充众数 4. **固定值填?*(Constant Imputation? - 适用于:任何类型,用户指定? - 实现:创建新列,填充指定? 5. **前向填充**(Forward Fill? - 适用于:时间序列数据、有顺序的观察数? - 实现:`df[column].fillna(method='ffill')`,用前一个非缺失值填? - 示例:[10, NaN, NaN, 20] ?[10, 10, 10, 20] 6. **后向填充**(Backward Fill? - 适用于:时间序列数据、有顺序的观察数? - 实现:`df[column].fillna(method='bfill')`,用后一个非缺失值填? - 示例:[10, NaN, NaN, 20] ?[10, 20, 20, 20] **注意**:所有填补方法都会创建新列(如`体重_填补`),新列紧邻原列,便于对比验证? #### Tab 3:高级填??新增 1. **MICE多重插补**(Multivariate Imputation by Chained Equations? - 适用于:缺失?%-30%,需要考虑变量间关? - 实现:使?`sklearn.impute.IterativeImputer` ### Phase 2:未来扩展(本次不开发) - 分组填补(Grouped Imputation?- 线性插值(Linear Interpolation?- KNN填补(KNN Imputation?- 组合填补(根据条件使用不同填补方法) --- ## 🎨 UI设计 ### 1. 按钮重命?**?*:`[删除缺失值]` **?*:`[缺失值处理]` ### 2. 对话框结? ``` ┌───────────────────────────────────────────────────────?? 缺失值处? [X] ?├───────────────────────────────────────────────────────?? ┌────────┬────────┬──────────? ?? ?删除 ?填补 ?高级填补 ? ?Ant Design Tabs ?? └────────┴────────┴──────────? ?├───────────────────────────────────────────────────────?? ?? 【Tab内容区域? ?? ?? ?? [取消] [执行处理] ?└───────────────────────────────────────────────────────?``` ### 3. Tab 2(填补)详细设计 ``` ┌───────────────────────────────────────────────────────?? 【Tab 2: 填补缺失值? ?? ?? 原始列:[体重(kg)▼] ?? ⚠️ 仅支持单列填? ?? ?? 新列名:[体重_填补 ] ?用户可修? ?? 💡 新列将创建在原列旁边,便于对? ?? ?? 📊 缺失值统计: ?? ┌──────────────────────────────────────────────? ?? ??当前缺失?25个(15.6%? ? ?? ??有效值:675个(84.4%? ? ?? ??数据类型:数值型 ? ?? ??有效值范围:45.2 - 98.5 kg ? ?? ??有效值均值:70.3 kg ? ?? ??有效值中位数?8.5 kg ? ?? ??推荐方法:中位数填补(数据偏态)? ? ?? └──────────────────────────────────────────────? ?? ?? 填补方法? ?? ?均值填补(适合正态分布的数值变量) ?? ?中位数填补(适合偏态分布的数值变量)? ?? ?众数填补(适合分类变量或离散数值) ?? ?固定值填补:[_______] ?用户输入 ?? ?前向填充(用前一个值填充,适合时间序列? ?? ?后向填充(用后一个值填充,适合时间序列? ?? ?? 📈 填补预览? ?? ┌──────────────────────────────────────────────? ?? ??填补值:68.5 kg ? ?? ??填补后均值:70.2 kg(原75.3 kg? ? ?? ??填补后标准差?2.5 kg(原10.8 kg? ? ?? ??将创建新列:"体重_填补" ? ?? ??原列"体重(kg?保持不变 ? ? ?? └──────────────────────────────────────────────? ?? ?? ?优势:原始数据保留,可随时对比验? ?? ?? [取消] [执行填补] ?└───────────────────────────────────────────────────────?``` ### 4. Tab 3(高级填补)详细设计 ``` ┌───────────────────────────────────────────────────────?? 【Tab 3: 高级填补 - MICE多重插补】⭐ 必须实现 ?? ?? ?MICE多重插补 ?? (Multivariate Imputation by Chained Equations? ?? ?? 选择要填补的列(可多选)? ?? ┌──────────────────────────────────────────────? ?? ??体重(kg? 缺失?25?5.6%? ? ?? ??收缩压(mmHg? 缺失?2?0.3%? ? ?? ??BMI 缺失??.4%? ? ?? ??舒张压(mmHg? 缺失??%? ? ?? └──────────────────────────────────────────────? ?? ?? 新列命名规则? ?? ?自动命名:原列名 + "_MICE" ?? 示例:体重(kg??体重(kg)_MICE ?? 收缩压(mmHg??收缩压(mmHg)_MICE ?? ?? 参数设置? ?? 迭代次数:[10▼] (默?0次,范围5-50? ?? 随机种子:[42 ] (确保结果可重复? ?? ?? 📊 MICE说明? ?? ┌──────────────────────────────────────────────? ?? ?MICE会根据其他变量的值来预测缺失值? ? ?? ? ? ?? ??适用场景? ? ?? ? ?缺失?%-30% ? ?? ? ?需要考虑变量间的相关? ? ?? ? ?多个变量同时有缺? ? ?? ? ?医学研究高质量填补的首选方?? ? ?? ? ? ?? ?⚠️ 注意? ? ?? ? ?计算时间较长?0万行?分钟? ? ?? ? ?需要足够的有效样本(建?50%有效? ? ?? ? ?新列将创建在各原列旁边,便于对比 ? ?? └──────────────────────────────────────────────? ?? ?? 💡 新列位置:每个新列紧邻其原列,便于逐列验证 ?? ?? [取消] [执行MICE填补] ?└───────────────────────────────────────────────────────?``` --- ## 🛠?技术实现方? ### 1. Python端(extraction_service? #### 新增文件:`operations/fillna.py` ```python """ 缺失值填?- 预写函数 支持均值、中位数、众数、固定值、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', 'ffill', 'bfill'], fill_value: Any = None ) -> dict: """ 简单填补缺失值(创建新列? Args: df: 输入数据? column: 原始列名 new_column_name: 新列名(?体重_填补"? method: 填补方法 - 'mean': 均值填? - 'median': 中位数填? - 'mode': 众数填补 - 'constant': 固定值填? - 'ffill': 前向填充(用前一个非缺失值) - 'bfill': 后向填充(用后一个非缺失值) 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: 迭代次数(默?0,范?-50? random_state: 随机种子(默?2,确保结果可重复? 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` ```python # 新增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` ```typescript // 新增方法 async executeFillnaSimple(params: { sessionId: string; column: string; method: 'mean' | 'median' | 'mode' | 'constant' | 'ffill' | 'bfill'; fillValue?: any; }): Promise async getFillnaStats(params: { sessionId: string; column: string; }): Promise async executeFillnaMice(params: { sessionId: string; columns: string[]; nIterations: number; }): Promise ``` #### 修改文件:`controllers/QuickActionController.ts` ```typescript // 新增处理方法 async handleFillnaSimple(request, reply) async getFillnaStats(request, reply) async handleFillnaMice(request, reply) ``` ### 3. 前端(frontend-v2? #### 重命名文?- `DropnaDialog.tsx` ?`MissingValueDialog.tsx` #### 修改文件:`MissingValueDialog.tsx` ```typescript 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(''); const [fillMethod, setFillMethod] = useState<'mean' | 'median' | 'mode' | 'constant' | 'ffill' | 'bfill'>('median'); const [fillValue, setFillValue] = useState(null); const [columnStats, setColumnStats] = useState(null); // Tab 1: 删除(保留原有逻辑?// Tab 2: 填补(新增) // Tab 3: MICE(新增) ``` #### 修改文件:`index.tsx` ```typescript // 更新按钮?const actionButtons = [ // ... { key: 'missing', icon: , 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后端 2. `backend/src/modules/dc/tool-c/services/QuickActionService.ts` - 新增 `executeFillnaSimple` 方法 - 新增 `getFillnaStats` 方法 - 新增 `executeFillnaMice` 方法 3. `backend/src/modules/dc/tool-c/controllers/QuickActionController.ts` - 新增 `handleFillnaSimple` 处理方法 - 新增 `getFillnaStats` 处理方法 - 新增 `handleFillnaMice` 处理方法 #### 前端 4. `frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx` - **重命名为** `MissingValueDialog.tsx` - 新增 Tabs 组件(删?填补/高级填补? - Tab 1: 保留原有删除功能 - Tab 2: 新增简单填补功能(均?中位?众数/固定值) - Tab 3: 新增MICE填补功能 5. `frontend-v2/src/modules/dc/pages/tool-c/index.tsx` - 更新按钮标签:`删除缺失值` ?`缺失值处理` - 更新 Dialog 组件引用 6. `frontend-v2/src/modules/dc/api/index.ts` - 新增 `fillnaSimple` API - 新增 `getFillnaStats` API - 新增 `fillnaMice` API --- ## 🔄 开发步? ### Step 1: Python端基础功能?0min?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后端?0min?1. 修改 `QuickActionService.ts` 2. 修改 `QuickActionController.ts` 3. 测试:确保API转发正常 ### Step 4: 前端UI重构?0min?1. 重命?`DropnaDialog.tsx` ?`MissingValueDialog.tsx` 2. 实现Tabs结构 3. Tab 1: 迁移原有删除功能 4. Tab 2: 实现简单填补UI 5. Tab 3: 实现MICE填补UI 6. 更新 `index.tsx` 中的引用和按钮标? ### Step 5: 前端API集成?0min?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%?- 分类列:婚姻状况(缺?0%?- 多列缺失:收缩压?5%? 舒张压(12%?- 时间序列列:随访血压(有顺序,缺失18%? 用于测试?后向填充 ``` #### 测试用例 | 编号 | 功能 | 测试场景 | 预期结果 | |------|------|----------|----------| | TC-1 | 均值填?| ?年龄"列使用均值填补,新列?年龄_填补" | 创建新列,缺失值被均值填充,原列不变 ?| | TC-2 | 中位数填?| ?体重"列使用中位数填补 | 创建新列,缺失值被中位数填??| | TC-3 | 众数填补 | ?婚姻状况"列使用众数填?| 创建新列,缺失值被众数填充 ?| | TC-4 | 固定值填补(数值) | ?年龄"列填充固定?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在大数据集上可能很慢?0万行?分钟?- ?**必须显示进度条或加载动画** - ?添加"预计耗时"提示(基于数据量估算?- ?提供"取消执行"按钮(长时间任务?- 💡 优化建议:考虑使用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 3(MICE??| 40分钟 | 多选列 + 参数 + 进度?| | API集成 | 30分钟 | 前端调用后端,处理新列名 | | 测试 | 40分钟 | 14个测试用例,重点测试新列位置 | | 优化和文?| 20分钟 | 错误处理 + 文档 | | **总计** | **?-6小时** | **包含完整MICE实现** ?| **说明**?- MICE是医学研究的核心需求,必须完整实现 - 新列插入逻辑需要仔细处理,确保位置正确 - 前端需要额外时间处理新列名输入和预? --- ## 📚 参考资? ### 缺失值填补理?- [sklearn.impute.IterativeImputer文档](https://scikit-learn.org/stable/modules/generated/sklearn.impute.IterativeImputer.html) - [MICE算法原理](https://www.jstatsoft.org/article/view/v045i03) ### 医学研究中的缺失值处?- 均?中位数填补:最常用,简单快?- MICE:高质量研究首选,考虑变量间关?- 分组填补:不同人群特征差异大时使? --- ## ?开发前确认清单 已确认事?✅: - [x] **MICE功能必须开?*(医学研究核心需求)?- [x] **填补方式:创建新?*(保留原始数据)?- [x] **新列位置:紧邻原?*(便于对比验证)?- [x] **无需撤销功能**(原始数据未被修改)?- [x] UI设计符合预期?个Tab切换)✅ - [x] 功能范围合理(Phase 1不包括分组填补、插值等)✅ - [x] 性能要求合理(MICE 10万行<60秒)?- [x] 测试用例完整?4个测试用例)?- [x] 时间估算可接受(?-4小时)✅ ## 🚀 准备开始开? 所有确认清单已完成,随时可以开始实施! --- ## 📝 更新记录 ### 2025-12-10 更新(用户要求) **新增功能**?1. ?**前向/后向填充加入本次开?*(原计划在Phase 2? - 前向填充(Forward Fill):用前一个非缺失值填? - 后向填充(Backward Fill):用后一个非缺失值填? - 适用场景:时间序列数据、有顺序的观察数? **影响**?- Tab 2新增2个填补选项(共6种方法) - Python函数 `fillna_simple` 方法参数新增 `'ffill'` ?`'bfill'` - 测试用例?4个增加到18?- 开发时间从5-6小时增加?-7小时 **适用场景说明**?- 均?中位数:适合独立观察的数值变?- 众数:适合分类变量 - 固定值:用户自定义场?- **前向填充**:随访数据(如多次测量,用上次值填充) - **后向填充**:预测性数据(用未来已知值填充) - MICE:需要考虑变量间关系的高质量填? --- ### 2025-12-09 更新(根据用户确认) **核心变更**?1. ?**MICE功能必须实现**(医学研究核心需求) 2. ?**填补方式改为创建新列**(保留原始数据) 3. ?**新列位置:紧邻原列右?*(便于对比验证) 4. ?**取消撤销功能**(原始数据未被修改,无需撤销? **影响**?- Python函数签名新增 `new_column_name` 参数 - UI新增"新列?输入?- 实现逻辑使用 `df.insert()` 确保位置正确 - 测试用例新增新列位置验证(TC-7, TC-8?- 开发时间从3小时增加?-6小时(MICE+新列逻辑? **优势**?- ?原始数据完全保留,数据安全性更?- ?新旧数据并列显示,便于验证填补效?- ?用户可多次尝试不同填补方法对?- ?符合医学研究的严谨性要? --- **已确认,准备开始开发!** 🚀