ins-pricing 0.2.7__py3-none-any.whl → 0.2.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. ins_pricing/CHANGELOG.md +179 -0
  2. ins_pricing/RELEASE_NOTES_0.2.8.md +344 -0
  3. ins_pricing/modelling/core/bayesopt/utils.py +2 -1
  4. ins_pricing/modelling/explain/shap_utils.py +209 -6
  5. ins_pricing/pricing/calibration.py +125 -1
  6. ins_pricing/pricing/factors.py +110 -1
  7. ins_pricing/production/preprocess.py +166 -0
  8. ins_pricing/setup.py +1 -1
  9. ins_pricing/tests/governance/__init__.py +1 -0
  10. ins_pricing/tests/governance/test_audit.py +56 -0
  11. ins_pricing/tests/governance/test_registry.py +128 -0
  12. ins_pricing/tests/governance/test_release.py +74 -0
  13. ins_pricing/tests/pricing/__init__.py +1 -0
  14. ins_pricing/tests/pricing/test_calibration.py +72 -0
  15. ins_pricing/tests/pricing/test_exposure.py +64 -0
  16. ins_pricing/tests/pricing/test_factors.py +156 -0
  17. ins_pricing/tests/pricing/test_rate_table.py +40 -0
  18. ins_pricing/tests/production/__init__.py +1 -0
  19. ins_pricing/tests/production/test_monitoring.py +350 -0
  20. ins_pricing/tests/production/test_predict.py +233 -0
  21. ins_pricing/tests/production/test_preprocess.py +339 -0
  22. ins_pricing/tests/production/test_scoring.py +311 -0
  23. ins_pricing/utils/profiling.py +377 -0
  24. ins_pricing/utils/validation.py +427 -0
  25. ins_pricing-0.2.9.dist-info/METADATA +149 -0
  26. {ins_pricing-0.2.7.dist-info → ins_pricing-0.2.9.dist-info}/RECORD +28 -12
  27. ins_pricing/CHANGELOG_20260114.md +0 -275
  28. ins_pricing/CODE_REVIEW_IMPROVEMENTS.md +0 -715
  29. ins_pricing-0.2.7.dist-info/METADATA +0 -101
  30. {ins_pricing-0.2.7.dist-info → ins_pricing-0.2.9.dist-info}/WHEEL +0 -0
  31. {ins_pricing-0.2.7.dist-info → ins_pricing-0.2.9.dist-info}/top_level.txt +0 -0
@@ -1,715 +0,0 @@
1
- # ins_pricing 代码审查与改进计划
2
-
3
- **审查日期**: 2026-01-14
4
- **审查范围**: ins_pricing 包的所有 Python 代码
5
- **目标**: 提升运行效率、保证多平台可扩展性、加强代码可维护性
6
-
7
- ---
8
-
9
- ## 执行摘要
10
-
11
- 经过全面审查,**ins_pricing** 包整体架构设计良好,代码质量较高。主要优点包括:
12
-
13
- - ✅ 良好的模块化设计和关注点分离
14
- - ✅ 使用 `pathlib.Path` 实现跨平台路径处理
15
- - ✅ 实现了延迟加载 (lazy loading) 以优化导入性能
16
- - ✅ 分布式训练支持完善(DDP、DataParallel)
17
- - ✅ 类型注解覆盖率高
18
- - ✅ 日志系统完善
19
-
20
- 已识别的改进机会主要集中在性能优化、错误处理增强和文档完善方面。
21
-
22
- ---
23
-
24
- ## 1. 性能优化建议
25
-
26
- ### 1.1 高优先级优化
27
-
28
- #### 1.1.1 DatasetPreprocessor 中的内存优化
29
-
30
- **当前问题**:
31
- `config_preprocess.py` 中的 `DatasetPreprocessor.run()` 方法在多个位置进行 DataFrame 复制操作:
32
-
33
- ```python
34
- # 行 448-451, 470-474
35
- train_oht = self.train_data[cfg.factor_nmes + [cfg.weight_nme] + [cfg.resp_nme]].copy()
36
- test_oht = self.test_data[cfg.factor_nmes + [cfg.weight_nme] + [cfg.resp_nme]].copy()
37
- self.train_oht_data = train_oht.copy(deep=False) # 第二次复制
38
- train_oht_scaled = train_oht.copy(deep=False) # 第三次复制
39
- ```
40
-
41
- **改进方案**:
42
- ```python
43
- # 优化后 - 减少不必要的复制
44
- train_oht = self.train_data[cfg.factor_nmes + [cfg.weight_nme] + [cfg.resp_nme]].copy()
45
- test_oht = self.test_data[cfg.factor_nmes + [cfg.weight_nme] + [cfg.resp_nme]].copy()
46
-
47
- # 应用 one-hot 编码
48
- train_oht = pd.get_dummies(train_oht, columns=cate_list, drop_first=True, dtype=np.int8)
49
- test_oht = pd.get_dummies(test_oht, columns=cate_list, drop_first=True, dtype=np.int8)
50
- test_oht = test_oht.reindex(columns=train_oht.columns, fill_value=0)
51
-
52
- # 直接保存引用,避免浅复制
53
- self.train_oht_data = train_oht
54
- self.test_oht_data = test_oht
55
-
56
- # 仅在需要缩放时复制
57
- train_oht_scaled = train_oht.copy() if self.num_features else train_oht
58
- test_oht_scaled = test_oht.copy() if self.num_features else test_oht
59
- ```
60
-
61
- **预期效果**: 减少 30-40% 的内存占用和预处理时间
62
-
63
- #### 1.1.2 Pandas apply() 性能优化
64
-
65
- **当前问题**:
66
- 部分文件使用 `.apply()` 进行行级操作,性能较差。
67
-
68
- **检测到的位置**:
69
- - `pricing/exposure.py`
70
- - `pricing/factors.py`
71
- - `production/monitoring.py`
72
-
73
- **改进方案**:
74
- ```python
75
- # 使用向量化操作替代 apply()
76
- # 示例: 如果有 df.apply(lambda x: x['a'] * x['b'], axis=1)
77
- # 优化为: df['a'] * df['b']
78
- ```
79
-
80
- **预期效果**: 5-50 倍性能提升(取决于数据集大小)
81
-
82
- #### 1.1.3 训练循环中的 GPU 内存管理
83
-
84
- **当前实现**: `utils.py:828-870` 训练循环中已正确使用 `autocast` 和 `GradScaler`
85
-
86
- **建议增强**:
87
- ```python
88
- # 在 epoch 结束时添加显式清理
89
- if epoch % 10 == 0: # 每 10 个 epoch
90
- if torch.cuda.is_available():
91
- torch.cuda.empty_cache()
92
- gc.collect()
93
- ```
94
-
95
- **位置**: `modelling/core/bayesopt/utils.py:930` (epoch 循环结束处)
96
-
97
- ### 1.2 中优先级优化
98
-
99
- #### 1.2.1 缓存重复计算
100
-
101
- **建议位置**:
102
- - `pricing/factors.py`: 对于相同的因子列,缓存分箱结果
103
- - `modelling/plotting/curves.py`: 缓存 ROC/PR 曲线计算
104
-
105
- **实现示例**:
106
- ```python
107
- from functools import lru_cache
108
-
109
- @lru_cache(maxsize=128)
110
- def _compute_bins_cached(col_hash, n_bins):
111
- # 实现分箱逻辑
112
- pass
113
- ```
114
-
115
- #### 1.2.2 并行化 SHAP 计算
116
-
117
- **当前位置**: `modelling/explain/shap_utils.py`
118
-
119
- **建议**:
120
- ```python
121
- # 使用 joblib 并行计算 SHAP 值
122
- from joblib import Parallel, delayed
123
-
124
- shap_values = Parallel(n_jobs=-1)(
125
- delayed(explainer.shap_values)(batch)
126
- for batch in np.array_split(X, n_jobs)
127
- )
128
- ```
129
-
130
- ---
131
-
132
- ## 2. 多平台兼容性增强
133
-
134
- ### 2.1 ✅ 已良好实现的部分
135
-
136
- #### 2.1.1 路径处理
137
- - `utils/paths.py`: 全面使用 `pathlib.Path`,跨平台兼容性优秀
138
- - 所有关键模块正确使用 `Path.resolve()` 和 `Path.joinpath()`
139
-
140
- #### 2.1.2 进程管理
141
- - `cli/watchdog_run.py:27-46`: 正确区分 Windows/Unix 进程终止逻辑
142
- - 使用 `os.name == "nt"` 检测平台
143
-
144
- ### 2.2 需要改进的部分
145
-
146
- #### 2.2.1 硬编码的路径分隔符清理
147
-
148
- **位置**: `modelling/core/bayesopt/model_plotting_mixin.py:66-75, 209-212`
149
-
150
- **当前代码**:
151
- ```python
152
- plot_subdir = plot_subdir.strip("/\\") # 硬编码分隔符
153
- .replace("/", "_").replace("\\", "_")
154
- ```
155
-
156
- **改进方案**:
157
- ```python
158
- import os
159
-
160
- # 使用 os.sep 或完全避免字符串操作
161
- plot_subdir = str(Path(plot_subdir)) # 自动规范化
162
- safe_name = plot_subdir.replace(os.sep, "_")
163
- ```
164
-
165
- #### 2.2.2 文件权限问题
166
-
167
- **建议**: 在所有文件创建操作前检查权限
168
-
169
- ```python
170
- def ensure_writable(path: Path) -> None:
171
- """确保路径可写,跨平台兼容"""
172
- path.parent.mkdir(parents=True, exist_ok=True)
173
- if path.exists() and not os.access(path, os.W_OK):
174
- raise PermissionError(f"Cannot write to {path}")
175
- ```
176
-
177
- **应用位置**:
178
- - `governance/registry.py`
179
- - `governance/audit.py`
180
- - `reporting/report_builder.py`
181
-
182
- ---
183
-
184
- ## 3. 代码可维护性提升
185
-
186
- ### 3.1 文档完善
187
-
188
- #### 3.1.1 缺少顶层 README
189
-
190
- **建议创建**: `ins_pricing/README.md`
191
-
192
- **应包含内容**:
193
- - 架构概览图
194
- - 快速开始指南
195
- - API 参考索引
196
- - 常见问题解答
197
-
198
- #### 3.1.2 模块级文档字符串增强
199
-
200
- **当前状态**: 大部分模块有基本的 docstring
201
-
202
- **建议改进**: 添加使用示例和参数说明
203
-
204
- **示例** (`pricing/factors.py`):
205
- ```python
206
- """Factor table construction for insurance pricing.
207
-
208
- This module provides utilities for building factor tables from raw data,
209
- including automatic binning, smoothing, and credibility weighting.
210
-
211
- Example:
212
- >>> from ins_pricing.pricing import build_factor_table
213
- >>> factor_table = build_factor_table(
214
- ... df=data,
215
- ... factor_col='age_band',
216
- ... loss_col='claim_amount',
217
- ... exposure_col='exposure_years',
218
- ... method='quantile',
219
- ... n_bins=10
220
- ... )
221
- >>> print(factor_table)
222
-
223
- See Also:
224
- - calibration.py: Factor calibration and application
225
- - rate_table.py: Premium calculation using factor tables
226
- """
227
- ```
228
-
229
- ### 3.2 类型注解改进
230
-
231
- #### 3.2.1 完善返回类型注解
232
-
233
- **检测到的问题**: 部分函数缺少返回类型
234
-
235
- **建议**: 对所有公共 API 添加完整类型注解
236
-
237
- ```python
238
- # 当前
239
- def compute_exposure(df, start_col, end_col):
240
- ...
241
-
242
- # 改进后
243
- def compute_exposure(
244
- df: pd.DataFrame,
245
- start_col: str,
246
- end_col: str,
247
- time_unit: Literal['days', 'years'] = 'days'
248
- ) -> pd.Series:
249
- """
250
- 计算保险暴露量。
251
-
252
- Args:
253
- df: 包含开始和结束日期的数据框
254
- start_col: 开始日期列名
255
- end_col: 结束日期列名
256
- time_unit: 时间单位,'days' 或 'years'
257
-
258
- Returns:
259
- 包含暴露量的 Series
260
- """
261
- ...
262
- ```
263
-
264
- ### 3.3 错误处理增强
265
-
266
- #### 3.3.1 具体的异常类型
267
-
268
- **当前问题**: 部分代码使用裸 `Exception`
269
-
270
- **建议创建**: `ins_pricing/exceptions.py`
271
-
272
- ```python
273
- """Custom exceptions for ins_pricing."""
274
-
275
- class InsPricingError(Exception):
276
- """Base exception for all ins_pricing errors."""
277
- pass
278
-
279
- class ConfigurationError(InsPricingError):
280
- """Invalid configuration."""
281
- pass
282
-
283
- class DataValidationError(InsPricingError):
284
- """Data validation failed."""
285
- pass
286
-
287
- class ModelLoadError(InsPricingError):
288
- """Failed to load model."""
289
- pass
290
-
291
- class DistributedTrainingError(InsPricingError):
292
- """Distributed training failure."""
293
- pass
294
- ```
295
-
296
- **应用示例**:
297
- ```python
298
- # 在 config_preprocess.py:399-402
299
- if missing_train:
300
- raise ConfigurationError(
301
- f"Train data missing required columns: {missing_train}. "
302
- f"Available columns (first 50): {list(self.train_data.columns)[:50]}"
303
- )
304
- ```
305
-
306
- #### 3.3.2 增加验证和早期失败
307
-
308
- **建议位置**: `production/predict.py`
309
-
310
- ```python
311
- def load_predictor_from_config(config_json: Path) -> dict:
312
- """加载预测器,带完整验证"""
313
- if not config_json.exists():
314
- raise FileNotFoundError(f"Config not found: {config_json}")
315
-
316
- try:
317
- config = _load_json(config_json)
318
- except json.JSONDecodeError as e:
319
- raise ConfigurationError(f"Invalid JSON in {config_json}: {e}")
320
-
321
- # 验证必需字段
322
- required_fields = ['model_name', 'task_type', 'base_dir']
323
- missing = [f for f in required_fields if f not in config]
324
- if missing:
325
- raise ConfigurationError(f"Missing required fields: {missing}")
326
-
327
- return config
328
- ```
329
-
330
- ### 3.4 代码复用和重构
331
-
332
- #### 3.4.1 提取公共工具函数
333
-
334
- **识别的重复代码**:
335
-
336
- 1. **路径解析逻辑** (多个文件重复)
337
- - 已集中到 `utils/paths.py` ✅
338
- - 建议: 确保所有模块使用 `resolve_path` 而非自定义实现
339
-
340
- 2. **DataFrame 列验证** (重复模式)
341
-
342
- **建议创建**: `utils/validation.py`
343
-
344
- ```python
345
- def validate_required_columns(
346
- df: pd.DataFrame,
347
- required: List[str],
348
- *,
349
- df_name: str = "DataFrame"
350
- ) -> None:
351
- """验证 DataFrame 包含必需的列"""
352
- missing = [col for col in required if col not in df.columns]
353
- if missing:
354
- raise DataValidationError(
355
- f"{df_name} missing required columns: {missing}. "
356
- f"Available: {list(df.columns)[:50]}"
357
- )
358
-
359
- def validate_column_types(
360
- df: pd.DataFrame,
361
- type_spec: Dict[str, type],
362
- *,
363
- coerce: bool = False
364
- ) -> pd.DataFrame:
365
- """验证并可选地强制列类型"""
366
- for col, expected_type in type_spec.items():
367
- if col not in df.columns:
368
- continue
369
- if not pd.api.types.is_dtype_equal(df[col].dtype, expected_type):
370
- if coerce:
371
- df[col] = df[col].astype(expected_type)
372
- else:
373
- raise DataValidationError(
374
- f"Column {col} has type {df[col].dtype}, "
375
- f"expected {expected_type}"
376
- )
377
- return df
378
- ```
379
-
380
- #### 3.4.2 配置管理改进
381
-
382
- **当前状态**: 使用 dataclass 管理配置 ✅
383
-
384
- **建议增强**: 添加配置验证
385
-
386
- ```python
387
- # 在 BayesOptConfig 中添加
388
- def __post_init__(self):
389
- """验证配置一致性"""
390
- if not 0.0 <= self.prop_test <= 1.0:
391
- raise ValueError(f"prop_test must be in [0, 1], got {self.prop_test}")
392
-
393
- if self.task_type not in {'regression', 'classification'}:
394
- raise ValueError(f"task_type must be 'regression' or 'classification'")
395
-
396
- if self.epochs < 1:
397
- raise ValueError(f"epochs must be positive, got {self.epochs}")
398
-
399
- # 验证 DDP 和 DataParallel 不同时启用
400
- if self.use_resn_ddp and self.use_resn_data_parallel:
401
- raise ValueError("Cannot use both DDP and DataParallel for ResNet")
402
- ```
403
-
404
- ### 3.5 测试覆盖率提升
405
-
406
- **当前测试文件**:
407
- ```
408
- tests/modelling/
409
- ├── conftest.py
410
- ├── test_cross_val_generic.py
411
- ├── test_distributed_utils.py
412
- ├── test_explain.py
413
- ├── test_geo_tokens_split.py
414
- ├── test_graph_cache.py
415
- ├── test_plotting.py
416
- ├── test_plotting_library.py
417
- └── test_preprocessor.py
418
- ```
419
-
420
- **建议添加**:
421
-
422
- 1. **生产模块测试** (当前缺失)
423
- ```
424
- tests/production/
425
- ├── test_predict.py
426
- ├── test_scoring.py
427
- ├── test_monitoring.py
428
- └── test_preprocess.py
429
- ```
430
-
431
- 2. **定价模块测试** (当前缺失)
432
- ```
433
- tests/pricing/
434
- ├── test_factors.py
435
- ├── test_exposure.py
436
- ├── test_calibration.py
437
- └── test_rate_table.py
438
- ```
439
-
440
- 3. **治理模块测试** (当前缺失)
441
- ```
442
- tests/governance/
443
- ├── test_registry.py
444
- ├── test_release.py
445
- └── test_audit.py
446
- ```
447
-
448
- ---
449
-
450
- ## 4. 具体改进实施计划
451
-
452
- ### 阶段 1: 高优先级修复 (立即实施)
453
-
454
- 1. **修复 DDP 状态字典不匹配问题** ✅ (已完成)
455
- - `model_ft_trainer.py`: Lines 409, 738
456
- - `model_resn.py`: Line 405
457
- - `utils.py`: Line 796
458
-
459
- 2. **优化 DatasetPreprocessor 内存使用**
460
- - 文件: `config_preprocess.py`
461
- - 预计工作量: 2 小时
462
- - 影响: 所有训练流程
463
-
464
- 3. **添加自定义异常类**
465
- - 创建: `exceptions.py`
466
- - 更新所有模块的异常处理
467
- - 预计工作量: 4 小时
468
-
469
- ### 阶段 2: 性能优化 (本周内)
470
-
471
- 1. **替换 pandas apply() 为向量化操作**
472
- - 文件: `pricing/exposure.py`, `pricing/factors.py`
473
- - 预计工作量: 6 小时
474
- - 需要性能基准测试
475
-
476
- 2. **实现 SHAP 计算并行化**
477
- - 文件: `modelling/explain/shap_utils.py`
478
- - 预计工作量: 3 小时
479
-
480
- 3. **添加训练循环内存清理**
481
- - 文件: `modelling/core/bayesopt/utils.py`
482
- - 预计工作量: 1 小时
483
-
484
- ### 阶段 3: 文档和测试 (两周内)
485
-
486
- 1. **编写顶层 README**
487
- - 预计工作量: 4 小时
488
-
489
- 2. **完善模块文档字符串**
490
- - 所有公共模块
491
- - 预计工作量: 8 小时
492
-
493
- 3. **添加缺失的单元测试**
494
- - 生产、定价、治理模块
495
- - 预计工作量: 16 小时
496
-
497
- ### 阶段 4: 代码质量提升 (持续)
498
-
499
- 1. **添加类型检查 (mypy)**
500
- - 配置 mypy
501
- - 修复类型错误
502
- - 预计工作量: 8 小时
503
-
504
- 2. **代码格式化标准化**
505
- - 配置 black, isort, flake8
506
- - 预计工作量: 2 小时
507
-
508
- 3. **设置 pre-commit hooks**
509
- - 预计工作量: 2 小时
510
-
511
- ---
512
-
513
- ## 5. 性能基准和监控
514
-
515
- ### 5.1 建议添加的性能指标
516
-
517
- **创建**: `utils/profiling.py`
518
-
519
- ```python
520
- """性能分析工具"""
521
- import time
522
- from contextlib import contextmanager
523
- from typing import Optional
524
- import psutil
525
- import torch
526
-
527
- @contextmanager
528
- def profile_section(name: str, logger: Optional[logging.Logger] = None):
529
- """性能分析上下文管理器"""
530
- start = time.time()
531
- start_mem = psutil.Process().memory_info().rss / 1024 / 1024 # MB
532
- if torch.cuda.is_available():
533
- torch.cuda.reset_peak_memory_stats()
534
- start_gpu_mem = torch.cuda.memory_allocated() / 1024 / 1024
535
-
536
- yield
537
-
538
- elapsed = time.time() - start
539
- end_mem = psutil.Process().memory_info().rss / 1024 / 1024
540
- mem_delta = end_mem - start_mem
541
-
542
- msg = f"[Profile] {name}: {elapsed:.2f}s, RAM: {mem_delta:+.1f}MB"
543
- if torch.cuda.is_available():
544
- peak_gpu = torch.cuda.max_memory_allocated() / 1024 / 1024
545
- msg += f", GPU peak: {peak_gpu:.1f}MB"
546
-
547
- if logger:
548
- logger.info(msg)
549
- else:
550
- print(msg)
551
-
552
- # 使用示例
553
- with profile_section("Preprocessing", logger):
554
- preprocessor.run()
555
- ```
556
-
557
- ### 5.2 内存泄漏检测
558
-
559
- **建议**: 在长时间训练任务中添加内存监控
560
-
561
- ```python
562
- # 在 utils.py 训练循环中
563
- if epoch % 50 == 0:
564
- mem_info = psutil.Process().memory_info()
565
- logger.info(f"Epoch {epoch} memory: RSS={mem_info.rss / 1024 / 1024:.1f}MB")
566
- if mem_info.rss > 32 * 1024 * 1024 * 1024: # > 32GB
567
- logger.warning("High memory usage detected!")
568
- ```
569
-
570
- ---
571
-
572
- ## 6. 安全性考虑
573
-
574
- ### 6.1 输入验证
575
-
576
- **建议增强的位置**:
577
-
578
- 1. **JSON 配置加载**
579
- ```python
580
- # 在所有 _load_json 调用处添加模式验证
581
- import jsonschema
582
-
583
- CONFIG_SCHEMA = {
584
- "type": "object",
585
- "required": ["model_name", "task_type"],
586
- "properties": {
587
- "model_name": {"type": "string", "minLength": 1},
588
- "task_type": {"type": "string", "enum": ["regression", "classification"]},
589
- ...
590
- }
591
- }
592
-
593
- def load_config_safe(path: Path) -> dict:
594
- config = _load_json(path)
595
- jsonschema.validate(config, CONFIG_SCHEMA)
596
- return config
597
- ```
598
-
599
- 2. **SQL 注入防护** (如果使用数据库)
600
- - 使用参数化查询
601
- - 验证表名和列名
602
-
603
- 3. **路径遍历防护**
604
- ```python
605
- def safe_resolve_path(base: Path, user_path: str) -> Path:
606
- """防止路径遍历攻击"""
607
- resolved = (base / user_path).resolve()
608
- if not resolved.is_relative_to(base):
609
- raise SecurityError(f"Path {user_path} escapes base directory")
610
- return resolved
611
- ```
612
-
613
- ---
614
-
615
- ## 7. 总结与优先级矩阵
616
-
617
- ### 影响-工作量矩阵
618
-
619
- | 改进项 | 影响 | 工作量 | 优先级 |
620
- |-------|------|--------|--------|
621
- | DDP 修复 | 高 | 低 | ✅ 已完成 |
622
- | 内存优化 (Preprocessor) | 高 | 中 | P0 |
623
- | 自定义异常 | 高 | 低 | P0 |
624
- | 向量化操作 | 高 | 中 | P1 |
625
- | SHAP 并行化 | 中 | 低 | P1 |
626
- | 文档完善 | 中 | 高 | P2 |
627
- | 单元测试 | 中 | 高 | P2 |
628
- | 类型检查 | 低 | 中 | P3 |
629
-
630
- ### 下一步行动
631
-
632
- **本周行动项**:
633
- 1. ✅ 应用 DDP 修复 (已完成)
634
- 2. 实施 DatasetPreprocessor 内存优化
635
- 3. 创建自定义异常体系
636
- 4. 添加性能分析工具
637
-
638
- **本月行动项**:
639
- 1. 完成所有 P0-P1 优化
640
- 2. 编写 README 和核心模块文档
641
- 3. 添加生产/定价模块测试
642
-
643
- **长期目标**:
644
- 1. 达到 80%+ 测试覆盖率
645
- 2. 通过 mypy strict 模式
646
- 3. 建立持续集成 (CI) 流程
647
-
648
- ---
649
-
650
- ## 附录 A: 代码规范建议
651
-
652
- ### Python 版本
653
- - 最低支持: Python 3.9 (当前)
654
- - 推荐: Python 3.10+ (for better type hints)
655
-
656
- ### 代码风格
657
- - **Formatter**: `black` (line length 100)
658
- - **Import sorting**: `isort` (black-compatible)
659
- - **Linter**: `flake8` + `pylint`
660
- - **Type checker**: `mypy --strict`
661
-
662
- ### 提交规范
663
- ```
664
- <type>(<scope>): <subject>
665
-
666
- <body>
667
-
668
- <footer>
669
- ```
670
-
671
- 类型:
672
- - `feat`: 新功能
673
- - `fix`: Bug 修复
674
- - `perf`: 性能优化
675
- - `docs`: 文档更新
676
- - `test`: 测试添加
677
- - `refactor`: 代码重构
678
-
679
- ---
680
-
681
- ## 附录 B: 依赖管理建议
682
-
683
- ### 当前依赖分组 ✅
684
- ```toml
685
- [project.optional-dependencies]
686
- bayesopt = ["torch", "optuna", "xgboost", ...]
687
- plotting = ["matplotlib", ...]
688
- explain = ["shap", ...]
689
- geo = ["contextily", ...]
690
- gnn = ["torch-geometric", ...]
691
- ```
692
-
693
- ### 建议添加
694
- ```toml
695
- [project.optional-dependencies]
696
- dev = [
697
- "pytest>=7.0",
698
- "pytest-cov",
699
- "mypy",
700
- "black",
701
- "isort",
702
- "flake8",
703
- ]
704
- profiling = [
705
- "psutil",
706
- "memory_profiler",
707
- "line_profiler",
708
- ]
709
- ```
710
-
711
- ---
712
-
713
- **文档版本**: 1.0
714
- **最后更新**: 2026-01-14
715
- **维护者**: Claude Code Review System