Major features: 1. Missing value imputation (6 simple methods + MICE): - Mean/Median/Mode/Constant imputation - Forward fill (ffill) and Backward fill (bfill) for time series - MICE multivariate imputation (in progress, shape issue to fix) 2. Auto precision detection: - Automatically match decimal places of original data - Prevent false precision (e.g. 13.57 instead of 13.566716417910449) 3. Categorical variable detection: - Auto-detect and skip categorical columns in MICE - Show warnings for unsuitable columns - Suggest mode imputation for categorical data 4. UI improvements: - Rename button: "Delete Missing" to "Missing Value Handling" - Remove standalone "Dedup" and "MICE" buttons - 3-tab dialog: Delete / Fill / Advanced Fill - Display column statistics and recommended methods - Extended warning messages (8 seconds for skipped columns) 5. Bug fixes: - Fix sessionService.updateSessionData -> saveProcessedData - Fix OperationResult interface (add message and stats) - Fix Toolbar button labels and removal Modified files: Python: operations/fillna.py (new, 556 lines), main.py (3 new endpoints) Backend: QuickActionService.ts, QuickActionController.ts, routes/index.ts Frontend: MissingValueDialog.tsx (new, 437 lines), Toolbar.tsx, index.tsx Tests: test_fillna_operations.py (774 lines), test scripts and docs Docs: 5 documentation files updated Known issues: - MICE imputation has DataFrame shape mismatch issue (under debugging) - Workaround: Use 6 simple imputation methods first Status: Development complete, MICE debugging in progress Lines added: ~2000 lines across 3 tiers
961 lines
35 KiB
Markdown
961 lines
35 KiB
Markdown
# 工具C 功能按钮开发计划 V1.0
|
||
|
||
**文档版本**: V1.4 (Phase 2+ 缺失值填补功能开发版)
|
||
**创建日期**: 2025-12-08
|
||
**最后更新**: 2025-12-10
|
||
**负责人**: AI开发团队
|
||
**项目状态**: ✅ Phase 1-2 已完成,7个核心功能 + NA处理优化 + Pivot优化 + 缺失值填补(开发完成,MICE待调试)
|
||
|
||
---
|
||
|
||
## 🔥 重要架构变更(2025-12-08)
|
||
|
||
**决策**:功能按钮采用**预写Python函数**架构,而非动态代码生成。
|
||
|
||
**变更原因**:
|
||
- ❌ 旧方案:动态拼接Python代码字符串 → 不稳定、有安全风险、难以测试
|
||
- ✅ 新方案:调用预写的Python函数 → 稳定、安全、高性能、易维护
|
||
|
||
**当前完成**(2025-12-08):
|
||
- ✅ Python微服务:`operations/` 模块
|
||
- filter.py(高级筛选)
|
||
- recode.py(数值映射)
|
||
- binning.py(生成分类变量)
|
||
- conditional.py(条件生成列)
|
||
- dropna.py(删除缺失值)
|
||
- compute.py(计算列)
|
||
- pivot.py(长表转宽表)
|
||
- ✅ Python微服务:7个API端点(`/api/operations/*`)
|
||
- ✅ Node.js后端:`QuickActionService.ts`(7个执行方法)
|
||
- ✅ Node.js后端:`QuickActionController.ts`(完整错误处理)
|
||
- ✅ 前端UI:7个Dialog组件(完整交互界面)
|
||
- ✅ 前端工具栏:7个功能按钮(已启用)
|
||
- ✅ 删除:`QuickActionCodeGenerator.ts`(不再使用)
|
||
|
||
**架构对比**:
|
||
|
||
| 维度 | 旧方案 | ✅ 新方案 |
|
||
|------|--------|---------|
|
||
| 稳定性 | ⚠️ 字符串拼接易出错 | ✅ 预写函数经过测试 |
|
||
| 安全性 | ⚠️ 有注入风险 | ✅ 无代码注入风险 |
|
||
| 性能 | ⚠️ 需解析代码 | ✅ 直接调用函数 |
|
||
| 可维护 | ⚠️ 后端拼接字符串 | ✅ Python集中管理 |
|
||
| 可测试 | ❌ 难以测试 | ✅ 易于单元测试 |
|
||
|
||
---
|
||
|
||
## 📋 文档目录
|
||
|
||
- [1. 概述](#1-概述)
|
||
- [2. 设计原则](#2-设计原则)
|
||
- [3. 功能清单](#3-功能清单)
|
||
- [4. 分期开发计划](#4-分期开发计划)
|
||
- [5. 技术架构](#5-技术架构)
|
||
- [6. 详细设计](#6-详细设计)
|
||
- [7. 验收标准](#7-验收标准)
|
||
|
||
---
|
||
|
||
## 1. 概述
|
||
|
||
### 1.1 背景
|
||
|
||
工具C当前已实现AI对话式数据清洗功能。为提升用户体验和操作效率,需要针对**高频、通用、标准化**的数据清洗操作开发功能按钮,实现**一键式操作**。
|
||
|
||
### 1.2 目标
|
||
|
||
- ✅ 提升高频操作的效率(从"描述需求"到"一键点击")
|
||
- ✅ 降低学习成本(直观的UI代替自然语言描述)
|
||
- ✅ 保持灵活性(复杂需求仍可使用AI对话)
|
||
- ✅ 符合医疗科研用户习惯(参考SPSS、Excel等专业工具)
|
||
|
||
### 1.3 适用场景
|
||
|
||
**功能按钮适合:**
|
||
- 高频使用(每个数据集都需要)
|
||
- 操作通用(不依赖特定业务规则)
|
||
- 参数明确(可以通过UI配置)
|
||
- 逻辑简单(1-3步即可完成)
|
||
|
||
**AI对话适合:**
|
||
- 低频使用(偶尔用一次)
|
||
- 业务特定(规则各异)
|
||
- 复杂逻辑(多步骤、多条件)
|
||
- 探索性操作(需理解上下文)
|
||
|
||
---
|
||
|
||
## 2. 设计原则
|
||
|
||
### 2.1 用户体验原则
|
||
|
||
1. **80/20法则**:用按钮解决80%的简单需求,用AI对话解决20%的复杂需求
|
||
2. **渐进式披露**:简单功能默认显示,复杂选项折叠/高级模式
|
||
3. **即时反馈**:提供预览功能,让用户在执行前看到结果
|
||
4. **可撤销性**:支持撤销(未来版本)或提供"创建副本"选项
|
||
|
||
### 2.2 技术原则
|
||
|
||
1. **✅ 预写函数架构**:功能按钮调用预写的、经过测试的Python函数(而非动态生成代码)
|
||
2. **无状态设计**:每个操作独立,不依赖前序状态
|
||
3. **安全可靠**:预写函数经过充分测试和验证,无代码注入风险
|
||
4. **性能优先**:直接调用函数,避免代码解析开销,优化大数据集处理
|
||
|
||
---
|
||
|
||
## 3. 功能清单
|
||
|
||
### 3.1 按分组划分
|
||
|
||
| 分组 | 功能 | 优先级 | 开发状态 |
|
||
|------|------|--------|---------|
|
||
| **样本筛选** | 高级筛选器 | P0 | ✅ 已完成(+为空/不为空条件)|
|
||
| **变量转换** | 数值映射(重编码)| P0 | ✅ 已完成(+NA处理选项)|
|
||
| | 生成分类变量(分箱)| P0 | ✅ 已完成(+NA处理选项)|
|
||
| | 条件生成列 | P0 | ✅ 已完成(+为空/不为空条件)|
|
||
| | 生成新变量(计算列)| P1 | ✅ 已完成(方案B:安全列名映射)|
|
||
| **数据清理** | 缺失值处理(删除+填补)| P0 | ✅ 已完成(6种简单填补+MICE,MICE待调试)|
|
||
| | 去重 | P1 | ⏸️ 已移除(用户需求)|
|
||
| **数据重塑** | 长表→宽表(Pivot)| P1 | ✅ 已完成(+保留未选列+原始列顺序)|
|
||
| **高级功能** | 多重插补(MICE)| P0 | 🚧 已集成到缺失值处理(待调试)|
|
||
|
||
**优先级说明**:
|
||
- **P0**:核心功能,Phase 1-2 必须完成
|
||
- **P1**:重要功能,Phase 3 完成
|
||
- **P2**:增强功能,Phase 4 可选
|
||
|
||
### 3.2 不开发的功能
|
||
|
||
| 功能 | 原因 |
|
||
|------|------|
|
||
| 清理列名 | 暂不开发(用户需求) |
|
||
| 宽表→长表 | 低频需求,暂不开发 |
|
||
| 数据透视表 | 超出MVP范围 |
|
||
| 统计分析 | 属于统计分析模块,非数据清洗 |
|
||
|
||
---
|
||
|
||
## 4. 分期开发计划
|
||
|
||
### Phase 1:核心功能(Week 1,预计5天)✅ 已完成
|
||
|
||
**目标**:解决最高频的3个需求
|
||
|
||
| 功能 | 工作量 | 状态 | 验收标准 |
|
||
|------|--------|------|---------|
|
||
| 1. 高级筛选器 | 2天 | ✅ 完成 | 支持多条件AND/OR,实时预览 |
|
||
| 2. 数值映射(重编码)| 1.5天 | ✅ 完成 | 自动提取唯一值,支持批量映射 |
|
||
| 3. 生成分类变量(分箱)| 1.5天 | ✅ 完成 | 支持自定义切点、等宽、等频 |
|
||
|
||
**里程碑**:✅ Week 1完成,3个核心功能可用(2025-12-08)
|
||
|
||
---
|
||
|
||
### Phase 2:条件生成+清理(Week 2,预计5天)✅ 已完成
|
||
|
||
**目标**:解决复杂条件逻辑需求
|
||
|
||
| 功能 | 工作量 | 状态 | 验收标准 |
|
||
|------|--------|------|---------|
|
||
| 4. 条件生成列 | 2天 | ✅ 完成 | 支持多条件IF-THEN规则 |
|
||
| 5. 删除缺失值 | 1天 | ✅ 完成 | 支持按行/列删除,预览影响 |
|
||
| 6. 去重 | 1天 | ⏸️ 暂不开发 | 用户决定暂不开发 |
|
||
| 7. 计算列 | 1天 | ✅ 完成 | 公式构建器,支持常用函数 |
|
||
| 8. Pivot(长→宽表)| 1天 | ✅ 完成 | 支持多值列转换,聚合选项 |
|
||
|
||
**里程碑**:✅ Week 2完成,7个核心功能可用(2025-12-08)
|
||
|
||
---
|
||
|
||
### Phase 3:数据重塑+填补(Week 3-4,预计8天)
|
||
|
||
**目标**:支持复杂数据转换
|
||
|
||
| 功能 | 工作量 | 负责人 | 验收标准 |
|
||
|------|--------|--------|---------|
|
||
| 8. 长表→宽表(Pivot)| 2天 | 前端+后端 | 支持多值列转换 |
|
||
| 9. 生成新变量(计算列)| 2天 | 前端+后端 | 公式构建器,支持常用函数 |
|
||
| 10. 缺失值填补 | 1.5天 | 前端+后端 | 支持均值/中位数/分组填补 |
|
||
| 11. 多重插补(MICE)| 1.5天 | Python微服务 | 集成sklearn,支持基础MICE |
|
||
| 12. 测试+文档 | 1天 | 全员 | 完成用户手册 |
|
||
|
||
**里程碑**:Week 4结束,所有P0/P1功能完成
|
||
|
||
---
|
||
|
||
### Phase 4:优化+增强(Week 5+,持续迭代)
|
||
|
||
- ✅ 性能优化(大数据集>10万行)
|
||
- ✅ 批量操作(批量重编码、批量删除列等)
|
||
- ✅ 操作历史(查看/回退历史操作)
|
||
- ✅ 保存为模板(常用操作保存为快捷方式)
|
||
- ✅ 数据验证(自动检查数据质量)
|
||
|
||
---
|
||
|
||
## 5. 技术架构
|
||
|
||
### 5.1 ✅ 整体架构(预写函数方案)
|
||
|
||
**架构决策**:功能按钮使用**预写Python函数**,而非动态生成代码,确保稳定性和性能。
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────┐
|
||
│ 前端 (React + Ant Design) │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ 工具栏组件 │ │
|
||
│ │ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ │
|
||
│ │ │筛选│ │重编│ │分箱│ │条件│ ... │ │
|
||
│ │ └────┘ └────┘ └────┘ └────┘ │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ 配置对话框(各功能独立) │ │
|
||
│ │ - 参数输入 │ │
|
||
│ │ - 实时预览 │ │
|
||
│ │ - 执行按钮 │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
└────────────────────┬────────────────────────────┘
|
||
│ HTTP POST
|
||
↓
|
||
┌─────────────────────────────────────────────────┐
|
||
│ 后端 (Node.js + Fastify) │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ QuickActionController │ │
|
||
│ │ - 接收功能按钮请求 │ │
|
||
│ │ - 验证参数 │ │
|
||
│ │ - 调用QuickActionService │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ ✅ QuickActionService (新) │ │
|
||
│ │ - executeFilter() 调用预写函数API │ │
|
||
│ │ - executeRecode() 调用预写函数API │ │
|
||
│ │ - executeBinning() 调用预写函数API │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
└────────────────────┬────────────────────────────┘
|
||
│ HTTP POST /api/operations/xxx
|
||
↓
|
||
┌─────────────────────────────────────────────────┐
|
||
│ Python微服务 (FastAPI) │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ ✅ operations/ (预写函数模块) │ │
|
||
│ │ - filter.py (筛选) │ │
|
||
│ │ - recode.py (重编码) │ │
|
||
│ │ - binning.py (分箱) │ │
|
||
│ │ - conditional.py (条件生成,待开发) │ │
|
||
│ │ - missing.py (缺失值处理,待开发) │ │
|
||
│ │ 每个函数: │ │
|
||
│ │ ✓ 经过单元测试 │ │
|
||
│ │ ✓ 有完整类型注解 │ │
|
||
│ │ ✓ 有详细文档 │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ ✅ API端点 (新) │ │
|
||
│ │ POST /api/operations/filter │ │
|
||
│ │ POST /api/operations/recode │ │
|
||
│ │ POST /api/operations/binning │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────┘
|
||
```
|
||
|
||
**✅ 优势**:
|
||
- ✅ **稳定性高**:预写函数经过单元测试,无字符串拼接风险
|
||
- ✅ **性能好**:直接调用函数,无代码解析开销
|
||
- ✅ **可维护**:代码集中在Python侧,便于优化
|
||
- ✅ **安全**:无代码注入风险
|
||
|
||
**❌ 已废弃**:
|
||
- ~~QuickActionCodeGenerator.ts~~ (已删除)
|
||
- ~~动态代码生成方案~~ (已弃用)
|
||
|
||
### 5.2 ✅ API设计(重构后)
|
||
|
||
#### Node.js后端API(前端调用)
|
||
|
||
```typescript
|
||
// 执行快速操作
|
||
POST /api/v1/dc/tool-c/quick-action
|
||
Body: {
|
||
sessionId: string,
|
||
action: 'filter' | 'recode' | 'binning' | 'conditional' | ...,
|
||
params: {
|
||
// 各功能特定参数
|
||
}
|
||
}
|
||
Response: {
|
||
success: boolean,
|
||
data: {
|
||
newDataPreview: Array<Object>, // 前50行预览
|
||
affectedRows: number, // 影响的行数
|
||
message: string, // 操作说明
|
||
executionTime: number, // Python执行时间(秒)
|
||
output: string // Python打印输出
|
||
}
|
||
}
|
||
|
||
// 预览操作结果(不实际执行)
|
||
POST /api/v1/dc/tool-c/quick-action/preview
|
||
Body: { 同上 }
|
||
Response: {
|
||
success: boolean,
|
||
data: {
|
||
preview: Array<Object>, // 前10行预览
|
||
estimatedChange: string, // "将删除23行" / "将新增1列"
|
||
originalRows: number,
|
||
newRows: number
|
||
}
|
||
}
|
||
```
|
||
|
||
#### ✅ Python微服务API(后端调用,新增)
|
||
|
||
**注意**:以下URL仅为示例,实际代码中使用环境变量 `EXTRACTION_SERVICE_URL` 配置。
|
||
|
||
```python
|
||
# 高级筛选(示例URL)
|
||
POST http://localhost:8000/api/operations/filter
|
||
Body: {
|
||
"data": [{"年龄": 25, "性别": "男"}, ...],
|
||
"conditions": [
|
||
{"column": "年龄", "operator": ">", "value": 30},
|
||
{"column": "性别", "operator": "=", "value": "男"}
|
||
],
|
||
"logic": "and" # or "or"
|
||
}
|
||
Response: {
|
||
"success": true,
|
||
"result_data": [...], # 筛选后的数据
|
||
"output": "原始数据: 100 行\n筛选后: 30 行...",
|
||
"execution_time": 0.023,
|
||
"result_shape": [30, 5]
|
||
}
|
||
|
||
# 数值映射(重编码)
|
||
POST http://localhost:8000/api/operations/recode
|
||
Body: {
|
||
"data": [{"性别": "男"}, {"性别": "女"}, ...],
|
||
"column": "性别",
|
||
"mapping": {"男": 1, "女": 2},
|
||
"create_new_column": true,
|
||
"new_column_name": "性别_编码"
|
||
}
|
||
Response: {
|
||
"success": true,
|
||
"result_data": [...],
|
||
"output": "映射完成: 96 个值成功映射\n映射成功率: 100.0%",
|
||
"execution_time": 0.015,
|
||
"result_shape": [96, 6]
|
||
}
|
||
|
||
# 生成分类变量(分箱)
|
||
POST http://localhost:8000/api/operations/binning
|
||
Body: {
|
||
"data": [{"年龄": 25}, {"年龄": 35}, ...],
|
||
"column": "年龄",
|
||
"method": "custom", # or "equal_width", "equal_freq"
|
||
"new_column_name": "年龄分组",
|
||
"bins": [18, 60], # 自定义切点
|
||
"labels": ["青少年", "成年", "老年"]
|
||
}
|
||
Response: {
|
||
"success": true,
|
||
"result_data": [...],
|
||
"output": "分箱结果分布:\n 青少年: 10 行 (10.4%)\n 成年: 70 行 (72.9%)...",
|
||
"execution_time": 0.018,
|
||
"result_shape": [96, 6]
|
||
}
|
||
```
|
||
|
||
### 5.3 ✅ 预写函数服务设计(重构后)
|
||
|
||
#### Node.js后端服务
|
||
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/services/QuickActionService.ts
|
||
|
||
export class QuickActionService {
|
||
|
||
// 调用Python微服务的预写函数API
|
||
async executeFilter(data: any[], params: FilterParams): Promise<OperationResult> {
|
||
return axios.post(`${PYTHON_SERVICE_URL}/api/operations/filter`, {
|
||
data,
|
||
conditions: params.conditions,
|
||
logic: params.logic,
|
||
});
|
||
}
|
||
|
||
async executeRecode(data: any[], params: RecodeParams): Promise<OperationResult> {
|
||
return axios.post(`${PYTHON_SERVICE_URL}/api/operations/recode`, {
|
||
data,
|
||
column: params.column,
|
||
mapping: params.mapping,
|
||
create_new_column: params.createNewColumn,
|
||
new_column_name: params.newColumnName,
|
||
});
|
||
}
|
||
|
||
async executeBinning(data: any[], params: BinningParams): Promise<OperationResult> {
|
||
return axios.post(`${PYTHON_SERVICE_URL}/api/operations/binning`, {
|
||
data,
|
||
column: params.column,
|
||
method: params.method,
|
||
new_column_name: params.newColumnName,
|
||
bins: params.bins,
|
||
labels: params.labels,
|
||
num_bins: params.numBins,
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Python预写函数
|
||
|
||
```python
|
||
# extraction_service/operations/filter.py
|
||
def apply_filter(df: pd.DataFrame, conditions: List[Dict], logic: str) -> pd.DataFrame:
|
||
"""
|
||
应用筛选条件(预写函数,经过充分测试)
|
||
|
||
Args:
|
||
df: 输入数据框
|
||
conditions: 筛选条件列表
|
||
logic: 'and' 或 'or'
|
||
|
||
Returns:
|
||
筛选后的数据框
|
||
"""
|
||
# 生成各个条件的mask
|
||
masks = []
|
||
for cond in conditions:
|
||
column = cond['column']
|
||
operator = cond['operator']
|
||
value = cond.get('value')
|
||
|
||
if operator == '=':
|
||
mask = df[column] == value
|
||
elif operator == '>':
|
||
mask = df[column] > value
|
||
# ... 其他运算符
|
||
|
||
masks.append(mask)
|
||
|
||
# 组合条件
|
||
if logic == 'and':
|
||
final_mask = pd.concat(masks, axis=1).all(axis=1)
|
||
else:
|
||
final_mask = pd.concat(masks, axis=1).any(axis=1)
|
||
|
||
return df[final_mask].copy()
|
||
|
||
# extraction_service/main.py
|
||
@app.post("/api/operations/filter")
|
||
async def operation_filter(request: FilterRequest):
|
||
"""调用预写函数"""
|
||
df = pd.DataFrame(request.data)
|
||
result_df = apply_filter(df, request.conditions, request.logic)
|
||
return JSONResponse(content={
|
||
"success": True,
|
||
"result_data": result_df.to_dict('records'),
|
||
"execution_time": execution_time,
|
||
...
|
||
})
|
||
```
|
||
|
||
**✅ 优势**:
|
||
- 预写函数经过单元测试,稳定可靠
|
||
- 无字符串拼接,无代码注入风险
|
||
- 直接调用函数,性能优秀
|
||
- 代码集中管理,易于维护和优化
|
||
|
||
**❌ 已废弃**:
|
||
- ~~QuickActionCodeGenerator.ts~~ (已删除,不再使用动态代码生成)
|
||
|
||
### 5.4 环境变量配置
|
||
|
||
**重要**:代码中使用环境变量配置Python微服务地址,**不使用硬编码**。
|
||
|
||
#### Node.js后端配置
|
||
|
||
在 `backend/.env` 中配置:
|
||
|
||
```bash
|
||
# Python微服务地址(必需)
|
||
EXTRACTION_SERVICE_URL=http://localhost:8000
|
||
|
||
# 生产环境示例
|
||
# EXTRACTION_SERVICE_URL=http://python-service:8000
|
||
# EXTRACTION_SERVICE_URL=https://api.yourdomain.com/python
|
||
```
|
||
|
||
#### 代码实现
|
||
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/services/QuickActionService.ts
|
||
const PYTHON_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000';
|
||
|
||
// 调用时使用环境变量
|
||
await axios.post(`${PYTHON_SERVICE_URL}/api/operations/filter`, {...});
|
||
```
|
||
|
||
**✅ 优势**:
|
||
- 开发环境:使用 `localhost:8000`
|
||
- 生产环境:使用内网地址或域名
|
||
- 容器化部署:使用服务名(如 `http://python-service:8000`)
|
||
- 符合云原生开发规范
|
||
|
||
---
|
||
|
||
## 6. 详细设计
|
||
|
||
### 6.1 高级筛选器
|
||
|
||
#### UI设计
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ 高级筛选 │
|
||
├─────────────────────────────────────────┤
|
||
│ ┌─────────────────────────────────────┐│
|
||
│ │ [列名 ▼] [条件 ▼] [值_________] ││
|
||
│ └─────────────────────────────────────┘│
|
||
│ [且 ▼] │
|
||
│ ┌─────────────────────────────────────┐│
|
||
│ │ [列名 ▼] [条件 ▼] [值_________] ││
|
||
│ └─────────────────────────────────────┘│
|
||
│ [+ 添加条件] │
|
||
│ │
|
||
│ 预览:将保留 87 行(共100行) │
|
||
│ │
|
||
│ [取消] [预览] [应用] │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 条件运算符
|
||
|
||
- 数值列:`=`, `≠`, `>`, `<`, `≥`, `≤`
|
||
- 文本列:`等于`, `不等于`, `包含`, `不包含`, `以...开头`, `以...结尾`
|
||
- 通用:`为空`, `不为空`
|
||
|
||
#### 生成代码示例
|
||
|
||
```python
|
||
# 单条件
|
||
df = df[df['年龄'] >= 18]
|
||
|
||
# 多条件 AND
|
||
df = df[(df['年龄'] >= 18) & (df['性别'] == '男')]
|
||
|
||
# 多条件 OR
|
||
df = df[(df['年龄'] >= 60) | (df['BMI'] >= 28)]
|
||
|
||
# 包含
|
||
df = df[df['诊断'].str.contains('糖尿病', na=False)]
|
||
|
||
# 不为空
|
||
df = df[df['BMI'].notna()]
|
||
```
|
||
|
||
---
|
||
|
||
### 6.2 数值映射(重编码)
|
||
|
||
#### UI设计
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ 变量重编码 │
|
||
├─────────────────────────────────────┤
|
||
│ 选择列:[研究中心 ▼] │
|
||
│ │
|
||
│ 自动检测到 3 个唯一值: │
|
||
│ ┌─────────────────┬─────────────┐ │
|
||
│ │ 原值 │ 新值 │ │
|
||
│ ├─────────────────┼─────────────┤ │
|
||
│ │ 黑龙江中医药... │ [1______] │ │
|
||
│ │ 山东中医药... │ [2______] │ │
|
||
│ │ 广州中医药... │ [3______] │ │
|
||
│ └─────────────────┴─────────────┘ │
|
||
│ │
|
||
│ ☑️ 创建新列(推荐) │
|
||
│ 新列名:[研究中心_编码_______] │
|
||
│ │
|
||
│ [取消] [预览] [执行] │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
#### 生成代码示例
|
||
|
||
```python
|
||
# 创建新列
|
||
mapping = {
|
||
'黑龙江中医药大学附属第二医院': 1,
|
||
'山东中医药大学附属医院': 2,
|
||
'广州中医药大学附属第一医院': 3
|
||
}
|
||
df['研究中心_编码'] = df['研究中心'].map(mapping)
|
||
|
||
# 或覆盖原列
|
||
df['研究中心'] = df['研究中心'].map(mapping)
|
||
```
|
||
|
||
---
|
||
|
||
### 6.3 生成分类变量(分箱)
|
||
|
||
#### UI设计
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ 连续变量分箱 │
|
||
├─────────────────────────────────────┤
|
||
│ 选择数值列:[督脉针刺持续时间 ▼] │
|
||
│ │
|
||
│ 分箱方式: │
|
||
│ ● 自定义切点 │
|
||
│ 切点:[10] [+] │
|
||
│ 标签: │
|
||
│ ≥10: [暴露=1_____] │
|
||
│ <10: [非暴露=0___] │
|
||
│ │
|
||
│ ○ 多段切点 │
|
||
│ 切点:[0] [14] [30] [999] │
|
||
│ 标签:[低=0][中=1][高=2] │
|
||
│ │
|
||
│ 新列名:[住院患者暴露分组_____] │
|
||
│ │
|
||
│ [取消] [预览分布] [执行] │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
#### 生成代码示例
|
||
|
||
```python
|
||
# 二分类(单切点)
|
||
df['住院患者暴露分组'] = (df['督脉针刺持续时间'] >= 10).astype(int)
|
||
|
||
# 多分类(多切点)
|
||
df['暴露强度分组'] = pd.cut(
|
||
df['督脉针刺持续时间'],
|
||
bins=[0, 14, 30, 999],
|
||
labels=[0, 1, 2],
|
||
right=False
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
### 6.4 条件生成列 ⭐核心功能
|
||
|
||
#### UI设计
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ 条件生成新列 │
|
||
├─────────────────────────────────────────┤
|
||
│ 新列名:[住院暴露出院暴露情况分组____] │
|
||
│ │
|
||
│ 规则(按顺序匹配): │
|
||
│ ┌───────────────────────────────────┐ │
|
||
│ │ 规则1 │ │
|
||
│ │ IF [住院患者暴露分组▼] [=▼] [1] │ │
|
||
│ │ [且▼] │ │
|
||
│ │ IF [督脉针刺持续时间▼] [>=▼][14] │ │
|
||
│ │ THEN 值为:[住院暴露出院暴露____] │ │
|
||
│ │ [删除规则]│ │
|
||
│ └───────────────────────────────────┘ │
|
||
│ ┌───────────────────────────────────┐ │
|
||
│ │ 规则2 │ │
|
||
│ │ IF [住院患者暴露分组▼] [=▼] [1] │ │
|
||
│ │ [且▼] │ │
|
||
│ │ IF [督脉针刺持续时间▼] [<▼] [14] │ │
|
||
│ │ THEN 值为:[住院暴露出院非暴露__] │ │
|
||
│ │ [删除规则]│ │
|
||
│ └───────────────────────────────────┘ │
|
||
│ [+ 添加规则] │
|
||
│ │
|
||
│ 其他情况(ELSE): │
|
||
│ ● 留空(None) │
|
||
│ ○ 固定值:[_______] │
|
||
│ ○ 使用默认值:[0______] │
|
||
│ │
|
||
│ 预览:将生成新列,预计87行有值 │
|
||
│ │
|
||
│ [取消] [预览前10行] [执行] │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 技术实现
|
||
|
||
**前端数据结构**:
|
||
```typescript
|
||
interface ConditionalRule {
|
||
conditions: Array<{
|
||
column: string,
|
||
operator: '=' | '!=' | '>' | '<' | '>=' | '<=',
|
||
value: string | number
|
||
}>,
|
||
logic: 'and' | 'or',
|
||
result: string | number
|
||
}
|
||
|
||
interface ConditionalParams {
|
||
newColumnName: string,
|
||
rules: ConditionalRule[],
|
||
elseValue: null | string | number
|
||
}
|
||
```
|
||
|
||
**生成代码示例**:
|
||
```python
|
||
def classify_exposure(row):
|
||
# 规则1
|
||
if row['住院患者暴露分组'] == 1 and row['督脉针刺持续时间'] >= 14:
|
||
return '住院暴露出院暴露'
|
||
# 规则2
|
||
elif row['住院患者暴露分组'] == 1 and row['督脉针刺持续时间'] < 14:
|
||
return '住院暴露出院非暴露'
|
||
# ELSE
|
||
else:
|
||
return None
|
||
|
||
df['住院暴露出院暴露情况分组'] = df.apply(classify_exposure, axis=1)
|
||
```
|
||
|
||
---
|
||
|
||
### 6.5 长表→宽表(Pivot)
|
||
|
||
#### UI设计
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ 长表转宽表(Pivot) │
|
||
├─────────────────────────────────────┤
|
||
│ 索引列(唯一标识): │
|
||
│ [Record ID ▼] │
|
||
│ │
|
||
│ 透视列(变成列名): │
|
||
│ [Event Name ▼] │
|
||
│ 检测到的值: │
|
||
│ • 筛选及基线 │
|
||
│ • 随访(2周) │
|
||
│ • 随访(1个月) │
|
||
│ │
|
||
│ 值列(要转置的数据): │
|
||
│ ☑️ FMA总得分 │
|
||
│ ☑️ FMA分级(1-5) │
|
||
│ ☑️ ADL总分 │
|
||
│ ☑️ NLR │
|
||
│ ☑️ PLR │
|
||
│ [ ] ...(选择其他列) │
|
||
│ │
|
||
│ 重复值处理: │
|
||
│ ● 取第一个 ○ 取最后一个 │
|
||
│ ○ 求平均值 ○ 求和 │
|
||
│ │
|
||
│ [取消] [预览结构] [执行] │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
#### 生成代码示例
|
||
|
||
```python
|
||
# Pivot转换
|
||
df_pivot = df.pivot_table(
|
||
index='Record ID',
|
||
columns='Event Name',
|
||
values=['FMA总得分', 'FMA分级(1-5)', 'ADL总分', 'NLR', 'PLR'],
|
||
aggfunc='first'
|
||
)
|
||
|
||
# 展平多级列名
|
||
df_pivot.columns = ['_'.join(col).strip() for col in df_pivot.columns.values]
|
||
df_pivot = df_pivot.reset_index()
|
||
|
||
# 示例:FMA总得分_筛选及基线, FMA总得分_随访(2周)
|
||
```
|
||
|
||
---
|
||
|
||
### 6.6 多重插补(MICE)
|
||
|
||
#### UI设计
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ 多重插补(MICE) │
|
||
├─────────────────────────────────────┤
|
||
│ ⚠️ 高级统计功能,需谨慎使用 │
|
||
│ │
|
||
│ 选择需要插补的列: │
|
||
│ ☑️ 年龄 │
|
||
│ ☑️ BMI │
|
||
│ ☑️ 血糖 │
|
||
│ [ ] 血压 │
|
||
│ [ ] ... │
|
||
│ │
|
||
│ 参数设置: │
|
||
│ 迭代次数:[10____](推荐5-20) │
|
||
│ 随机种子:[42____](可重复结果) │
|
||
│ │
|
||
│ 预计插补:32个缺失值 │
|
||
│ │
|
||
│ ⚠️ 注意: │
|
||
│ • MICE假设数据MAR(随机缺失) │
|
||
│ • 插补时间较长(大数据集>1分钟) │
|
||
│ • 建议先备份原数据 │
|
||
│ │
|
||
│ [取消] [执行] │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
#### 技术实现
|
||
|
||
**依赖库**:需在Python微服务中安装 `scikit-learn`
|
||
|
||
```python
|
||
from sklearn.experimental import enable_iterative_imputer
|
||
from sklearn.impute import IterativeImputer
|
||
|
||
# 选择需要插补的列
|
||
cols_to_impute = ['年龄', 'BMI', '血糖']
|
||
df_subset = df[cols_to_impute]
|
||
|
||
# MICE插补
|
||
imputer = IterativeImputer(
|
||
max_iter=10,
|
||
random_state=42,
|
||
verbose=0
|
||
)
|
||
df[cols_to_impute] = imputer.fit_transform(df_subset)
|
||
|
||
print(f'插补完成,剩余缺失值: {df[cols_to_impute].isna().sum().sum()}')
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 验收标准
|
||
|
||
### 7.1 功能验收
|
||
|
||
每个功能按钮需通过以下测试:
|
||
|
||
#### 基础功能测试
|
||
|
||
| 测试项 | 验收标准 |
|
||
|-------|---------|
|
||
| UI显示 | 按钮、对话框正确渲染,无布局错误 |
|
||
| 参数验证 | 错误输入有友好提示 |
|
||
| 预览功能 | 预览结果准确,性能<2秒 |
|
||
| 执行功能 | 代码正确执行,结果符合预期 |
|
||
| 错误处理 | 异常有明确提示,不崩溃 |
|
||
|
||
#### 数据准确性测试
|
||
|
||
| 测试项 | 验收标准 |
|
||
|-------|---------|
|
||
| 小数据集 | <1000行,结果100%准确 |
|
||
| 中数据集 | 1000-10000行,性能<5秒 |
|
||
| 大数据集 | 10000-50000行,性能<30秒 |
|
||
| 边界情况 | 全空列、全0列、单行等正确处理 |
|
||
|
||
#### 用户体验测试
|
||
|
||
| 测试项 | 验收标准 |
|
||
|-------|---------|
|
||
| 学习成本 | 新用户5分钟内学会使用 |
|
||
| 操作效率 | 比AI对话快3-5倍 |
|
||
| 错误恢复 | 支持撤销或提供"创建副本"选项 |
|
||
|
||
### 7.2 性能基准
|
||
|
||
| 操作 | 数据量 | 目标性能 |
|
||
|------|-------|---------|
|
||
| 高级筛选 | 10万行 | <2秒 |
|
||
| 数值映射 | 10万行 | <3秒 |
|
||
| 分箱 | 10万行 | <3秒 |
|
||
| 条件生成列 | 10万行 | <5秒 |
|
||
| Pivot转换 | 5000行 | <10秒 |
|
||
| MICE插补 | 5000行 | <60秒 |
|
||
|
||
### 7.3 代码质量标准
|
||
|
||
- ✅ 代码覆盖率 >80%
|
||
- ✅ ESLint/TSLint 0错误
|
||
- ✅ 所有API有完整的TypeScript类型定义
|
||
- ✅ 关键函数有JSDoc注释
|
||
- ✅ 用户操作有日志记录
|
||
|
||
---
|
||
|
||
## 8. 风险评估
|
||
|
||
### 8.1 技术风险
|
||
|
||
| 风险 | 影响 | 概率 | 应对措施 |
|
||
|------|------|------|---------|
|
||
| Python库依赖问题 | 高 | 中 | 提前验证库兼容性 |
|
||
| 大数据集性能 | 中 | 高 | 分批处理+进度条 |
|
||
| 代码生成错误 | 高 | 低 | 严格单元测试 |
|
||
| 浏览器兼容性 | 低 | 低 | 只支持现代浏览器 |
|
||
|
||
### 8.2 用户体验风险
|
||
|
||
| 风险 | 影响 | 概率 | 应对措施 |
|
||
|------|------|------|---------|
|
||
| 功能过于复杂 | 中 | 中 | 提供视频教程 |
|
||
| 与AI功能冲突 | 低 | 低 | 明确使用场景 |
|
||
| 期望过高 | 中 | 中 | 明确功能边界 |
|
||
|
||
---
|
||
|
||
## 9. 后续规划
|
||
|
||
### Phase 5:智能化增强(2-3个月后)
|
||
|
||
1. **操作推荐**:根据数据特征推荐合适的操作
|
||
2. **自动诊断**:检测数据质量问题(缺失、异常、重复)
|
||
3. **批量操作**:一次性应用多个操作
|
||
4. **操作模板**:保存常用操作序列
|
||
|
||
### Phase 6:协作增强(3-6个月后)
|
||
|
||
1. **操作历史**:查看、回退、分享操作历史
|
||
2. **团队模板**:团队共享清洗模板
|
||
3. **数据版本**:支持数据快照和版本管理
|
||
|
||
---
|
||
|
||
## 10. 附录
|
||
|
||
### 10.1 参考资料
|
||
|
||
- SPSS数据清洗功能
|
||
- Excel数据透视表
|
||
- Python Pandas文档
|
||
- Ant Design组件库
|
||
|
||
### 10.2 术语表
|
||
|
||
| 术语 | 解释 |
|
||
|------|------|
|
||
| 重编码 | 将一列的值映射为另一组值 |
|
||
| 分箱 | 将连续数值转为离散分类 |
|
||
| Pivot | 长表转宽表的数据重塑操作 |
|
||
| MICE | 多重插补法,处理缺失值的统计方法 |
|
||
| MAR | Missing At Random,随机缺失 |
|
||
|
||
### 10.3 更新日志
|
||
|
||
| 版本 | 日期 | 变更内容 |
|
||
|------|------|---------|
|
||
| V1.0 | 2025-12-08 | 初版,规划Phase 1-4功能 |
|
||
| V1.1 | 2025-12-08 | 架构重构:改为预写Python函数 |
|
||
| V1.2 | 2025-12-08 | Phase 1-2完成:7个核心功能上线 |
|
||
| V1.3 | 2025-12-10 | NA处理优化:4个功能支持空值处理;Pivot优化:保留未选列+原始列顺序;计算列方案B实施:安全列名映射;UX优化:列头tooltip+预览提示可关闭+滚动条优化 |
|
||
| V1.4 | 2025-12-10 | 缺失值填补功能开发:6种简单填补(均值/中位数/众数/固定值/前向/后向)+MICE多重插补;自动精度检测;分类列识别;功能按钮调整(删除"去重"和"多重插补","删除缺失值"改为"缺失值处理");状态:开发完成,MICE的DataFrame shape问题待调试 |
|
||
|
||
---
|
||
|
||
**文档结束**
|
||
|