-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
90 average calibration functions in utils.jl #97
Changes from 22 commits
733312a
25ea642
c290ed8
4ff22f4
6a22210
df3d60d
09f25e8
07b318f
eafa7bd
f66e08e
5355281
2efaa99
26643ee
b79ca39
0d71736
5f772cf
d146d1d
7af9378
2c42236
9d67ddc
9f07583
f81d226
6cdc503
89bb19b
6fe01a2
0bba488
8311de3
7837333
b0518b2
6a9ee1b
203513d
dce9bdb
b906c3b
2059bed
3258618
c86dc25
3d2ebd6
4ab04f6
267b8f4
d188daf
270b70a
3320063
3750dbe
39d4bdc
56c3b66
908c804
f468803
459b2fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,3 +1,5 @@ | ||||||||||||
using Distributions: Distributions | ||||||||||||
using Statistics: mean, var | ||||||||||||
""" | ||||||||||||
functional_variance(la::AbstractLaplace, 𝐉::AbstractArray) | ||||||||||||
|
||||||||||||
|
@@ -22,6 +24,8 @@ Computes the linearized GLM predictive. | |||||||||||
- `fμ::AbstractArray`: Mean of the predictive distribution. The output shape is column-major as in Flux. | ||||||||||||
- `fvar::AbstractArray`: Variance of the predictive distribution. The output shape is column-major as in Flux. | ||||||||||||
|
||||||||||||
- `normal_distr` An array of normal distributions approximating the predictive distribution p(y|X) given the input data X. | ||||||||||||
|
||||||||||||
# Examples | ||||||||||||
|
||||||||||||
```julia-repl | ||||||||||||
|
@@ -39,7 +43,10 @@ function glm_predictive_distribution(la::AbstractLaplace, X::AbstractArray) | |||||||||||
fμ = reshape(fμ, Flux.outputsize(la.model, size(X))) | ||||||||||||
fvar = functional_variance(la, 𝐉) | ||||||||||||
fvar = reshape(fvar, size(fμ)...) | ||||||||||||
return fμ, fvar | ||||||||||||
fstd = sqrt.(fvar) | ||||||||||||
normal_distr = [ | ||||||||||||
Distributions.Normal(fμ[i], fstd[i]) for i in 1:size(fμ, 1)] | ||||||||||||
return (normal_distr,fμ,fvar ) | ||||||||||||
pasq-cat marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||
end | ||||||||||||
|
||||||||||||
""" | ||||||||||||
|
@@ -55,9 +62,10 @@ Computes predictions from Bayesian neural network. | |||||||||||
- `predict_proba::Bool=true`: If `true` (default), returns probabilities for classification tasks. | ||||||||||||
|
||||||||||||
# Returns | ||||||||||||
|
||||||||||||
For classification tasks: | ||||||||||||
- `fμ::AbstractArray`: Mean of the predictive distribution if link function is set to `:plugin`, otherwise the probit approximation. The output shape is column-major as in Flux. | ||||||||||||
- `fvar::AbstractArray`: If regression, it also returns the variance of the predictive distribution. The output shape is column-major as in Flux. | ||||||||||||
For regression tasks: | ||||||||||||
- `normal_distr::Distributions.Normal`:the array of Normal distributions computed by glm_predictive_distribution. The output shape is column-major as in Flux. | ||||||||||||
|
||||||||||||
# Examples | ||||||||||||
|
||||||||||||
|
@@ -75,11 +83,12 @@ predict(la, hcat(x...)) | |||||||||||
function predict( | ||||||||||||
la::AbstractLaplace, X::AbstractArray; link_approx=:probit, predict_proba::Bool=true | ||||||||||||
) | ||||||||||||
fμ, fvar = glm_predictive_distribution(la, X) | ||||||||||||
normal_distr,fμ, fvar = glm_predictive_distribution(la, X) | ||||||||||||
pasq-cat marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||
#fμ, fvar = mean.(normal_distr), var.(normal_distr) | ||||||||||||
|
||||||||||||
# Regression: | ||||||||||||
if la.likelihood == :regression | ||||||||||||
return fμ, fvar | ||||||||||||
return normal_distr | ||||||||||||
end | ||||||||||||
|
||||||||||||
# Classification: | ||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
using Flux | ||
using Statistics | ||
|
||
""" | ||
get_loss_fun(likelihood::Symbol) | ||
|
@@ -39,3 +40,112 @@ corresponding to the number of neurons on the last layer of the NN. | |
function outdim(model::Chain)::Number | ||
return [size(p) for p in Flux.params(model)][end][1] | ||
end | ||
|
||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i fixed the docstrings but for a new line ( without the empy line in the middle), i had to use the \ character. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i checked the results in the julia repl but i was not able to make the function appear in the documentation. i tried to go in docs/ and then type julia make.jl and i got "[ Info: SetupBuildDirectory: setting up build directory. |
||
empirical_frequency(Y_val,array) | ||
|
||
FOR REGRESSION MODELS. | ||
Given a calibration dataset (x_t, y_t) for i ∈ {1,...,T} and an array of predicted distributions, the function calculates the empirical frequency | ||
phat_j = {y_t|F_t(y_t)<= p_j, t= 1,....,T}/T, where T is the number of calibration points, p_j is the confidence level and F_t is the | ||
cumulative distribution function of the predicted distribution targeting y_t. The function was suggested by Kuleshov(2018) in https://arxiv.org/abs/1807.00263 | ||
Arguments: | ||
Y_val: a vector of values y_t | ||
array: an array of sampled distributions F(x_t) stacked column-wise. | ||
""" | ||
function empirical_frequency(Y_cal,sampled_distributions) | ||
|
||
|
||
quantiles= collect(0:0.05:1) | ||
quantiles_matrix = hcat([quantile(samples, quantiles) for samples in sampled_distributions]...) | ||
n_rows = size(bounds_quantiles_matrix,1) | ||
counts = [] | ||
|
||
for i in 1:n_rows | ||
push!(counts, sum(Y_cal .<= quantiles_matrix[i, :]) / length(Y_cal)) | ||
end | ||
return counts | ||
end | ||
|
||
""" | ||
sharpness(array) | ||
|
||
FOR REGRESSION MODELS. | ||
Given a calibration dataset (x_t, y_t) for i ∈ {1,...,T} and an array of predicted distributions, the function calculates the | ||
sharpness of the predicted distributions, i.e., the average of the variances var(F_t) predicted by the forecaster for each x_t | ||
The function was suggested by Kuleshov(2018) in https://arxiv.org/abs/1807.00263 | ||
Arguments: | ||
sampled_distributions: an array of sampled distributions F(x_t) stacked column-wise. | ||
""" | ||
function sharpness(sampled_distributions) | ||
sharpness= mean(var.(sampled_distributions)) | ||
return sharpness | ||
|
||
end | ||
|
||
|
||
|
||
|
||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above comment on maths notation |
||
empirical_frequency-classification(Y_val,array) | ||
|
||
FOR BINARY CLASSIFICATION MODELS. | ||
Given a calibration dataset (x_t, y_t) for i ∈ {1,...,T} let p_t= H(x_t)∈[0,1] be the forecasted probability. | ||
We group the p_t into intervals I-j for j= 1,2,...,m that form a partition of [0,1]. The function computes | ||
the observed average p_j= T^-1_j ∑_{t:p_t ∈ I_j} y_j in each interval I_j. | ||
The function was suggested by Kuleshov(2018) in https://arxiv.org/abs/1807.00263 | ||
Arguments: | ||
y_binary: the array of outputs y_t numerically coded . 1 for the target class, 0 for the negative result. | ||
|
||
sampled_distributions: an array of sampled distributions stacked column-wise where in the first row | ||
there is the probability for the target class y_1=1 and in the second row y_0=0. | ||
""" | ||
function empirical_frequency_binary_classification(y_binary,sampled_distributions) | ||
|
||
pred_avg= collect(range(0,step=0.1,stop=0.9)) | ||
emp_avg = [] | ||
total_pj_per_intervalj = [] | ||
class_probs = sampled_distributions[1, :] | ||
|
||
for j in 1:10 | ||
j_float = j / 10.0 -0.1 | ||
push!(total_pj_per_intervalj,sum( j_float.<class_probs.<j_float+0.1)) | ||
|
||
|
||
if total_pj_per_intervalj[j]== 0 | ||
#println("it's zero $j") | ||
push!(emp_avg, 0) | ||
#push!(pred_avg, 0) | ||
else | ||
indices = findall(x -> j_float < x <j_float+0.1, class_probs) | ||
|
||
|
||
|
||
push!(emp_avg, 1/total_pj_per_intervalj[j] * sum(y_binary[indices])) | ||
println(" numero $j") | ||
pred_avg[j] = 1/total_pj_per_intervalj[j] * sum(sampled_distributions[1,indices]) | ||
end | ||
|
||
end | ||
|
||
return (total_pj_per_intervalj, emp_avg, pred_avg) | ||
end | ||
|
||
""" | ||
sharpness-classification(array) | ||
|
||
FOR BINARY CLASSIFICATION MODELS. | ||
We can also assess sharpness by looking at the distribution of model predictions.When forecasts are sharp, | ||
most predictions are close to 0 or 1; unsharp forecasters make predictions closer to 0.5. | ||
The function was suggested by Kuleshov(2018) in https://arxiv.org/abs/1807.00263 | ||
|
||
Arguments: | ||
y_binary: the array of outputs y_t numerically coded . 1 for the target class, 0 for the negative result. | ||
sampled_distributions: an array of sampled distributions stacked column-wise where in the first row | ||
there is the probability for the target class y_1=1 and in the second row y_0=0. | ||
""" | ||
function sharpness_classification(y_binary, sampled_distributions) | ||
class_one = sampled_distributions[1, findall(y_binary .== 1)] | ||
class_zero = sampled_distributions[2, findall(y_binary .== 0)] | ||
|
||
return mean(class_one), mean(class_zero) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we could just keep this consistent and return everything in both cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edit: my bad, let's indeed as discussed just add an option for classification to return distribution. By default, we should still return probabilities for now, but at least we give the option and add that to the docstring.