Book Image

Julia Programming Projects

By : Adrian Salceanu
Book Image

Julia Programming Projects

By: Adrian Salceanu

Overview of this book

Julia is a new programming language that offers a unique combination of performance and productivity. Its powerful features, friendly syntax, and speed are attracting a growing number of adopters from Python, R, and Matlab, effectively raising the bar for modern general and scientific computing. After six years in the making, Julia has reached version 1.0. Now is the perfect time to learn it, due to its large-scale adoption across a wide range of domains, including fintech, biotech, education, and AI. Beginning with an introduction to the language, Julia Programming Projects goes on to illustrate how to analyze the Iris dataset using DataFrames. You will explore functions and the type system, methods, and multiple dispatch while building a web scraper and a web app. Next, you'll delve into machine learning, where you'll build a books recommender system. You will also see how to apply unsupervised machine learning to perform clustering on the San Francisco business database. After metaprogramming, the final chapters will discuss dates and time, time series analysis, visualization, and forecasting. We'll close with package development, documenting, testing and benchmarking. By the end of the book, you will have gained the practical knowledge to build real-world applications in Julia.
Table of Contents (19 chapters)
Title Page
Copyright and Credits
Dedication
About Packt
Contributors
Preface
Index

Getting started with Julia


If you followed through the first part of the chapter, by now you should have a fully functional local Julia installation, the knowledge to start a Julia REPL session, and have your preferred IDE ready for coding. If that is not the case, please refer to the previous sections. From this point on we're getting down to business—it's time to write some Julia code!

The Julia REPL

The first thing we need to understand is how to use the powerful REPL. As a Julia developer, you'll spend a significant amount of time doing exploratory programming, interacting with the shell and the filesystem, and managing packages. The REPL will be your trusted sidekick. It's worth getting to know it well, it will save you a lot of time down the line.

The acronym REPL stands for read-eval-print loop. Simply put, it's a language-specific shell, an interactive coding environment that allows inputting expressions, evaluates them, and outputs the result.

REPLs are very useful as they provide a simple way to interact with the language, to try out ideas and prototype, facilitating exploratory programming and debugging. It is especially powerful in the context of data analysis, where one can quickly connect to a data source, load a data sample and then slice and dice, rapidly testing different hypothesis.

Julia provides an excellent REPL experience, with rich functionality that covers quick evaluation of Julia statements, searchable history, tab-completion, syntax highlighting, dedicated help and shell modes, to name just a few.

If you do not have a working Julia installation, please see the Installing Julia section.

Interacting with the REPL

Depending on your OS and your preferences, the REPL can be started by simply invoking $ julia with no arguments, or by double-clicking the julia executable.

You will be greeted with a screen like this one (the Julia version might be different than mine):

Now Julia is waiting for us to input our code, evaluating it line by line. You can confirm that by checking the Terminal prompt, which says julia>. This is called the julian mode. Let's take it for a spin.

Note

You can follow through the IJulia Jupyter notebook provided with this chapter's support files. If you are not familiar with Jupyter and don't know how to run it locally, you can use Juliabox (juliabox.com). All you have to do is create an account, log in, and then load the notebook from https://github.com/PacktPublishing/Julia-Programming-Projects/blob/master/Chapter01/Chapter%201.ipynb.

Input the following lines, pressing Enter after each one:

julia> 2+2 
julia> 2^3

So we can use Julia like a simple calculator. Not very useful, but this is only the beginning and illustrates how powerful this rapid input and feedback cycle can be when we deal with complex computations.

println is a very useful function that prints whatever value it receives, appending a new line afterward. Type the following code:

julia> println("Welcome to Julia")

Under each line, you should see the output generated by each expression. Your window should now look like this.

julia> 2+2 
4 
julia> 2^3 
8 
julia> println("Welcome to Julia") 
Welcome to Julia

Let's try some more. The REPL interprets one line at a time, but everything is evaluated in a common scope. This means that we can define variables and refer to them later on, as follows:

julia> greeting = "Hello" 
"Hello"

This looks great! Let's use the greeting variable with println:

julia> println(greting) 
ERROR: UndefVarError: greting not defined

Oops! A little typo there, and the REPL promptly returned an error. It's not greting, it's greeting. This also tells us that Julia does not allow using variables without properly initializing them. It just looked for the greting variable, unsuccessfully—and it threw an undefined variable error. Let's try that again, this time more carefully:

julia> println(greeting) 
Hello

OK, that's much better! We can see the output: the Hello value we stored in the greeting variable.

The ans variable

The REPL provides a few helping features, specific to this interactive environment (they won't be available when executing a Julia script). One of these is the ans variable, automatically set up and updated by Julia.

If you type julia> 2^3—unsurprisingly, you'll get 8. Now input julia> ans—you'll get 8 again! What's up with that? ans is a special variable that exists only in the REPL and that automatically stores the last returned value. It can prove very useful when working with the REPL, but more importantly, you need to be aware of its existence so that you don't accidentally declare a variable with the same name. Otherwise, you'll run into some very hard to understand bugs with your variable's value constantly overwritten.

Prompt pasting

The REPL comes with a very powerful feature called prompt pasting. This allows us to copy-paste-execute Julia code and snippets that include both the julia> prompt and the output of the expression. It activates when pasting text that starts with julia>. In that case, only expressions starting with julia> are parsed, and all the others are ignored. This makes it possible to paste a chunk of code that has been copied from another REPL session or from the documentation, without having to scrub away prompts and outputs.

Note

Prompt pasting does not work in IJulia Jupyter notebooks.

To see this in action, copy and paste the following snippet, as is:

julia> using Dates 
 
julia> Dates.now() 
2018-09-02T21:13:03.122 
julia> ans 
2018-09-02T21:13:03.122

If all goes well, both expressions should output your current time, and not the one from the snippet, effectively replacing the results in the snippet with the results in your Julia session.

Note

This feature does not work with the default Windows command prompt due to its limitations.

Tab completion

In both the Julian, pkg, and help modes you can press the Tab key after entering the first few characters of a function to get a list of all the matches:

julia> pri[TAB] 
primitive type   print             print_shortest    print_with_color  println           printstyled 

It can also be used to substitute LaTeX math symbols with their Unicode equivalents. To do this, type a backslash as the first character, then the first few characters of the symbol, then Tab. This will complete the name of the symbol or will display a list of options if there's more than one matching name. Pressing Tab again on the complete name of the symbol will perform the replacement:

julia> \pi[TAB] 
julia> π 
π = 3.1415926535897... 

julia> \om[TAB] \omega \ominus 
julia> \ome[TAB] 
julia> \omega[TAB] 
julia> ω
Cleaning the REPL scope

Julia does not have the concept of null so you can't really deallocate a variable from memory. If, however, you need to free an expensive resource referenced by a variable, you can replace its value with something like 0 and the previous value will be automatically garbage collected. You can even invoke the garbage collector yourself straight away by calling gc().

Additional REPL modes

The Julia REPL comes with four operational modes—and additional ones can be defined as needed. The currently active mode is indicated by its prompt. In the previous examples we've used the julian mode julia>, which evaluates the inputted expression. The other three available modes are help, help?>, shell, shell>, and package management, pkg>.

The active mode can be switched by typing a specific character right at the beginning of the line. The prompt will change in response, to indicate the current mode. The mode will stay active until the current line is evaluated, automatically switching back to julian (with the exception of the pkg> mode which is sticky—that is, it stays active until explicitly exited by typing backspace at the beginning of the line). The alternative modes can be exited without evaluating the expression by deleting everything on the line until the prompt changes back to julia>, or by pressing Ctrl + C.

Accessing the documentation with the help mode

The help mode provides access to documentation without having to get out of the REPL. To access it, simply type ? at the beginning of the line. You should see the  help?> prompt. Now you can input text, and Julia will search the documentation for matching entries, as follows:

julia> ?  
help?> println 
search: println printstyled print_with_color print print_shortest sprint isprint 
 
  println([io::IO], xs...) 
 
  Print (using print) xs followed by a newline. If io is not supplied, prints to stdout. 
 
  Examples 
  ≡≡≡≡≡≡≡≡≡≡ 
 
  julia> println("Hello, world") 
  Hello, world 
 
  julia> io = IOBuffer(); 
 
  julia> println(io, "Hello, world") 
 
  julia> String(take!(io)) 
  "Hello, world\n" 

Note

In IJulia, the additional modes are activated by prefixing the input with the desired mode activator. For instance, to access the help for the previous println function, we need to input ?println.

The output supports rich formatting, via Markdown:

julia> using Profile 
help?> Profile.print

Resulting a rich output as in the following screenshot:

More complex expressions can be queried, including macros, types, and variables.

For example, help?> @time:

Or help?> IO:

Shell mode

The shell mode is used to switch to a command-line interface similar to the system shell, for directly executing OS commands. To enter it, input a semicolon ; at the very beginning of the julian prompt:

julia> ;

Upon typing ; the prompt changes (in place) to shell>:

Note

To enter shell mode in IJulia and execute a shell command, prefix the command with ;, for example ;ls.

Now we can execute system-wide commands directly, without the need to wrap them in Julia code. This will list the last ten lines of your repl_history.jl file. This file is used by Julia to keep a history of the commands executed in the REPL, so your output will be different from mine:

julia> using REPL
shell> tail -n 10 ~/.julia/logs/repl_history.jl
IO
# time: 2018-09-02 21:56:47 CEST
# mode: julia
REPL.find_hist_file()
# time: 2018-09-02 21:58:47 CEST
# mode: shell
tail -n 10 ~/.julia/logs/repl_history.jl

While in REPL mode we can access Julia's API, making this a very powerful combo. For example, in order to programmatically get the path to the REPL history file, we can use the REPL.find_hist_file() function, as follows:

julia> REPL.find_hist_file() 
"/Users/adrian/.julia/logs/repl_history.jl"

The path to the file will be different for you.

We can use this in the shell mode by wrapping the command in $():

shell> tail -n 10 $(REPL.find_hist_file()) 
    REPL.find_hist_file() 
# time: 2018-09-02 21:58:47 CEST 
# mode: shell 
    tail -n 10 ~/.julia/logs/repl_history.jl 
# time: 2018-09-02 22:00:03 CEST 
# mode: shell 
    tail -n 10 $(REPL.find_hist_file())

Similarly to the help mode, the shell mode can be exited without executing any command by pressing backspace at the beginning of the line or typing Ctrl + C.

In IJulia, the command can be executed by prefixing the input with ;, like this:

;tail -n 10 ~/.julia/logs/repl_history.jl

Search modes

Besides the help and the shell modes, there are two search modes. These are not necessarily Julia specific, being common to many *nix style editing apps.

Press the Ctrl key and the R key at the same time in order to initiate a reverse incremental search. The prompt will change to (reverse-i-search). Start typing your query and the most recent result will show. To find older results, type Ctrl + R again.

The counterpart of Ctrl + R is Ctrl + S, initiating an incremental search. The two may be used in conjunction to move through the previous or next matching results, respectively.

The startup.jl file

If you want to automatically execute some code every time you run Julia, you can add it to a special file called startup.jl. This file is not automatically created, so you'll have to add it yourself to your Julia configuration directory. Any code you add to it will be run by Julia each time it starts up. Let's have some fun and do this using Julia—and practice a bit of what we've learned so far.

First, go into shell mode and run these three commands:

shell> mkdir $(dirname(REPL.find_hist_file()))/../config 
 
shell> cd $(dirname(REPL.find_hist_file()))/../config 
/Users/adrian/.julia/config 
 
shell> touch startup.jl 

Then, in julian mode, execute the following:

julia> write("startup.jl", "println(\"Welcome to Julia!\")") 
28 

What did we just do? In shell mode, we created a new directory, called config, just one folder up from where our history file was. Then we cd into the newly created folder, where we created a new file called startup.jl. Finally, we asked Julia to add the line "println(\"Welcome to Julia!\")" to the startup.jl file. Next time we start the Julia REPL we'll be greeted by this welcome message. Check this out:

REPL hooks

It is also possible to define a function that will be automatically called before starting a REPL session. To achieve this, you need to use the atreplinit(f) function, which registers a one-argument function f to be called before the REPL interface is initialized in interactive sessions. This function should be called from within the startup.jl file.

Let's say that we edit our startup.jl file so that it now looks like this:

println("Welcome to Julia!") 
 
atreplinit() do (f) 
  println("And welcome to you too!") 
end 

Our REPL will now greet us twice:

The atreplinit function can be used in tandem with isinteractive, which returns a Boolean true or false value that tells us whether or not Julia is running an interactive session.

Exiting the REPL

In order to exit the REPL, you can type ^ D (Ctrl + D). However, that will only work if you're at the beginning of the line (when the text buffer is empty). Otherwise just type ^C (Ctrl + C) to first interrupt (or cancel) and clear the line. You can also run exit(), which will stop the execution of the current Julia process.

Note

For the complete list of key bindings at the REPL and how to customise them, you can read the official documentation at https://docs.julialang.org/en/v1.0/stdlib/REPL/#Key-bindings-1