Seven Lines of Julia (examples sought)

@Glen, excellent example.
PS: for some reason the units in meter were not recognized and had to use longer syntax: L = (14.24 ± 0.2)u"m"

You probably had the global variable m already defined before using Unitful.DefaultSymbols.

1 Like

I’m loving all the examples being presented here. I would like to encourage folks to submit as many different kinds of examples as possible, and I’ll work on collecting them and getting them onto julialang.org and generally on to social media with something like a #WhyJulia or #WorldOfJulia tag. I think @jiahao used to maintain such a thing a while ago for presentations and such.

It would greatly help to have a 3-5 line description of what it is doing, and why it is interesting, to go along with the code snippet.

-viral

16 Likes

@TheCedarPrince, would it be possible to write down your nice example, including an input data source, as a self-contained snippet? Thanks in advance.

The examples are nice and interesting, but IMO <10 LOC is not where Julia really shines. When not relying on packages, this domain is mostly about surface syntax tricks baked into the language.

The amazing powers of the language start to show around 100 LOC, and come into play fully from 1-5 kLOC, replicating functionality and speed of much larger libraries in other languages.

6 Likes

Agree with Tamas, but it is also nice to have a couple of very short examples. Here a Gibbs sampler sampling the posterior parameters of normal observations with mean distributed a priori as N(μ0, σ0) and precision 1/σ^2 a priori as Gamma(α, β):

using Distributions, Statistics
function mc(x, iterations, μ0 = 0., τ0 = 1e-7, α = 0.0001, β = 0.0001)
    sumx, n = sum(x), length(x)
    μ, τ = sumx/n, 1/var(x)
    samples = [(μ, τ)]
    for i in 1:iterations
        μ = rand(Normal((τ0*μ0 + τ*sumx)/(τ0 + n*τ), 1/sqrt(τ0 + n*τ)))
        τ = rand(Gamma(α + n/2, 1/(β + 0.5*sum((xᵢ-μ)^2 for xᵢ in x))))
        push!(samples, (μ, τ))
    end
    samples
end

Usage

samples = mc(rand(Normal(0.2, 1.7^(-0.5)), 1_000), 10_000)
μs, τs = first.(samples), last.(samples)
println("mean μ = ", mean(μs), " ± ", std(μs))
println("precision τ = ", mean(τs), " ± ", std(τs))

Output:

mean μ = 0.2076960556449643 ± 0.023693641548604788
precision τ = 1.8301418451485263 ± 0.08225999887566306

7 Likes

@mschauer, please do not forget to indicate the packages required to run the example provided.

It is self-contained and not based on a package… well you need distributions of course.

@mschauer, so you should add using Distributions

If you look I did.

Couldn’t this be written without the need for a loop and push!? I think this would get you to seven lines while also being to my eye quite readable:

using Distributions, Statistics

function mc(x, iterations, μ₀ = 0., τ₀ = 1e-7, α = 0.0001, β = 0.0001)
    ∑x, n = sum(x), length(x)
    μ, τ = ∑x/n, 1/var(x)
    μₛ = rand(Normal((τ₀*μ₀ + τ*∑x)/(τ₀ + n*τ), 1/√(τ₀ + n*τ)), iterations)
    τₛ = rand(Gamma(α + n/2, 1/(β + 0.5*sum((xᵢ-μ)^2 for xᵢ in x))), iterations)
    samples = [(μ, τ); collect(zip(μₛ, τₛ))]
end

There is interdependence - the next value of μ depends on τ and vice versa. This is typical for a Gibbs sampler that you cannot parallelise it easily and really need a loop here (and this is exactly what brought me to try Julia in the first place :slightly_smiling_face:)

4 Likes

Ah yes, I somehow thought the μ and τ would always come from the outer scope, and the results only differed on the fifth decimal or so when I checked so it seemed equivalent!

1 Like

More than 7 lines of code, but still a quite compact pipeline for geospatial machine learning:

using GeoStats, MLJ, CSV, Plots

model = @load DecisionTreeClassifier

df = CSV.read("agriculture.csv") # link to file: https://github.com/JuliaEarth/GeoStats.jl/blob/master/docs/src/data/agriculture.csv
df.crop = categorical(df.crop)

Ω = georef(df, (:x,:y))

Ωs, Ωt = split(Ω, 0.2, (1.0,-1.0))

𝒯 = ClassificationTask([:band1,:band2,:band3,:band4], :crop)
𝒫 = LearningProblem(Ωs, Ωt, 𝒯)
𝔏 = PointwiseLearn(model)

Ω̂t = solve(𝒫, 𝔏)

plot(Ω̂t, ms=0.2, c=:cividis, title="crop (prediction)")

test

Commented example is here: https://juliaearth.github.io/GeoStats.jl/stable/workflow/#Defining-problems

6 Likes

Nice observation that the “wrong” solution is so good… Bernstein von Mises theorem strikes again.

2 Likes

Love everyone’s contributions… Hate to say it but I hard a hard time finding something around 7 LOC to submit :D. But, I did think of something I did a while back.

mutable struct βLASSO
  η::Float32
  λ::Float32
  β::Float32
end

βLASSO(η = Float32(0.01), λ = Float32(0.009), β = Float32(50.0)) = βLASSO(η, λ, β)

function apply!(o::βLASSO, x, Δ)
  Δ = o.η .* ( Δ .+ ( o.λ .* sign.( Δ ) ) )
  Δ = Δ .* Float32.( abs.( x.data ) .> ( opt.β * opt.λ ) )
  return Δ
end

(full sloppy gist here: https://gist.github.com/caseykneale/b21c4c6cf5119c58d4f933baac16136b)

Summary:
I was reading the following paper: https://arxiv.org/pdf/2007.13657.pdf around when it was first printed. The paper describes a projected gradient descent method for a penalized(β) LASSO regularization. In < 30min I was able to write my own optimizer, implement the majority of the paper and play with the loss function using Flux.jl. Below is a synthetic example of their loss function properly selecting a single variable of interest while minimizing the contributions of the others.
BLASSO wts

Why Julia:
The tools in the ecosystem and the language facilitate quickly implementing cutting edge stuff. Plus, unicode support for readability!

4 Likes

@juliohm, the nice plot took very long time to display in my laptop (2nd time plotting it was also very slow). Any recommendation on this?

It may be an issue with Plots.jl @Rafael_Guerra, I had to lock the version to some old version in the documentation for example because plots became too slow. Are you also using the GR backend? We can try to address this in Zulip or in a private message.

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

@juliohm, yes, I am using the GR backend. Other info: Win10 Julia 1.5.3, GR v0.53.0, Plots v1.9.1. Thanks for the tips and for the offer to look at it. I will reach out on separate channel after doing some more homework on this.

1 Like