Skip to content

Metrics & formulas

Derived from the ai_cdss source (metrics.py builders, recommender.py MVT criterion). Notation: patient \(p\), protocol \(q\), clinical subscale \(k\), session index \(t\) (within a \((p,q)\) pair). \(P_p\) is the set of all protocols available to patient \(p\) (their PPF protocol set, state.all_protocols); \(\mathrm{prescribed}_p \subseteq P_p\) is the set prescribed in the prior week.

Recent adherence

Per-session adherence \(A_t \in [0,1]\) is an input (session data); a day where every session was NOT_PERFORMED sets \(A_t = \mathrm{NaN}\) so a fully-skipped day does not anchor the average. RECENT_ADHERENCE is the exponentially-weighted moving average of \(A_t\) per \((p,q)\) (ewm(alpha, adjust=True)):

\[ \mathrm{RECENT\_ADH}_t = \frac{\sum_{i=0}^{t-1}(1-\alpha)^i\,A_{t-i}} {\sum_{i=0}^{t-1}(1-\alpha)^i}, \qquad \alpha = 0.5 . \]

Delta DM

A robust local trend of the difficulty-modulation value \(\mathrm{DM}\) per \((p,q)\), in two steps (build_delta_dm).

1 · Smoothing — Savitzky–Golay filter (window \(L=7\), polynomial order \(2\)):

\[ \widetilde{\mathrm{DM}} = \mathrm{SavGol}\!\left(\mathrm{DM};\, L=7,\, \mathrm{poly}=2\right). \]

2 · Slope — rolling Theil–Sen regression of \(\widetilde{\mathrm{DM}}\) against the session index over a window \(W=7\) (median of pairwise slopes, outlier-robust):

\[ \mathrm{DELTA\_DM}_t = \operatorname*{median}_{\substack{i<j \\ i,j \in [t-W+1,\,t]}} \frac{\widetilde{\mathrm{DM}}_j - \widetilde{\mathrm{DM}}_i}{\,j-i\,}, \qquad W = 7 . \]

Missing values are filled with \(0\).

Patient–protocol fit (PPF)

Cosine similarity between the patient's clinical deficit vector and the protocol's attribute vector, both indexed by subscale \(k\) (compute_ppf).

Patient deficit (normalize clinical scores by their max, take the complement):

\[ d_{p,k} = 1 - \frac{\mathrm{score}_{p,k}}{\max_k}. \]

Protocol attributes (mean of the protocol features mapped to subscale \(k\)):

\[ a_{q,k} = \operatorname{mean}\{\,\text{features of } q \text{ mapped to } k\,\}. \]

PPF (cosine):

\[ \mathrm{PPF}(p,q) = \frac{d_p \cdot a_q}{\lVert d_p\rVert\,\lVert a_q\rVert} = \sum_k \hat d_{p,k}\,\hat a_{q,k}, \qquad \hat d_{p,k} = \frac{d_{p,k}}{\lVert d_p\rVert}, \quad \hat a_{q,k} = \frac{a_{q,k}}{\lVert a_q\rVert}. \]

The per-subscale contribution \(\mathrm{CONTRIB}_{p,q,k} = \hat d_{p,k}\,\hat a_{q,k}\) sums over \(k\) to \(\mathrm{PPF}(p,q)\).

Score

Weighted linear combination of the three metrics (default weights \(w=[1,1,1]\)); missing components are treated as \(0\) (Scorer):

\[ \mathrm{SCORE}(p,q) = w_0\,\mathrm{RECENT\_ADH}(p,q) + w_1\,\mathrm{DELTA\_DM}(p,q) + w_2\,\mathrm{PPF}(p,q). \]

MVT swap criterion

The threshold is the mean score over all of patient \(p\)'s protocols (per-patient, protocol-wide) (_below_mean_protocols):

\[ \theta_p = \frac{1}{|P_p|}\sum_{q \in P_p}\mathrm{SCORE}(p,q). \]

Swap targets are the prescribed protocols scoring strictly below that patient's own protocol-set mean:

\[ \mathrm{swap}_p = \bigl\{\, q \in \mathrm{prescribed}_p : \mathrm{SCORE}(p,q) < \theta_p \,\bigr\}. \]

Fallback (aisn_min_one_swap): if \(\mathrm{swap}_p = \varnothing\), force-swap the single lowest-scoring prescribed protocol, \(\arg\min_{q \in \mathrm{prescribed}_p} \mathrm{SCORE}(p,q)\).

Constants

Symbol Value Source (constants.py)
\(\alpha\) (EWMA) \(0.5\) EWMA_ALPHA
\(L\) (Savitzky–Golay window) \(7\) SAVGOL_WINDOW_SIZE
poly (Savitzky–Golay order) \(2\) SAVGOL_POLY_ORDER
\(W\) (Theil–Sen window) \(7\) THEILSON_REGRESSION_WINDOW_SIZE
\(w\) (score weights) \([1,1,1]\) Scorer default