feat: 添加强化学习项目报告及重构课程作业报告代码结构

- 新增强化学习个人项目报告,包含基于PyTorch从零实现的PPO算法
- 重构课程作业报告代码结构,提取运行时路径管理和notebook执行逻辑到独立模块
- 更新依赖文件requirements.txt,添加强化学习相关依赖
- 简化模型比较结果表格,仅保留基线逻辑回归模型数据
This commit is contained in:
2026-04-30 16:54:41 +08:00
parent 6ac02ba4fe
commit d353133b31
21 changed files with 1639 additions and 102 deletions
@@ -0,0 +1,55 @@
import json
import traceback
from pathlib import Path
from .runtime_paths import build_paths
def execute_notebook(
start_at: int | None = None,
stop_at: int | None = None,
namespace: dict | None = None,
) -> dict:
paths = build_paths()
paths.ensure_outputs()
nb_data = json.loads(paths.notebook.read_text(encoding="utf-8"))
code_cells = [c for c in nb_data["cells"] if c["cell_type"] == "code"]
if not code_cells:
return {"status": "skipped", "reason": "no code cells found"}
ns = (namespace or {}).copy()
ns.update(paths.as_injection())
ns["RANDOM_STATE"] = 42
start = max((start_at or 1) - 1, 0)
stop = stop_at if stop_at is not None else len(code_cells)
cells_to_run = code_cells[start:stop]
results = []
for i, cell in enumerate(cells_to_run, start=start + 1):
src = "".join(cell["source"])
tag = f"cell_{i}"
try:
exec(compile(src, tag, "exec"), ns)
results.append({"cell": i, "status": "ok"})
except Exception as exc:
results.append({"cell": i, "status": "error", "error": str(exc)})
traceback.print_exc()
print(f"Stopping at cell {i} due to error.")
break
results_summary = {
"status": "completed",
"total": len(cells_to_run),
"cells": results,
"outputs": {
"data_dir": str(paths.data_dir),
"output_dir": str(paths.output_dir),
},
}
return results_summary
if __name__ == "__main__":
execute_notebook()
@@ -1,32 +1,52 @@
"""
Part 2: 运行完整的 notebook cells 1-35
解决中文路径编码问题
"""
import warnings, time, os, sys, json, traceback
warnings.filterwarnings('ignore')
import warnings
warnings.filterwarnings("ignore")
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as _p
_p.show = lambda *a, **kw: None
nb = r'D:\Code\doing_exercises\programs\外教作业外快\强化学习个人课程作业报告\notebooks\insurance_premium_risk.ipynb'
cells = json.load(open(nb, encoding='utf-8'))['cells']
code_cells = [c for c in cells if c['cell_type'] == 'code']
print(f"Total code cells: {len(code_cells)}")
matplotlib.use("Agg")
import matplotlib.pyplot as _real_mpl_plt
main_ns = globals().copy()
main_ns['RANDOM_STATE'] = 42
_real_mpl_plt.show = lambda *a, **kw: None
for i, cell in enumerate(code_cells, start=1):
src = ''.join(cell['source'])
print(f"\n{'='*60}")
print(f"Running cell {i}/{len(code_cells)}...")
try:
exec(compile(src, f'cell_{i}', 'exec'), main_ns)
except Exception as e:
print(f"ERROR cell {i}: {e}")
traceback.print_exc()
print("Stopping.")
break
import os
import sys
import time
import json
import traceback
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import accuracy_score, f1_score, classification_report, confusion_matrix, ConfusionMatrixDisplay
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.cluster import KMeans
from sklearn.mixture import GaussianMixture
from sklearn.metrics import silhouette_score
from sklearn.decomposition import PCA
import xgboost as xgb
import optuna
optuna.logging.set_verbosity(optuna.logging.WARNING)
print("\n\nAll cells executed!")
from src.notebook_runner import execute_notebook
from src.runtime_paths import build_paths
paths = build_paths()
print(f"Project root : {paths.project_root}")
print(f"Notebook : {paths.notebook}")
print(f"Data dir : {paths.data_dir}")
print(f"Output dir : {paths.output_dir}")
ns = vars()
result = execute_notebook(start_at=1, namespace=ns)
print(f"\nExecution finished: {result['status']}")
print(f"Cells run: {len([c for c in result['cells'] if c['status'] == 'ok'])}/{result['total']}")
print(f"Output dir: {result['outputs']['output_dir']}")
@@ -0,0 +1,31 @@
from dataclasses import dataclass
from pathlib import Path
@dataclass(frozen=True)
class RuntimePaths:
project_root: Path
notebook: Path
data_dir: Path
output_dir: Path
def ensure_outputs(self) -> None:
(self.output_dir / "figures").mkdir(parents=True, exist_ok=True)
(self.output_dir / "tables").mkdir(parents=True, exist_ok=True)
(self.output_dir / "predictions").mkdir(parents=True, exist_ok=True)
def as_injection(self) -> dict:
return {
"DATA_DIR": str(self.data_dir),
"OUTPUT_DIR": str(self.output_dir),
}
def build_paths() -> RuntimePaths:
root = Path(__file__).resolve().parents[1]
return RuntimePaths(
project_root=root,
notebook=root / "notebooks" / "insurance_premium_risk.ipynb",
data_dir=root / "dataset_final",
output_dir=root / "outputs",
)