From de9e3e397bf7e4c510d6dabe8b42d1ee4ddcdc70 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Mon, 10 Aug 2026 16:09:33 -0400 Subject: [PATCH] docs: keep marginal summaries as parameter dictionaries --- .../guides/results/aggregator/samples.ipynb | 32 +++++---- .../aggregator/samples_via_aggregator.ipynb | 68 ++++++++++++------- notebooks/guides/results/start_here.ipynb | 21 +++--- scripts/guides/results/aggregator/samples.py | 30 ++++---- .../aggregator/samples_via_aggregator.py | 66 +++++++++++------- scripts/guides/results/start_here.py | 19 +++--- 6 files changed, 141 insertions(+), 95 deletions(-) diff --git a/notebooks/guides/results/aggregator/samples.ipynb b/notebooks/guides/results/aggregator/samples.ipynb index 580c8395..b464c78e 100644 --- a/notebooks/guides/results/aggregator/samples.ipynb +++ b/notebooks/guides/results/aggregator/samples.ipynb @@ -463,18 +463,20 @@ "PDF stands for \"Probability Density Function\" and it quantifies probability of each model parameter having values\n", "that are sampled. It therefore enables error estimation via a process called marginalization.\n", "\n", - "The median pdf vector is available, which estimates every parameter via 1D marginalization of their PDFs." + "The median pdf vector is available, which estimates every parameter via 1D marginalization of their PDFs.\n", + "\n", + "Because these statistics are computed independently, combining them does not necessarily produce a physically valid\n", + "profile. Requesting a dictionary reports the marginalized parameters without constructing a model instance." ] }, { "cell_type": "code", "metadata": {}, "source": [ - "instance = samples.median_pdf()\n", + "parameter_dict = samples.median_pdf(as_dict=True)\n", "\n", - "print(\"Median PDF Model Instances: \\n\")\n", - "print(instance, \"\\n\")\n", - "print(instance.galaxies.galaxy.bulge)\n", + "print(\"Median PDF Model Parameters: \\n\")\n", + "print(parameter_dict, \"\\n\")\n", "print()\n", "\n", "vector = samples.median_pdf(as_instance=False)\n", @@ -503,12 +505,12 @@ "cell_type": "code", "metadata": {}, "source": [ - "instance_upper_sigma = samples.values_at_upper_sigma(sigma=3.0)\n", - "instance_lower_sigma = samples.values_at_lower_sigma(sigma=3.0)\n", + "parameter_dict_upper_sigma = samples.values_at_upper_sigma(sigma=3.0, as_dict=True)\n", + "parameter_dict_lower_sigma = samples.values_at_lower_sigma(sigma=3.0, as_dict=True)\n", "\n", - "print(\"Errors Instances: \\n\")\n", - "print(instance_upper_sigma.galaxies.galaxy.bulge, \"\\n\")\n", - "print(instance_lower_sigma.galaxies.galaxy.bulge, \"\\n\")" + "print(\"Marginalized Parameter Bounds: \\n\")\n", + "print(parameter_dict_upper_sigma, \"\\n\")\n", + "print(parameter_dict_lower_sigma, \"\\n\")" ], "outputs": [], "execution_count": null @@ -524,12 +526,12 @@ "cell_type": "code", "metadata": {}, "source": [ - "instance_upper_values = samples.errors_at_upper_sigma(sigma=3.0)\n", - "instance_lower_values = samples.errors_at_lower_sigma(sigma=3.0)\n", + "parameter_dict_upper_values = samples.errors_at_upper_sigma(sigma=3.0, as_dict=True)\n", + "parameter_dict_lower_values = samples.errors_at_lower_sigma(sigma=3.0, as_dict=True)\n", "\n", - "print(\"Errors Instances: \\n\")\n", - "print(instance_upper_values.galaxies.galaxy.bulge, \"\\n\")\n", - "print(instance_lower_values.galaxies.galaxy.bulge, \"\\n\")" + "print(\"Marginalized Parameter Errors: \\n\")\n", + "print(parameter_dict_upper_values, \"\\n\")\n", + "print(parameter_dict_lower_values, \"\\n\")" ], "outputs": [], "execution_count": null diff --git a/notebooks/guides/results/aggregator/samples_via_aggregator.ipynb b/notebooks/guides/results/aggregator/samples_via_aggregator.ipynb index eba40d45..988a5d96 100644 --- a/notebooks/guides/results/aggregator/samples_via_aggregator.ipynb +++ b/notebooks/guides/results/aggregator/samples_via_aggregator.ipynb @@ -426,18 +426,20 @@ "PDF stands for \"Probability Density Function\" and it quantifies probability of each model parameter having values\n", "that are sampled. It therefore enables error estimation via a process called marginalization.\n", "\n", - "The median pdf vector is available, which estimates every parameter via 1D marginalization of their PDFs." + "The median pdf vector is available, which estimates every parameter via 1D marginalization of their PDFs.\n", + "\n", + "Independent marginal statistics need not combine into a physically valid profile, so they are returned as parameter\n", + "dictionaries instead of model instances." ] }, { "cell_type": "code", "metadata": {}, "source": [ - "mp_instances = [samps.median_pdf() for samps in agg.values(\"samples\")]\n", + "mp_dicts = [samps.median_pdf(as_dict=True) for samps in agg.values(\"samples\")]\n", "\n", - "print(\"Median PDF Model Instances: \\n\")\n", - "print(mp_instances, \"\\n\")\n", - "print(mp_instances[0].galaxies.galaxy.bulge)\n", + "print(\"Median PDF Model Parameters: \\n\")\n", + "print(mp_dicts, \"\\n\")\n", "print()" ], "outputs": [], @@ -461,24 +463,32 @@ "cell_type": "code", "metadata": {}, "source": [ - "uv3_lists = [samps.values_at_upper_sigma(sigma=3.0) for samps in agg.values(\"samples\")]\n", + "uv3_lists = [\n", + " samps.values_at_upper_sigma(sigma=3.0, as_instance=False)\n", + " for samps in agg.values(\"samples\")\n", + "]\n", "\n", - "uv3_instances = [\n", - " samps.values_at_upper_sigma(sigma=3.0) for samps in agg.values(\"samples\")\n", + "uv3_dicts = [\n", + " samps.values_at_upper_sigma(sigma=3.0, as_dict=True)\n", + " for samps in agg.values(\"samples\")\n", "]\n", "\n", - "lv3_lists = [samps.values_at_lower_sigma(sigma=3.0) for samps in agg.values(\"samples\")]\n", + "lv3_lists = [\n", + " samps.values_at_lower_sigma(sigma=3.0, as_instance=False)\n", + " for samps in agg.values(\"samples\")\n", + "]\n", "\n", - "lv3_instances = [\n", - " samps.values_at_lower_sigma(sigma=3.0) for samps in agg.values(\"samples\")\n", + "lv3_dicts = [\n", + " samps.values_at_lower_sigma(sigma=3.0, as_dict=True)\n", + " for samps in agg.values(\"samples\")\n", "]\n", "\n", "print(\"Errors Lists: \\n\")\n", "print(uv3_lists, \"\\n\")\n", "print(lv3_lists, \"\\n\")\n", - "print(\"Errors Instances: \\n\")\n", - "print(uv3_instances, \"\\n\")\n", - "print(lv3_instances, \"\\n\")" + "print(\"Errors Dictionaries: \\n\")\n", + "print(uv3_dicts, \"\\n\")\n", + "print(lv3_dicts, \"\\n\")" ], "outputs": [], "execution_count": null @@ -496,23 +506,31 @@ "cell_type": "code", "metadata": {}, "source": [ - "ue3_lists = [samps.errors_at_upper_sigma(sigma=3.0) for samps in agg.values(\"samples\")]\n", + "ue3_lists = [\n", + " samps.errors_at_upper_sigma(sigma=3.0, as_instance=False)\n", + " for samps in agg.values(\"samples\")\n", + "]\n", "\n", - "# ue3_instances = [\n", - "# samps.errors_at_upper_sigma(sigma=3.0) for samps in agg.values(\"samples\")\n", - "# ]\n", + "ue3_dicts = [\n", + " samps.errors_at_upper_sigma(sigma=3.0, as_dict=True)\n", + " for samps in agg.values(\"samples\")\n", + "]\n", "\n", - "le3_lists = [samps.errors_at_lower_sigma(sigma=3.0) for samps in agg.values(\"samples\")]\n", - "# le3_instances = [\n", - "# samps.errors_at_lower_sigma(sigma=3.0) for samps in agg.values(\"samples\")\n", - "# ]\n", + "le3_lists = [\n", + " samps.errors_at_lower_sigma(sigma=3.0, as_instance=False)\n", + " for samps in agg.values(\"samples\")\n", + "]\n", + "le3_dicts = [\n", + " samps.errors_at_lower_sigma(sigma=3.0, as_dict=True)\n", + " for samps in agg.values(\"samples\")\n", + "]\n", "\n", "print(\"Errors Lists: \\n\")\n", "print(ue3_lists, \"\\n\")\n", "print(le3_lists, \"\\n\")\n", - "print(\"Errors Instances: \\n\")\n", - "# print(ue3_instances, \"\\n\")\n", - "# print(le3_instances, \"\\n\")" + "print(\"Errors Dictionaries: \\n\")\n", + "print(ue3_dicts, \"\\n\")\n", + "print(le3_dicts, \"\\n\")" ], "outputs": [], "execution_count": null diff --git a/notebooks/guides/results/start_here.ipynb b/notebooks/guides/results/start_here.ipynb index 48522755..f2a6a692 100644 --- a/notebooks/guides/results/start_here.ipynb +++ b/notebooks/guides/results/start_here.ipynb @@ -577,7 +577,10 @@ " - Deriving errors on derived quantities, such as the Einstein radius.\n", "\n", "Below, is an example of how to use the `Samples` object to estimate the mass model parameters which are\n", - "the median of the probability distribution function and its errors at 3 sigma confidence intervals." + "the median of the probability distribution function and its errors at 3 sigma confidence intervals.\n", + "\n", + "These statistics are computed independently for every parameter, so their combined vector is not guaranteed to\n", + "describe one physically valid profile. We therefore request dictionaries instead of constructing model instances." ] }, { @@ -586,18 +589,18 @@ "source": [ "samples = result.samples\n", "\n", - "median_pdf_instance = samples.median_pdf()\n", + "median_pdf_dict = samples.median_pdf(as_dict=True)\n", "\n", - "print(\"Median PDF Model Instances: \\n\")\n", - "print(median_pdf_instance.galaxies.galaxy.bulge)\n", + "print(\"Median PDF Model Parameters: \\n\")\n", + "print(median_pdf_dict)\n", "print()\n", "\n", - "ue3_instance = samples.values_at_upper_sigma(sigma=3.0)\n", - "le3_instance = samples.values_at_lower_sigma(sigma=3.0)\n", + "ue3_dict = samples.values_at_upper_sigma(sigma=3.0, as_dict=True)\n", + "le3_dict = samples.values_at_lower_sigma(sigma=3.0, as_dict=True)\n", "\n", - "print(\"Errors Instances: \\n\")\n", - "print(ue3_instance.galaxies.galaxy.bulge, \"\\n\")\n", - "print(le3_instance.galaxies.galaxy.bulge, \"\\n\")" + "print(\"Marginalized Parameter Bounds: \\n\")\n", + "print(ue3_dict, \"\\n\")\n", + "print(le3_dict, \"\\n\")" ], "outputs": [], "execution_count": null diff --git a/scripts/guides/results/aggregator/samples.py b/scripts/guides/results/aggregator/samples.py index d21b2b51..820b8bd3 100644 --- a/scripts/guides/results/aggregator/samples.py +++ b/scripts/guides/results/aggregator/samples.py @@ -267,12 +267,14 @@ that are sampled. It therefore enables error estimation via a process called marginalization. The median pdf vector is available, which estimates every parameter via 1D marginalization of their PDFs. + +Because these statistics are computed independently, combining them does not necessarily produce a physically valid +profile. Requesting a dictionary reports the marginalized parameters without constructing a model instance. """ -instance = samples.median_pdf() +parameter_dict = samples.median_pdf(as_dict=True) -print("Median PDF Model Instances: \n") -print(instance, "\n") -print(instance.galaxies.galaxy.bulge) +print("Median PDF Model Parameters: \n") +print(parameter_dict, "\n") print() vector = samples.median_pdf(as_instance=False) @@ -290,22 +292,22 @@ By inputting `sigma=3.0` margnialization find the values spanning 99.7% of 1D PDF. Changing this to `sigma=1.0` would give the errors at the 68.3% confidence limit. """ -instance_upper_sigma = samples.values_at_upper_sigma(sigma=3.0) -instance_lower_sigma = samples.values_at_lower_sigma(sigma=3.0) +parameter_dict_upper_sigma = samples.values_at_upper_sigma(sigma=3.0, as_dict=True) +parameter_dict_lower_sigma = samples.values_at_lower_sigma(sigma=3.0, as_dict=True) -print("Errors Instances: \n") -print(instance_upper_sigma.galaxies.galaxy.bulge, "\n") -print(instance_lower_sigma.galaxies.galaxy.bulge, "\n") +print("Marginalized Parameter Bounds: \n") +print(parameter_dict_upper_sigma, "\n") +print(parameter_dict_lower_sigma, "\n") """ They can also be returned at the values of the parameters at their error values. """ -instance_upper_values = samples.errors_at_upper_sigma(sigma=3.0) -instance_lower_values = samples.errors_at_lower_sigma(sigma=3.0) +parameter_dict_upper_values = samples.errors_at_upper_sigma(sigma=3.0, as_dict=True) +parameter_dict_lower_values = samples.errors_at_lower_sigma(sigma=3.0, as_dict=True) -print("Errors Instances: \n") -print(instance_upper_values.galaxies.galaxy.bulge, "\n") -print(instance_lower_values.galaxies.galaxy.bulge, "\n") +print("Marginalized Parameter Errors: \n") +print(parameter_dict_upper_values, "\n") +print(parameter_dict_lower_values, "\n") """ __Sample Instance__ diff --git a/scripts/guides/results/aggregator/samples_via_aggregator.py b/scripts/guides/results/aggregator/samples_via_aggregator.py index 82508272..c7881bec 100644 --- a/scripts/guides/results/aggregator/samples_via_aggregator.py +++ b/scripts/guides/results/aggregator/samples_via_aggregator.py @@ -243,12 +243,14 @@ that are sampled. It therefore enables error estimation via a process called marginalization. The median pdf vector is available, which estimates every parameter via 1D marginalization of their PDFs. + +Independent marginal statistics need not combine into a physically valid profile, so they are returned as parameter +dictionaries instead of model instances. """ -mp_instances = [samps.median_pdf() for samps in agg.values("samples")] +mp_dicts = [samps.median_pdf(as_dict=True) for samps in agg.values("samples")] -print("Median PDF Model Instances: \n") -print(mp_instances, "\n") -print(mp_instances[0].galaxies.galaxy.bulge) +print("Median PDF Model Parameters: \n") +print(mp_dicts, "\n") print() """ @@ -261,47 +263,63 @@ By inputting `sigma=3.0` margnialization find the values spanning 99.7% of 1D PDF. Changing this to `sigma=1.0` would give the errors at the 68.3% confidence limit. """ -uv3_lists = [samps.values_at_upper_sigma(sigma=3.0) for samps in agg.values("samples")] +uv3_lists = [ + samps.values_at_upper_sigma(sigma=3.0, as_instance=False) + for samps in agg.values("samples") +] -uv3_instances = [ - samps.values_at_upper_sigma(sigma=3.0) for samps in agg.values("samples") +uv3_dicts = [ + samps.values_at_upper_sigma(sigma=3.0, as_dict=True) + for samps in agg.values("samples") ] -lv3_lists = [samps.values_at_lower_sigma(sigma=3.0) for samps in agg.values("samples")] +lv3_lists = [ + samps.values_at_lower_sigma(sigma=3.0, as_instance=False) + for samps in agg.values("samples") +] -lv3_instances = [ - samps.values_at_lower_sigma(sigma=3.0) for samps in agg.values("samples") +lv3_dicts = [ + samps.values_at_lower_sigma(sigma=3.0, as_dict=True) + for samps in agg.values("samples") ] print("Errors Lists: \n") print(uv3_lists, "\n") print(lv3_lists, "\n") -print("Errors Instances: \n") -print(uv3_instances, "\n") -print(lv3_instances, "\n") +print("Errors Dictionaries: \n") +print(uv3_dicts, "\n") +print(lv3_dicts, "\n") """ We can compute the upper and lower errors on each parameter at a given sigma limit. The `ue3` below signifies the upper error at 3 sigma. """ -ue3_lists = [samps.errors_at_upper_sigma(sigma=3.0) for samps in agg.values("samples")] +ue3_lists = [ + samps.errors_at_upper_sigma(sigma=3.0, as_instance=False) + for samps in agg.values("samples") +] -# ue3_instances = [ -# samps.errors_at_upper_sigma(sigma=3.0) for samps in agg.values("samples") -# ] +ue3_dicts = [ + samps.errors_at_upper_sigma(sigma=3.0, as_dict=True) + for samps in agg.values("samples") +] -le3_lists = [samps.errors_at_lower_sigma(sigma=3.0) for samps in agg.values("samples")] -# le3_instances = [ -# samps.errors_at_lower_sigma(sigma=3.0) for samps in agg.values("samples") -# ] +le3_lists = [ + samps.errors_at_lower_sigma(sigma=3.0, as_instance=False) + for samps in agg.values("samples") +] +le3_dicts = [ + samps.errors_at_lower_sigma(sigma=3.0, as_dict=True) + for samps in agg.values("samples") +] print("Errors Lists: \n") print(ue3_lists, "\n") print(le3_lists, "\n") -print("Errors Instances: \n") -# print(ue3_instances, "\n") -# print(le3_instances, "\n") +print("Errors Dictionaries: \n") +print(ue3_dicts, "\n") +print(le3_dicts, "\n") """ __Sample Instance__ diff --git a/scripts/guides/results/start_here.py b/scripts/guides/results/start_here.py index 3f762c40..2e4ff456 100644 --- a/scripts/guides/results/start_here.py +++ b/scripts/guides/results/start_here.py @@ -403,21 +403,24 @@ Below, is an example of how to use the `Samples` object to estimate the mass model parameters which are the median of the probability distribution function and its errors at 3 sigma confidence intervals. + +These statistics are computed independently for every parameter, so their combined vector is not guaranteed to +describe one physically valid profile. We therefore request dictionaries instead of constructing model instances. """ samples = result.samples -median_pdf_instance = samples.median_pdf() +median_pdf_dict = samples.median_pdf(as_dict=True) -print("Median PDF Model Instances: \n") -print(median_pdf_instance.galaxies.galaxy.bulge) +print("Median PDF Model Parameters: \n") +print(median_pdf_dict) print() -ue3_instance = samples.values_at_upper_sigma(sigma=3.0) -le3_instance = samples.values_at_lower_sigma(sigma=3.0) +ue3_dict = samples.values_at_upper_sigma(sigma=3.0, as_dict=True) +le3_dict = samples.values_at_lower_sigma(sigma=3.0, as_dict=True) -print("Errors Instances: \n") -print(ue3_instance.galaxies.galaxy.bulge, "\n") -print(le3_instance.galaxies.galaxy.bulge, "\n") +print("Marginalized Parameter Bounds: \n") +print(ue3_dict, "\n") +print(le3_dict, "\n") """ __Linear Light Profiles__