feat: align prediction report with guidance
This commit is contained in:
+28
-11
@@ -18,8 +18,10 @@ from app.prediction import (
|
||||
REMAINING_LIFE_COLUMN,
|
||||
PredictionError,
|
||||
estimate_remaining_life,
|
||||
format_years,
|
||||
grade_info,
|
||||
interpolate_probability,
|
||||
make_analysis_text,
|
||||
prepare_model_features,
|
||||
read_input_file,
|
||||
render_survival_chart,
|
||||
@@ -60,6 +62,18 @@ class PredictionHelpersTest(unittest.TestCase):
|
||||
def test_probability_helpers(self) -> None:
|
||||
self.assertEqual(interpolate_probability([1, 5, 10], [0.9, 0.8, 0.6], 6), 0.6)
|
||||
self.assertEqual(estimate_remaining_life([1, 5, 10], [0.9, 0.4, 0.2]), 5.0)
|
||||
self.assertEqual(format_years(None, 10, 73), 63.0)
|
||||
|
||||
def test_analysis_text_displays_health_state_as_decimal(self) -> None:
|
||||
text = make_analysis_text(
|
||||
[
|
||||
{"pipe_id": "P001", "health_state": 0.734, "grade_label": "IV级"},
|
||||
{"pipe_id": "P002", "health_state": 0.2, "grade_label": "I级"},
|
||||
]
|
||||
)
|
||||
|
||||
self.assertIn("0.73", text)
|
||||
self.assertNotIn("%", text)
|
||||
|
||||
def test_grade_boundaries(self) -> None:
|
||||
self.assertEqual(grade_info(0.2)[0], "I级")
|
||||
@@ -79,13 +93,12 @@ class PredictionHelpersTest(unittest.TestCase):
|
||||
|
||||
validate_input_frame(df)
|
||||
|
||||
def test_example_workbook_columns_match_backend_contract(self) -> None:
|
||||
def test_example_workbook_contains_backend_contract_columns(self) -> None:
|
||||
workbook = load_workbook(Path(__file__).resolve().parents[1] / "example.xlsx", read_only=True)
|
||||
worksheet = workbook["Template"]
|
||||
headers = [cell.value for cell in next(worksheet.iter_rows(min_row=1, max_row=1))]
|
||||
|
||||
self.assertEqual(len(headers), len(INPUT_COLUMNS))
|
||||
self.assertEqual(set(headers), set(INPUT_COLUMNS))
|
||||
self.assertTrue(set(INPUT_COLUMNS).issubset(headers))
|
||||
|
||||
def test_read_input_file_preserves_text_pipe_ids(self) -> None:
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
@@ -183,8 +196,8 @@ class PredictionHelpersTest(unittest.TestCase):
|
||||
]
|
||||
summary_rows = [{"pipe_id": "P001"}, {"pipe_id": "P002"}]
|
||||
summary_sheet_rows = [
|
||||
{ID_COLUMN: "P001", PIPE_AGE_COLUMN: "10 年", "当前健康状态": 0.7, "健康等级": "IV级", REMAINING_LIFE_COLUMN: ">63"},
|
||||
{ID_COLUMN: "P002", PIPE_AGE_COLUMN: "12 年", "当前健康状态": 0.6, "健康等级": "III级", REMAINING_LIFE_COLUMN: ">61"},
|
||||
{ID_COLUMN: "P001", PIPE_AGE_COLUMN: 10, "当前健康状态": 0.7, "健康等级": "IV级", REMAINING_LIFE_COLUMN: 63},
|
||||
{ID_COLUMN: "P002", PIPE_AGE_COLUMN: 12, "当前健康状态": 0.6, "健康等级": "III级", REMAINING_LIFE_COLUMN: 61},
|
||||
]
|
||||
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
@@ -199,6 +212,8 @@ class PredictionHelpersTest(unittest.TestCase):
|
||||
summary_data.columns.tolist(),
|
||||
[ID_COLUMN, PIPE_AGE_COLUMN, "当前健康状态", "健康等级", REMAINING_LIFE_COLUMN],
|
||||
)
|
||||
self.assertEqual(summary_data[PIPE_AGE_COLUMN].tolist(), [10, 12])
|
||||
self.assertEqual(summary_data[REMAINING_LIFE_COLUMN].tolist(), [63, 61])
|
||||
|
||||
sample_data = pd.read_excel(output_path, sheet_name="样本数据")
|
||||
self.assertEqual(sample_data.columns.tolist(), ["管龄(年)", "P001", "P002"])
|
||||
@@ -209,15 +224,19 @@ class PredictionHelpersTest(unittest.TestCase):
|
||||
|
||||
openpyxl_workbook = load_workbook(output_path)
|
||||
sample_worksheet = openpyxl_workbook["样本数据"]
|
||||
summary_worksheet = openpyxl_workbook["结果摘要"]
|
||||
self.assertEqual(sample_worksheet.freeze_panes, "A2")
|
||||
self.assertEqual(sample_worksheet.auto_filter.ref, "A1:C3")
|
||||
self.assertEqual(sample_worksheet["B2"].number_format, "0.0%")
|
||||
self.assertEqual(summary_worksheet["C2"].number_format, "0.00")
|
||||
self.assertEqual(sample_worksheet["B2"].number_format, "0.00")
|
||||
self.assertIn("73减去当前管龄", summary_worksheet["E1"].value)
|
||||
self.assertNotIn("73 - 当前管龄", summary_worksheet["E1"].value)
|
||||
|
||||
def test_prediction_workbook_writes_pipe_ids_as_excel_text(self) -> None:
|
||||
predictions = [dummy_prediction("00123", [1], [0.9], 10, 0.9)]
|
||||
summary_rows = [{"pipe_id": "00123"}]
|
||||
summary_sheet_rows = [
|
||||
{ID_COLUMN: "00123", PIPE_AGE_COLUMN: "10 年", "当前健康状态": 0.9, "健康等级": "V级", REMAINING_LIFE_COLUMN: ">63"}
|
||||
{ID_COLUMN: "00123", PIPE_AGE_COLUMN: 10, "当前健康状态": 0.9, "健康等级": "V级", REMAINING_LIFE_COLUMN: 63}
|
||||
]
|
||||
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
@@ -243,19 +262,17 @@ class PredictionHelpersTest(unittest.TestCase):
|
||||
patch("app.prediction.plt.xlabel") as xlabel,
|
||||
patch("app.prediction.plt.ylabel") as ylabel,
|
||||
patch("app.prediction.plt.figtext") as figtext,
|
||||
patch("app.prediction.plt.title") as title,
|
||||
):
|
||||
summary_rows, _ = render_survival_chart([dummy_prediction()], output_path)
|
||||
summary_rows, summary_sheet_rows = render_survival_chart([dummy_prediction()], output_path)
|
||||
|
||||
self.assertAlmostEqual(summary_rows[0]["health_state"], 0.4)
|
||||
self.assertEqual(summary_rows[0]["grade_label"], "II级")
|
||||
self.assertEqual(summary_sheet_rows[0][PIPE_AGE_COLUMN], 12.0)
|
||||
|
||||
xlabel.assert_called_once()
|
||||
self.assertEqual(xlabel.call_args.args[0], "管龄(年)")
|
||||
ylabel.assert_called_once()
|
||||
self.assertEqual(ylabel.call_args.args[0], "管道健康状态")
|
||||
title.assert_called_once()
|
||||
self.assertEqual(title.call_args.args[0], "供水管道健康状态曲线")
|
||||
figtext.assert_called_once()
|
||||
self.assertIn(f"前{CHART_DISPLAY_LIMIT}条管道的示例数据", figtext.call_args.args[2])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user