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

698 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 工具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`
```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'],
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`
```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';
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`
```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<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`
```typescript
// 更新按钮组
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后端
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端基础功能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.tsx``MissingValueDialog.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是医学研究的核心需求必须完整实现
- 新列插入逻辑需要仔细处理,确保位置正确
- 前端需要额外时间处理新列名输入和预览
---
## 📚 参考资料
### 缺失值填补理论
- [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设计符合预期3个Tab切换
- [x] 功能范围合理Phase 1不包括分组填补、插值等
- [x] 性能要求合理MICE 10万行<60秒
- [x] 测试用例完整14个测试用例
- [x] 时间估算可接受约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+新列逻辑)
**优势**
- ✅ 原始数据完全保留,数据安全性更高
- ✅ 新旧数据并列显示,便于验证填补效果
- ✅ 用户可多次尝试不同填补方法对比
- ✅ 符合医学研究的严谨性要求
---
**已确认,准备开始开发!** 🚀