Skip to content

Commit ecb2db9

Browse files
authored
Pymc tutorial - rendering setup (#3)
* pymc - reorganizing tuturials as a book - WIP * pymc - updated Clay setup for book * pymc - added render command * pymc - fixed render command
1 parent 3935766 commit ecb2db9

File tree

5 files changed

+172
-151
lines changed

5 files changed

+172
-151
lines changed

notebooks/toc.edn

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@
4242
:title "Using PyMC from Clojure - DRAFT 🛠"
4343
:url "projects/stats/pymc/index.html"
4444
:source-path "projects/stats/pymc"
45-
;:cmd ""
45+
:cmd "clj -Adev notebooks/render.clj"
4646
:tags [:pymc :stats :bayes :python :draft]}
4747

48-
{:created "2024-09-07"
48+
{:created "2024-09-07"
4949
:updated "2024-09-07"
5050
:title "Using sklearn models from Clojure with sklearn-clj"
5151
:url "projects/ml/sklearn-clj/index.html"

projects/stats/pymc/clay.edn

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
{:remote-repo {:git-url "https://github.com/scicloj/clojure-data-scrapbook"
22
:branch "main"}
3-
:base-target-path "temp"
4-
:title "Using PyMC from Clojure - DRAFT 🛠"}
3+
:base-target-path "temp"}
Lines changed: 7 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -1,152 +1,12 @@
11
(load-string (slurp "https://raw.githubusercontent.com/scicloj/clojure-data-tutorials/main/header.edn"))
2-
;; ---------------
32

4-
;; This tutorial demonstrates using
5-
;; the probabilistic programming library PyMC
6-
;; from Clojure.
7-
8-
;; We follow the linear regression example from
9-
;; the [Introductory Overview of PyMC](https://www.pymc.io/projects/docs/en/stable/learn/core_notebooks/pymc_overview.html).
10-
11-
;; ## Setup
12-
13-
;; Relevant Clojure namespaces:
14-
15-
(ns index
16-
(:require [libpython-clj2.require :refer [require-python]]
17-
[libpython-clj2.python :refer [py. py.. py.-] :as py]
18-
[fastmath.random :as random]
19-
[tablecloth.api :as tc]
20-
[tablecloth.column.api :as tcc]
21-
[tech.v3.datatype :as dtype]
22-
[scicloj.hanamicloth.v1.plotlycloth :as ploclo]
23-
[scicloj.kind-pyplot.v1.api :as pyplot]
24-
[scicloj.kindly.v4.kind :as kind]))
25-
26-
;; Relevant Python modules:
27-
28-
(require-python '[builtins :as python]
29-
'operator
30-
'[arviz :as az]
31-
'[arviz.style :as az.style]
32-
'[pandas :as pd]
33-
'[matplotlib.pyplot :as plt]
34-
'[numpy :as np]
35-
'[numpy.random :as np.random]
36-
'[pymc :as pm])
37-
38-
;; Some convenience functions to access Python idioms:
39-
40-
(defn brackets [obj entry]
41-
(py. obj __getitem__ entry))
42-
43-
(def colon
44-
(python/slice nil nil))
45-
46-
;; Theme for ArViZ visualizations:
47-
48-
(arviz.style/use "arviz-darkgrid")
49-
50-
;; ## Synthetic data
51-
52-
(def random-seed 8927)
53-
54-
(def dataset-size 101)
55-
56-
(def true-parameter-values
57-
{:alpha 1
58-
:sigma 1
59-
:beta [1 2.5]})
60-
61-
;; We will generate a dataset by the following recipe:
62-
63-
(defn gen-dataset [{:keys [size random-seed
64-
alpha sigma beta]}]
65-
(let [rng (random/rng :isaac random-seed)]
66-
(-> {:x1 (take size (random/->seq rng))
67-
:x2 (-> (take size (random/->seq rng))
68-
(tcc/* 0.2))}
69-
tc/dataset
70-
(tc/add-column :y
71-
#(-> (tcc/+ alpha
72-
(tcc/* (beta 0) (:x1 %))
73-
(tcc/* (beta 1) (:x2 %))
74-
(tcc/* sigma
75-
(dtype/make-reader
76-
:float32 size (rand)))))))))
3+
^:kindly/hide-code
4+
(ns index)
775

78-
(def dataset
79-
(gen-dataset (merge {:random-seed random-seed
80-
:size dataset-size}
81-
true-parameter-values)))
6+
;; # Preface
827

83-
(tc/head dataset)
84-
85-
;; Let us visualize our dataset:
86-
87-
(->> [:x1 :x2]
88-
(mapv (fn [x]
89-
(-> dataset
90-
(ploclo/layer-point
91-
{:=x :x1}))))
92-
kind/fragment)
93-
94-
;; ## Using PyMC
95-
96-
pm/__version__
97-
98-
;; Let us define a Bayesian model for our data:
99-
100-
(def basic-model (pm/Model))
101-
102-
(py/with [_ basic-model]
103-
(let [{:keys [x1 x2 y]} (-> dataset
104-
(update-vals np/array))
105-
alpha (pm/Normal "alpha"
106-
:mu 0
107-
:sigma 10)
108-
beta (pm/Normal "beta"
109-
:mu 0
110-
:sigma 10
111-
:shape 2)
112-
sigma (pm/HalfNormal "sigma"
113-
:sigma 1)
114-
mu (operator/add alpha
115-
(operator/mul (brackets beta 0)
116-
x1)
117-
(operator/mul (brackets beta 0)
118-
x2))
119-
y_obs (pm/Normal "y_obs"
120-
:mu mu
121-
:sigma sigma
122-
:observed y)]))
123-
124-
;; Now we can sample from the posterior:
125-
126-
(def idata
127-
(py/with [_ basic-model]
128-
(pm/sample)))
129-
130-
;; Here is the resulting structure:
131-
132-
(-> idata
133-
(py.- posterior)
134-
(py.- alpha)
135-
(py. sel :draw (python/slice 0 4)))
136-
137-
;; Alternativelty, we could also use the Slice sampling algorithm
138-
;; instead of the default NUTS.
139-
140-
(def slice-idata
141-
(py/with [_ basic-model]
142-
(let [step (pm/Slice)]
143-
(pm/sample 5000 :step step))))
144-
145-
slice-idata
146-
147-
;; ## Posterior analysis
148-
149-
;; Let us plot our sampling using ArViZ:
8+
;; These tutorials demonstrate using
9+
;; the probabilistic programming library [PyMC](https://www.pymc.io/)
10+
;; from Clojure.
15011

151-
(pyplot/pyplot
152-
#(az/plot_trace idata :combined true))
12+
;; * [Intro](./intro.html)
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
;; # Intro
2+
3+
;; Here is our introduction to using PyMC from Clojure.
4+
5+
;; We follow the linear regression example from
6+
;; the [Introductory Overview of PyMC](https://www.pymc.io/projects/docs/en/stable/learn/core_notebooks/pymc_overview.html).
7+
8+
;; ## Setup
9+
10+
;; Relevant Clojure namespaces:
11+
12+
(ns intro
13+
(:require [libpython-clj2.require :refer [require-python]]
14+
[libpython-clj2.python :refer [py. py.. py.-] :as py]
15+
[fastmath.random :as random]
16+
[tablecloth.api :as tc]
17+
[tablecloth.column.api :as tcc]
18+
[tech.v3.datatype :as dtype]
19+
[scicloj.hanamicloth.v1.plotlycloth :as ploclo]
20+
[scicloj.kind-pyplot.v1.api :as pyplot]
21+
[scicloj.kindly.v4.kind :as kind]))
22+
23+
;; Relevant Python modules:
24+
25+
(require-python '[builtins :as python]
26+
'operator
27+
'[arviz :as az]
28+
'[arviz.style :as az.style]
29+
'[pandas :as pd]
30+
'[matplotlib.pyplot :as plt]
31+
'[numpy :as np]
32+
'[numpy.random :as np.random]
33+
'[pymc :as pm])
34+
35+
;; Some convenience functions to access Python idioms:
36+
37+
(defn brackets [obj entry]
38+
(py. obj __getitem__ entry))
39+
40+
(def colon
41+
(python/slice nil nil))
42+
43+
;; Theme for ArViZ visualizations:
44+
45+
(arviz.style/use "arviz-darkgrid")
46+
47+
;; ## Synthetic data
48+
49+
(def random-seed 8927)
50+
51+
(def dataset-size 101)
52+
53+
(def true-parameter-values
54+
{:alpha 1
55+
:sigma 1
56+
:beta [1 2.5]})
57+
58+
;; We will generate a dataset by the following recipe:
59+
60+
(defn gen-dataset [{:keys [size random-seed
61+
alpha sigma beta]}]
62+
(let [rng (random/rng :isaac random-seed)]
63+
(-> {:x1 (take size (random/->seq rng))
64+
:x2 (-> (take size (random/->seq rng))
65+
(tcc/* 0.2))}
66+
tc/dataset
67+
(tc/add-column :y
68+
#(-> (tcc/+ alpha
69+
(tcc/* (beta 0) (:x1 %))
70+
(tcc/* (beta 1) (:x2 %))
71+
(tcc/* sigma
72+
(dtype/make-reader
73+
:float32 size (rand)))))))))
74+
75+
(def dataset
76+
(gen-dataset (merge {:random-seed random-seed
77+
:size dataset-size}
78+
true-parameter-values)))
79+
80+
(tc/head dataset)
81+
82+
;; Let us visualize our dataset:
83+
84+
(->> [:x1 :x2]
85+
(mapv (fn [x]
86+
(-> dataset
87+
(ploclo/layer-point
88+
{:=x :x1}))))
89+
kind/fragment)
90+
91+
;; ## Using PyMC
92+
93+
pm/__version__
94+
95+
;; Let us define a Bayesian model for our data:
96+
97+
(def basic-model (pm/Model))
98+
99+
(py/with [_ basic-model]
100+
(let [{:keys [x1 x2 y]} (-> dataset
101+
(update-vals np/array))
102+
alpha (pm/Normal "alpha"
103+
:mu 0
104+
:sigma 10)
105+
beta (pm/Normal "beta"
106+
:mu 0
107+
:sigma 10
108+
:shape 2)
109+
sigma (pm/HalfNormal "sigma"
110+
:sigma 1)
111+
mu (operator/add alpha
112+
(operator/mul (brackets beta 0)
113+
x1)
114+
(operator/mul (brackets beta 0)
115+
x2))
116+
y_obs (pm/Normal "y_obs"
117+
:mu mu
118+
:sigma sigma
119+
:observed y)]))
120+
121+
;; Now we can sample from the posterior:
122+
123+
(def idata
124+
(py/with [_ basic-model]
125+
(pm/sample)))
126+
127+
;; Here is the resulting structure:
128+
129+
(-> idata
130+
(py.- posterior)
131+
(py.- alpha)
132+
(py. sel :draw (python/slice 0 4)))
133+
134+
;; Alternativelty, we could also use the Slice sampling algorithm
135+
;; instead of the default NUTS.
136+
137+
(def slice-idata
138+
(py/with [_ basic-model]
139+
(let [step (pm/Slice)]
140+
(pm/sample 5000 :step step))))
141+
142+
slice-idata
143+
144+
;; ## Posterior analysis
145+
146+
;; Let us plot our sampling using ArViZ:
147+
148+
(pyplot/pyplot
149+
#(az/plot_trace idata :combined true))
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(ns render
2+
(:require [scicloj.clay.v2.api :as clay]))
3+
4+
(clay/make! {:format [:quarto :html]
5+
:show false
6+
:base-source-path "notebooks"
7+
:source-path ["index.clj"
8+
"intro.clj"]
9+
:base-target-path "docs"
10+
:book {:title "Using PyMC from clojure"}
11+
:clean-up-target-dir true})
12+
13+
(System/exit 0)

0 commit comments

Comments
 (0)