3 + 5
[1] 8
12 / 7
[1] 1.714286
Simply put, programming allows you to move away from point-and-click activities. They might seem great because they’re intuitive and relatively easy - until you want to redo an analysis after collecting more data. You then need to manually go through the whole process again.
By writing out the different steps of your analysis you’re making all those ‘clicks’ explicit. The added benefit is that it forces you to think more about what steps you need to go through in your analysis, thereby making errors less likely!
This also very much improves the reproducibility of the analysis: after all, running the same code on the same data should also result in the same outcome. This is great when you’re sharing your analysis with colleagues, but also great for your future self. Your brilliant approach might have made sense at the time, but who knows how much you still recall a year later… More and more often funding bodies are (rightfully!) requiring you to include raw data and analysis pipelines when submitting a paper. So, you’ll be ahead of the game.
In this course we’re focusing on generic programming concepts, but we’re illustrating them in two different languages: R and Python.
In both cases we don’t directly type in commands in some kind of terminal window, but instead use an additional bit of software to make our programming experience a bit more user-friendly.
For R, the RStudio software is a very popular choice - and one we’ll be using here. It’s free, open-source and well-supported. What more can you ask for?
In the image above you can see that the window is divided into three main parts, each with various tabs. In clockwise order we have:
In bold we’ve highlighted the tabs we’ll be using most.
In the Console we can directly run code - more on that soon. The Environment shows any information that is stored in R’s memory (empty in the figure above). The Files tab is a mini-browser; Plots shows you any plots that have been created and Help is where you can go for… well, help.
A good way of staying organised is to keep all the files related to a given project together. Using that concept when programming is really helpful, because it makes it easier for the computer to find all the data, scripts and other information related to an analysis.
We often refer to this as the working directory. This simply is the starting point for the computer to look for stuff.
Because you easily accumulate a lot of files when analysing data, it’s good to be organised. During this course we’ll create a project folder called data-analysis
, which we’ll make our working directory.
Within this folder we’ll have sub folders that allow us to further organise our data. We’ll use the following structure:
Folder | Description |
---|---|
data | Contains the data files we’ll use in this course, for example surveys.csv . For your own analysis you might want to consider adding another folder within this to contain the raw data. It’s good practice to always keep an untouched copy of your raw data. This helps with transparency and allows you analyse data differently in the future. Aim to keep your data cleaning and analyses programmatically. |
images | This folder will contain any images you might produce, for example for publications or data exploration. |
scripts | Here we can store any scripts we create. Here it’s also good to be structured and organised, something we cover a bit more in Section 4.4.1. |
… | The opportunities are endless. You can add folders for documents, presentations, etc. How you do things matters less than being consistent! |
All the files in the working directory can be referenced using relative paths. This allows you to move you working directory across your computer - or to other computers - without breaking any of the links within your scripts.
Before we start writing any code we’ll set up our working environment properly. To do this, we’ll create our data-analysis
working directory, with all its sub folders.
The easiest way to set up a working directory in R is to create an R-project. This is simply a folder on your computer with a shortcut in it (ending in .RProj
). When you double-click on the shortcut, it opens RStudio and sets the working directory to that particular folder.
To create an “R Project”:
File
menu, click on New Project
. Choose New Directory
, then New Project
.~/data-analysis
).Create Project
.Open in new session
to ensure RStudio starts afresh.R will show you your current working directory in the Files
pane. Alternatively, you can get it by typing in and running the getwd()
command.
Complete setting up a working directory before proceeding.
The basis of programming is that we create or code instructions for the computer to follow. Next, we tell the computer to follow the instructions by executing or running those instructions.
There are two main ways of interacting with the language: by using the console or by using script files (plain text files that contain your code). The console is the place where commands can be typed and executed immediately by the computer. It is also where the results will be shown for commands that have been executed. However, no record is kept and any information is lost once the session is closed.
Instead, we uses scripts to write all the commands. That way there is a complete record of what we did, and anyone (including our future selves!) can easily replicate the results on their computer.
Console/terminal | Script |
---|---|
runs code directly | in essence, a text file |
interactive | needs to be told to run |
no record | records actions |
difficult to trace progress | transparent workflow |
We can type commands directly in the Console pane and press EnterEnter.
RStudio also allows you to execute commands directly from the script editor by using the ControlControl + EnterEnter shortcut (on Macs, + will work, too). The command on the current line in the script (indicated by the cursor) or all of the commands in the currently selected text will be sent to the console and executed when you press ControlControl + EnterEnter. You can find other keyboard shortcuts in this RStudio cheatsheet about the RStudio IDE (PDF).
If R is ready to accept commands, the R console shows a >
prompt. If it receives a command (by typing, copy-pasting or sent from the script editor using ControlControl + EnterEnter), R will try to execute it, and when ready, will show the results and come back with a new >
prompt to wait for new commands.
If R is still waiting for you to enter more data because it isn’t complete yet, the console will show a +
prompt. It means that you haven’t finished entering a complete command. This is because you have not ‘closed’ a parenthesis or quotation, i.e. you don’t have the same number of left-parentheses as right-parentheses, or the same number of opening and closing quotation marks. When this happens, and you thought you finished typing your command, click inside the console window and press EscapeEscape. This will cancel the incomplete command and return you to the >
prompt.
The simplest way of using a programming language is to use it interactively. We can do this by typing directly into the console / terminal.
Running code like this directly in the console is generally not a good idea, because then we can’t keep track of what we are doing. So, we first need to create a script to save our code in. Then, we can then play around. Let’s focus on that next.
As your analysis grows, so does your code. So,often we want to split analyses into multiple scripts, for example:
01_preprocessing
may contain data cleaning steps02_exploration
may contain exploratory plots of your data03_analysis
could contain (statistical) analyses of your data04_figures
could contain code for figures, ready for publicationEach of these files could be hundreds of lines long. So, keeping track of your code makes sense. We can do that with code headings, which use the # heading ----
syntax. You can even add different heading levels, by increasing the number of #
at the start.
This creates a little table of contents in the bottom-left corner of the script pane:
Functions are “canned scripts” that automate more complicated sets of commands including operations assignments, etc. Many functions are predefined, or can be made available by importing packages (more on that later). A function usually takes one or more inputs called arguments. Functions often (but not always) return a value. A typical example would be the function sqrt()
. The input (the argument) must be a number, and the return value (in fact, the output) is the square root of that number.
Here, the value 9
is given to the sqrt()
function. This function calculates the square root, and returns the value. This function is very simple, because it takes just one argument.
The return ‘value’ of a function need not be numerical (like that of sqrt()
), and it also does not need to be a single item: it can be a set of things, or even a data set. We’ll see that when we read data files.
Arguments allow you to control the behaviour of a function. They can be anything, not only numbers or file names. Exactly what each argument means differs per function and can be looked up in the documentation. Some functions take arguments which may either be specified by the user, or, if left out, take on a default value: these are called options.
Options are typically used to alter the way the function operates, such as if it should ignore missing values, or what symbol to use in a plot. However, if you want something specific, you can specify a value of your choice which will be used instead of the default.
Let’s try a function that can take multiple arguments: round()
.
Here, we’ve called round()
with just one argument, 3.14159
, and it has returned the value 3
. That’s because the default is to round to the nearest whole number. If we want more digits we can see how to do that by getting information about the round()
function.
We can use args(round)
to find what arguments it takes, or look at the help for this function using ?round
.
We see that if we want a different number of digits, we can type digits = 2
or however many we want. For example:
If you provide the arguments in the exact same order as they are defined you don’t have to name them:
And if you do name the arguments, you can switch their order:
We can use help(round)
to find what arguments it takes.
We see that if we want a different number of digits, we can type ndigits = 2
or however many we want. For example:
If you provide the arguments in the exact same order as they are defined you don’t have to name them:
Python still expects the arguments in the correct order, so this gives an error:
It’s good practice be explicit about the names of the arguments. That way you can avoid confusion later on when looking back at your code or when sharing your code.
LO: adding functionality (installing + loading packages) LO: For Python: requires numpy
for next section
Level:
Create a working directory called data-analysis
. When you’ve done this, add the following sub folders:
data
scripts
images
Note: programming languages are case-sensitive, so data
is not treated the same way as Data
.
Level:
Create a script and save it as session_01
in the scripts
folder within your working directory.
Remember, you will need to add an extension to the file. This is .R
for R scripts or .py
for Python ones.
4.4.2 Comments in code
It’s always a good idea to add explanations to your code. We can do that with the hash tag
#
symbol, for example:It’s always a good idea to add lots of comments to your code. What makes sense to you in that moment, might not a week later. Similarly, when sharing code with colleagues and collaborators, it’s always good to be as clear as possible.
Please complete the exercises to create a script and trial running code.