Add aligned missingness analyses and results
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
"""Plot the aligned-data rate sweep and matched missing-type response."""
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
RESULTS = Path(__file__).resolve().parent / "results"
|
||||
|
||||
|
||||
def read_csv(name: str) -> list[dict[str, str]]:
|
||||
with (RESULTS / name).open(encoding="utf-8-sig", newline="") as stream:
|
||||
return list(csv.DictReader(stream))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
rate_rows = read_csv("controlled_missingness.csv")
|
||||
rate_bootstrap = read_csv("controlled_group_bootstrap.csv")
|
||||
type_bootstrap = read_csv("matched_missing_type_bootstrap.csv")
|
||||
|
||||
colors = {"single": "#3b82f6", "sync": "#dc2626", "partial": "#16a34a", "async": "#9333ea"}
|
||||
labels = {"single": "Single modality", "sync": "Synchronous", "partial": "Partial overlap", "async": "Asynchronous"}
|
||||
fig, (ax_rate, ax_type) = plt.subplots(1, 2, figsize=(12.4, 4.8), gridspec_kw={"width_ratios": [1.35, 1.0]})
|
||||
|
||||
baseline = next(row for row in rate_rows if row["model"] == "C5" and row["mask_pattern"] == "none")
|
||||
baseline_ci = next(row for row in rate_bootstrap if row["model"] == "C5" and row["scenario"] == "0.0/none" and row["metric"] == "mae")
|
||||
for mode in ("single", "sync", "partial", "async"):
|
||||
rows = [baseline] + sorted(
|
||||
(row for row in rate_rows if row["model"] == "C5" and row["mask_pattern"] == mode),
|
||||
key=lambda row: float(row["rate_requested_per_selected_source"]),
|
||||
)
|
||||
x, y, lower, upper = [], [], [], []
|
||||
for row in rows:
|
||||
if row["mask_pattern"] == "none":
|
||||
ci = baseline_ci
|
||||
scenario = "0.0/none"
|
||||
else:
|
||||
scenario = f"{float(row['rate_requested_per_selected_source']):.1f}/{mode}"
|
||||
ci = next(item for item in rate_bootstrap if item["model"] == "C5" and item["scenario"] == scenario and item["metric"] == "mae")
|
||||
x.append(float(row["rate_realized_additional_global"]))
|
||||
y.append(float(row["regression_mae"]))
|
||||
lower.append(float(ci["ci_2_5"]))
|
||||
upper.append(float(ci["ci_97_5"]))
|
||||
ax_rate.errorbar(
|
||||
x, y, yerr=[np.asarray(y) - np.asarray(lower), np.asarray(upper) - np.asarray(y)],
|
||||
color=colors[mode], marker="o", linewidth=1.7, markersize=4.5,
|
||||
capsize=2.5, label=labels[mode], alpha=0.95,
|
||||
)
|
||||
ax_rate.set_title("C5 performance across missing rates")
|
||||
ax_rate.set_xlabel("Added missing rate (paper definition)")
|
||||
ax_rate.set_ylabel("Regression MAE (95% group-bootstrap CI)")
|
||||
ax_rate.grid(axis="both", color="#d1d5db", linewidth=0.7, alpha=0.65)
|
||||
ax_rate.legend(frameon=False, fontsize=8.5, loc="upper left")
|
||||
|
||||
type_order = ("T", "A", "V", "TA", "TV", "AV", "TAV")
|
||||
point, low, high = [], [], []
|
||||
for label in type_order:
|
||||
scenario = f"matched_type_{label}"
|
||||
boot = next(row for row in type_bootstrap if row["model"] == "C5" and row["scenario"] == scenario and row["metric"] == "mae")
|
||||
point.append(float(boot["delta_to_natural"]))
|
||||
low.append(float(boot["delta_to_natural_ci_2_5"]))
|
||||
high.append(float(boot["delta_to_natural_ci_97_5"]))
|
||||
positions = np.arange(len(type_order))
|
||||
ax_type.errorbar(
|
||||
positions, point, yerr=[np.asarray(point) - low, high - np.asarray(point)],
|
||||
fmt="o", color="#2563eb", ecolor="#2563eb", capsize=3, linewidth=1.4,
|
||||
markersize=5,
|
||||
)
|
||||
ax_type.axhline(0, color="#374151", linewidth=1, linestyle="--")
|
||||
ax_type.set_xticks(positions, type_order)
|
||||
ax_type.set_title("Matched missing-modality types")
|
||||
ax_type.set_xlabel("Hidden modality set")
|
||||
ax_type.set_ylabel("MAE change from natural condition")
|
||||
ax_type.grid(axis="y", color="#d1d5db", linewidth=0.7, alpha=0.65)
|
||||
ax_type.text(
|
||||
0.02, 0.02, "Same added feature-row count per sample and type",
|
||||
transform=ax_type.transAxes, fontsize=7.5, color="#4b5563",
|
||||
)
|
||||
|
||||
fig.tight_layout(pad=1.2)
|
||||
output = RESULTS / "aligned_missingness_effects.png"
|
||||
fig.savefig(output, dpi=200, bbox_inches="tight", facecolor="white")
|
||||
print(output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user