From 0d7a4cc9c339682dab280d88e69bb11dc469da1f Mon Sep 17 00:00:00 2001 From: Joao P Dubas Date: Tue, 11 Jun 2024 14:53:19 +0000 Subject: [PATCH] chore(growth): move nil logic to scorer behaviour Handle `nil` measurement in `Growth.Score.Scorer`. --- lib/growth/calc/centile.ex | 6 +----- lib/growth/calc/z_score.ex | 7 +------ lib/growth/score/scorer.ex | 40 +++++++++++++++++++++++++++----------- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/lib/growth/calc/centile.ex b/lib/growth/calc/centile.ex index 8b9dc53..332cf44 100644 --- a/lib/growth/calc/centile.ex +++ b/lib/growth/calc/centile.ex @@ -23,7 +23,7 @@ defmodule Growth.Calc.Centile do alias Growth.Calc.ZScore - @spec compute(number(), ZScore.l(), ZScore.m(), ZScore.s()) :: number() | :na | nil + @spec compute(number(), ZScore.l(), ZScore.m(), ZScore.s()) :: number() | :na @doc """ Compute the centile for a given measurement (`y`) and the Box-Cox values: power (`l`), median (`m`), and coefficient of variation (`s`). @@ -36,10 +36,6 @@ defmodule Growth.Calc.Centile do 19.0 """ - def compute(nil, _, _, _) do - nil - end - def compute(y, l, m, s) do zscore = ZScore.raw(y, l, m, s) diff --git a/lib/growth/calc/z_score.ex b/lib/growth/calc/z_score.ex index 36f43f5..fc87cb5 100644 --- a/lib/growth/calc/z_score.ex +++ b/lib/growth/calc/z_score.ex @@ -34,7 +34,7 @@ defmodule Growth.Calc.ZScore do """ @type s :: number() - @spec compute(number(), l(), m(), s()) :: Growth.measure() + @spec compute(number(), l(), m(), s()) :: number() @doc """ Compute the adjusted z-score for a given measurement (`y`) and the Box-Cox values: power (`l`), median (`m`), and coefficient of variation (`s`). @@ -49,11 +49,6 @@ defmodule Growth.Calc.ZScore do 1.4698319520484722 """ - - def compute(nil, _, _, _) do - nil - end - def compute(y, l, m, s) do y |> raw(l, m, s) diff --git a/lib/growth/score/scorer.ex b/lib/growth/score/scorer.ex index 26ab1cf..6c74334 100644 --- a/lib/growth/score/scorer.ex +++ b/lib/growth/score/scorer.ex @@ -25,7 +25,7 @@ defmodule Growth.Score.Scorer do growth |> lms(indicator) |> Enum.map(fn {precision, {l, m, s}} -> - {precision, {z_score(indicator, growth, l, m, s), centile(indicator, growth, l, m, s)}} + {precision, scores(indicator, growth, l, m, s)} end) %{growth | results: [Map.new([{indicator.measure_name(), result}]) | growth.results]} @@ -58,23 +58,41 @@ defmodule Growth.Score.Scorer do |> Enum.reject(&is_nil/1) end - @spec z_score(module(), Growth.t(), ZScore.l(), ZScore.m(), ZScore.s()) :: number() + @spec scores(module(), Growth.t(), ZScore.l(), ZScore.m(), ZScore.s()) :: + {Growth.measure(), number() | :na, nil} + @doc """ + Calculate the z-score and centile of an indicator measurement. + """ + def scores(indicator, growth, l, m, s) do + measure = Map.get(growth, indicator.measure_name()) + + { + z_score(measure, l, m, s), + centile(measure, l, m, s) + } + end + + @spec z_score(Growth.measure(), ZScore.l(), ZScore.m(), ZScore.s()) :: Growth.measure() @doc """ Check `Growth.Calc.ZScore.compute/4`. """ - def z_score(indicator, growth, l, m, s) do - growth - |> Map.get(indicator.measure_name()) - |> ZScore.compute(l, m, s) + def z_score(nil, _, _, _) do + nil end - @spec centile(module(), Growth.t(), ZScore.l(), ZScore.m(), ZScore.s()) :: number() | :na + def z_score(value, l, m, s) do + ZScore.compute(value, l, m, s) + end + + @spec centile(Growth.measure(), ZScore.l(), ZScore.m(), ZScore.s()) :: number() | :na | nil @doc """ Check `Growth.Calc.Centile.compute/4`. """ - def centile(indicator, growth, l, m, s) do - growth - |> Map.get(indicator.measure_name()) - |> Centile.compute(l, m, s) + def centile(nil, _, _, _) do + nil + end + + def centile(value, l, m, s) do + Centile.compute(value, l, m, s) end end