Should you learn Julia?. Is the high performing lovechild of... | by Alexander Bailey | Towards Data Science

Julia is the newest ‘it’ language of the moment, so I thought I’d give it a try. The question is, is it something worth adding to a data scientist's arsenal?
The first thing to know about Julia is that it was easy to download and use (on Mac anyway, good luck Windows users). It was also a breeze to install the kernel to allow it to work within Jupyter notebooks.
Julia isn’t an object-oriented language like Python, so to get writing we need to let go of some (but not all) of those tidy ‘Pythonic’ ways of doing things.
Classes don’t exist in Julia, so we have to make do with structures like we would with MATLAB. Again, like MATLAB, Julia adopts excellent syntax for linear algebra, which is built natively into the language. This replaces the need for modules like NumPy, in favour of more intuitive syntax like A*x , x' and ./ for multiplication, complex conjugate and pointwise division.
The other thing that users should be wary of, and have to get used to with Julia, is ending functions and loops with theend keyword. However, you’ll be pleased to hear that the reason for this is because Julia isn’t a whitespace sensitive language so you’ll never see an “inconsistent use of tabs and spaces in indentation” error again!
Julia is still technically a dynamically typed language, meaning that you don’t need to tell it which variable has which type — similar to how Python works.
However, Julia does support typing which can enforce a variable to be a specific type, unlike Python. This is pretty handy for two reasons:
It allows Julia code to run faster than a fully dynamic language, if a variable is typed then it doesn’t need to check what type it is before performing the calculation.Debugging is easier when dealing with typed variables, as variables can’t be accidentally assigned to a different type without you explicitly doing it. To get the same effect in Python you have to spend a lot of time implementing assert statements on each function input and even then, things can still go wrong!
It allows Julia code to run faster than a fully dynamic language, if a variable is typed then it doesn’t need to check what type it is before performing the calculation.
Debugging is easier when dealing with typed variables, as variables can’t be accidentally assigned to a different type without you explicitly doing it. To get the same effect in Python you have to spend a lot of time implementing assert statements on each function input and even then, things can still go wrong!
This is one of Julia’s niftiest features...
When implementing mathematical expressions in MATLAB or Python, we can often be met with variables like x_hat or sigma . However, in Julia, we can use the Unicode characters as variables instead of giving us x̂, and σ!
“Well how am I supposed to remember the keyboard combination for x̂and σ? I’m not googling it every time I want to use it!”
It’s a valid concern, but not to fear as the core developers of Julia are one step ahead of us. For x̂, just write x\hat ⇥ and forσ , write\sigma ⇥ , similar to how you would in LaTex.
Whilst the cynics may think this is a gimmicky feature, I think it allows for much more readable code and as the Zen of Python says, “Readability counts”.
In my last article, we implemented a logistic regression model from scratch but what does that look like in Julia?
function σ(x::Array{Float64,2})    return 1.0 ./ (1.0 .+ exp.(-x))endfunction fit(        X::Array{Float64,2},        y::Array{Float64,1},        epochs::Int64=100,        μ::Float64=0.0001    )    ε::Float64 = 0.00001    loss = []        X = vcat(X, ones(1,size(X)[end]))    dims, n_data_points = size(X)        w = randn(1,dims)    for i in 1:epochs        X̂ = w*X        ŷ = σ(X̂)    cost = -sum(y'.*log.(ŷ .+ ε) .+ (1 .- y').*log.(1 .- ŷ .+ ε))                dc_dw = -sum((y' .- ŷ).*X,dims=2)'                w = w .- dc_dw * μ        append!(loss,cost)    end    return w,lossendfunction predict(X::Array{Float64,2},w::Array{Float64,1})    X = vcat(X, ones(1,size(X)[end]))    X̂ = w*X    ŷ = σ(X̂)    return ŷend
In this implementation, we can see a perfect example of how Julia’s Unicode characters can make code more readable. The native linear algebra support further simplifies the code by removing np. every time we want to perform multiplication or summation. We have also typed the function inputs to ensure that both the type and dimensionality of the inputs are valid.
Julia’s C based pedigree and typing allow for some pretty nice speed improvements over its sluggish Python parent. This can all be done without making any major improvements to the efficiency of the code.
Let’s calculate the first 10,000 prime numbers with this simple Python function:
def n_primes(n:int)->list:    primes = []    i = 2    while len(primes) < n:        prime_bool = True        for j in range(2,i//2+1):            if i%j == 0:                prime_bool = False        if prime_bool == True:              primes.append(i)        i += 1    return primes
Which takes 2 min 42s. Let’s compare that to Julia when we use typing:
function n_primes(n::Int64)    primes = Int64[]    i::Int64 = 2    while size(primes)[1] < n        prime_bool::Bool = true        for j = 2:i÷2            if i%j == 0                prime_bool = false            end        end        if prime_bool == true              append!(primes,i)        end        i += 1    end    return primesend>> @time n_primes(10000)
This took just 7.55 seconds!
For the intrepid amongst us who want to deploy code in the wild, then compiling to a binary is a useful tool to have.
Python developers are no strangers with the issue of defining dependencies, and wrestling with pip to ensure all packages remain interoperable. Julia’s nifty solution to this is to compile to a single binary. Not only does this mean that deployment can be as simple as putting that binary in a Docker container and launching your service, but it also means that this comes with the same security improvements that come with using languages like Go.
Then don’t let Julia stop you, there is a Python interpreter built directly into Julia so using Python is as simple as using Pycall.
using Pycallpackagename = pyimport(“packagename”)
It really is as easy as that! Pycall allows the use of all built-in Python namespace functions and feature (even use context managers).
Debugging isn’t quite as easy as it is in Python; this could be that I’m just familiar with Python’s traceback errors, or that Python just has a more descriptive way of telling you where your mistake is.
Here’s a quick example to try and illustrate in Python:
... and in Julia:
I think one of these is a lot clearer than the other...
The only other issue with Julia is the lack of support for machine learning libraries. This may be a product of its relative youth, but it remains a frustrating feature. Julia has wrappers for Pandas, TensorFlow and Sklearn but this doesn’t help us if we want to grab a pre-trained ResNet 50 or a Bert model as the chances are they will be written in Python.
Having said that, the Julia community is growing and more native libraries are being built on an almost daily basis like Lathe and MLJ, so there’s hope for us yet!
The lack of class-based objects in Julia can also make using some of those libraries somewhat unwieldy when used outside of Python. For example Pandas’ df.loc[] becomesloc!(df, ).
Finally, there are too many functions in the basis namespace of Julia. In some ways, this is convenient and allows for a MATLAB-like level of usability and ease of writing code. However, it makes the readability of Julia code worse, with it often being hard to tell if a function is there by default, if it’s user-defined or if it’s been imported from another module.
I say yes! What’s the harm anyway? Writing production code in Julia is going to be tough at the moment given the lack of supported libraries available. But, Julia does offer easy to learn syntax, blazing fast code execution, a built-in Python interpreter and host of other potential improvements to a data scientist’s workflow. Given its growing popularity, there might just be a reason to switch over in the future or, maybe your next project has some pretty tough performance constraints? Julia might just be the answer.