Skip to content

Instantly share code, notes, and snippets.

@jcpsantiago
Created June 27, 2025 20:24
Show Gist options
  • Save jcpsantiago/398ee7b0d65fac6eba43517d83ed2dfd to your computer and use it in GitHub Desktop.
Save jcpsantiago/398ee7b0d65fac6eba43517d83ed2dfd to your computer and use it in GitHub Desktop.
Prostate cancer risk group classification shifts between NCCN and EAU 2025
(ns eau-nccn
"Script to explore how different patient groups are classified
according to the 2025 EAU Guidelines for Prostate Cancer and the
NCCN.
It starts by creating a list of all the permutations of the
relevant markers, then applying the different classifications to each permutation.
Finally, we calculate the % of each classification and the frequency
of each EAU<>NCCN combination.
The Sankey diagram can be accessed via this public link:
https://sankeymatic.com/build/?i=PTAEFEDsBcFMCdQDEA2B7A7gZ1AI1tBrLJKAHJoAmsWANKCgJYDWso0AFo1gFwBQIUEOHCAymgCu8AMZsA2gEEAsgHkAqmQAqAXVCaAhvADmBPnzIBhC2VAAZTKHjdmoOQBZd4BWrsOnWZnMrGyR9ADdJeH1cFHkAVk9vZHDI6Nig61A1SAAzFKk0%2BQBGAA5En2y8iIKY2AybAAlGIw5HZ1cigGYAJnLQJpa2gLNLTNDqqNqOvoHW%2D0DRm0r8ydjXAE4%2B8dTa%2BqzclcKOopnmueczM0EATUlQaX1SLAJQfXIqWAByHGk0dHh6ExWOwuLwBGAeAAhCSUEzQUAAYgADHEAOzgkSY4QAOlxaEQb1%2B%2D1AOXxr1AWEYkCMa1QmH4gmhsJechOoBUnAQ5FgsiwlOgjBoiIAbEjhVcwAAiOQAKm0ktAAFtYI8cJK1M9XpAAJ6vRWSGAMWA5eFoMIISUMsBMuGuOWgUThKlGLASrKazn3NAweB%2DHD4dAYdhoe4SLDQNCKxgALzqgm1kVAlEY%2BiMUUV31eAAcsyqopBZLjsXxKbHQEHRUi%2BEJWpW%2BIrDEYqQxQEVutXHK320J4aUO7hQN0q7gjF7iQicpOpx3oPmsFnDCR4WQ%2BJAPuWux3WnEq0J5%2DppM7QKi4v38dRELuQbBla8O0SyQiSs%2BXx20AvD9BdUU%2BDlA6H4DCfRoCkNgkWxU8hCpDgEEYaAcl9RVQEkaBKWoABaKl7z%2BR91jw%2DC3w%2DODdXAtxTxQfQEwkU14AvV5qMjYDGGkDsACswwFHIEycJtIBwFchHY8NGC4khKH4jt4Fgc14GeNN9CzVoBNeaBoAPLgC0jLNYjgcMQ0gPMaGgPgKIDH4cMQZEkWs6yt0YahyDslomBaeFwJPDtSRgPJZApVV0OeJwcg7JgDP3Q9qVAcDu0cWAKIFc1SzYIoiivBsjEgETv1s0y4sgfRbwU3NDBwa4OyS1txSEIgznhNwcuiOKgJQCQ2CKvNSs8iQUBQLMpMPSlvVAMqhCzNB%2BUYIaA0wDsatc0B6qrXLevGuDJtIfQGP0FzSCvLBpBgwqGM8xhZPhfBSSk%2DspP0ZgxqpeFOj4ZrWpJfEG3hT5aGxT4Oz641GAAD1AT5fr3CRJyBkHfs5ZU0EnZ54TedZ%2Byi%2B9QCeoRKAx%2BsCDeZUYHWrBHlYbUPuYxyhCYYTFVwbbHl5YagA
")
(def perms
(for [psa [9 15 21]
biopsy [1 2]
isup [1 2 3 4 5]
t-stage [1 2 3 4 5 6]]
{:psa psa
:biopsy biopsy
:isup isup
:t-stage t-stage}))
(defn t
"
Map t-stage to an integer for easier math.
"
[k]
(let [t-stages [:t1 :t2a :t2b :t2c :t3 :t4]
t-mapping (zipmap t-stages [1 2 3 4 5 6])]
(if (contains? t-mapping k)
(k t-mapping)
(throw (ex-info (str t " is not a valid t-stage! Valid stages " t-stages)
{:k k :t-mapping t-mapping})))))
(defn eau-low
[{:keys [psa isup t-stage]}]
(and
(= isup 1)
(< psa 10)
(<= t-stage (t :t2a))))
(defn eau-favorable
[{:keys [psa isup t-stage]}]
(or
(and
(= isup 2)
(< psa 10)
(<= t-stage (t :t2b)))
(and
(= isup 1)
(<= 10 psa 20)
(<= t-stage (t :t2b)))
(and
(= isup 1)
(< psa 10)
(= t-stage (t :t2b)))))
(defn eau-unfavorable
[{:keys [psa isup t-stage]}]
(or
(and
(= isup 2)
(<= 10 psa 20)
(<= t-stage (t :t2b)))
(and
(= isup 3)
(<= t-stage (t :t2b)))))
(defn eau-high
[{:keys [psa isup t-stage]}]
(or
(> isup 3)
(> psa 20)
(>= t-stage (t :t2c))))
(defn eau
[m]
(cond
(eau-high m) :high-risk
(eau-low m) :low-risk
(eau-favorable m) :favorable
(eau-unfavorable m) :unfavorable
:else :uncategorized))
(def eau-freqs
(->> perms
(map #(assoc % :eau (eau %)))
(map :eau)
(frequencies)))
(defn add-percent
[perms freqs]
(reduce
(fn [p c]
(update p c (fn [v] [v (str (int (* (/ v (count perms)) 100)) "%")])))
freqs
(keys freqs)))
;; ----------------------------------------------------------------------------
(defn nccn-low
[{:keys [psa isup t-stage]}]
(and
(= isup 1)
(< psa 10)
(<= t-stage (t :t2a))))
(def nccn-intermediate-factors
[(fn [{:keys [isup]}]
(<= 2 isup 3))
(fn [{:keys [psa]}]
(<= 10 psa 20))
(fn [{:keys [t-stage]}]
(<= (t :t2b) t-stage (t :t2c)))])
(defn nccn-n-intermediate-risk-factors
[perm]
(->> nccn-intermediate-factors
(map #(% perm))
(filter true?)
(count)))
(defn nccn-favorable
[{:keys [isup biopsy] :as perm}]
(and
(= (nccn-n-intermediate-risk-factors perm) 1)
(< isup 3)
(= biopsy 1)))
(defn nccn-unfavorable
[{:keys [isup biopsy] :as perm}]
(or
(<= 2 (nccn-n-intermediate-risk-factors perm) 3)
(= isup 3)
(= biopsy 2)))
(defn nccn-high
[{:keys [psa isup t-stage]}]
(or
(> isup 3)
(> psa 20)
(>= t-stage (t :t3))))
(defn nccn
[m]
(cond
(nccn-high m) :high-risk
(nccn-low m) :low-risk
(nccn-favorable m) :favorable
(nccn-unfavorable m) :unfavorable
:else :uncategorized))
(def nccn-freqs
(->> perms
(map #(assoc % :nccn (nccn %)))
(map :nccn)
(frequencies)))
(def percentages
{:eau (add-percent perms eau-freqs)
:nccn (add-percent perms nccn-freqs)
:combinations (->> perms
(map #(assoc % :eau (eau %)))
(map #(assoc % :nccn (nccn %)))
;; (filter #(and (= (:eau %) :favorable)
;; (= (:nccn %) :unfavorable))))
(map #(assoc % :same? (= (:eau %) (:nccn %))))
(map (fn [p] [(:eau p) (:nccn p)]))
(frequencies))})
percentages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment