1  First Steps


This chapter walks through the basics of working in R: installing the software, writing your first commands, saving them in scripts, and building up the objects you will use throughout the book. We start with simple arithmetic, then move to vectors and matrices, write your first function, and finish with loops and logical comparisons. The pace is gentle on purpose so that the rest of the book can move quickly.

1.1 Why Program?

You will program your statistical analysis, and we will cover some of the basics of how to do this in R. There are five practical benefits, roughly in the order you will notice them.

Automation. Next quarter’s sales report, or the same table with one more year of data, is the same analysis run again. Done by hand, it costs another afternoon. Done by AI, you may use a different formula. Written as a script, you swap the data file and rerun it.

Reproducibility. Every calculation is recorded, rather than hidden in a sequence of clicks that nobody wrote down. This is what lets you, a colleague, or a boss find the exact step where a number went wrong.

Scale. The same code that summarizes 100 observations summarizes one million.

Better methods. Most of this book is spent on methods that don’t fit into a cell formula: we build confidence intervals by resampling the data thousands of times, and we test hypotheses by simulating what the data would look like if there were no effect.

Transferable thinking. The underlying skill is turning a vague question, such as “are our west-coast customers different?”, into a sequence of explicit and checkable steps. That skill outlives R and carries over to any job where somebody has to defend a number.

Errors Stay Hidden Until Someone Reruns.

A spreadsheet shows you numbers, not the steps that produced them. A mistake in the steps therefore looks exactly like a correct result. Ask AI to find the “worst Excel errors” and note the frequency they arise from copy/paste via the “point-and-click” approach.

  • Reinhart and Rogoff’s widely cited finding on public debt and growth rested in part on a spreadsheet average that left out five countries. The error surfaced only when someone else obtained the file and recomputed the numbers (Herndon et al. 2014).
  • JPMorgan’s 2012 trading loss involved a risk model that ran through a series of Excel spreadsheets, with data copied by hand from one to the next. One formula divided by a sum where it should have divided by an average, which muted the estimated volatility by about half (JPMorgan Chase & Co. 2013, 124 and 128).

None of these were hard problems. They were ordinary mistakes that nobody could see. See https://retractionwatch.com/ and https://econjwatch.org/ for an ongoing account of what happens when academics don’t.

Why R and RStudio.

We program with R because it is good for complex stats, concise figures, and coherent organization. R is built and developed by applied statisticians for statistics, and used by many in academia and industry. It is also free on any machine, and it stays free after you graduate and after you leave whatever employer paid for your other software.

We will also use a second pieces of software, RStudio, which is the only one you will interface with. R performs the analysis while RStudio provides the workspace for writing code, inspecting data, and viewing results.1 Rstudio is popular choice in academia and business.

So my main sell to you is that “programming in R” is in your own self-interest, not mine. Excel is useful for data entry and a quick inspection, while R is stronger for work that must be updated, checked, explained, or scaled. Checking and explaining our work is especially important to incorporating AI into our workflow. Think about what your future employers want and do some of your own research to best understand how much to invest.

1.2 First Steps

Installation.

First Install R (see also the R Installation and Administration Manual). Then Install RStudio.

For Fedora (linux) users, note that you need to first enable the repo and then install

Code
sudo dnf install 'dnf-command(copr)'
sudo dnf copr enable iucar/RStudio
sudo dnf install RStudio-desktop

Make sure you have the latest version of R and RStudio for class. If not, then reinstall.

Interfacing with RStudio.

RStudio is perhaps the easiest to get going with. (There are other GUI’s.)

In RStudio, there are 4 panes. If you do not see 4, click “file > new file > R script” on the top left of the toolbar.

The top left pane is where you write your code. For example, type

1+1

The pane below is where your code is executed. Keep your mouse on the same line as your code, and then click “Run”. You should see

> 1+1
[1] 2

If you click “Run” again, you should see that same output printed again.

As we proceed, you can see both my source code and output like this:

Code
1 + 1
## [1] 2

In this chapter, code annotations will help you

Code
1+1
## [1] 2
1
You can use + to add any numbers. E.g., 1+2

Try \(2+2\) and \(3+3\). First execute each one-at-a-time. Then highlight/run them both together.

Comments.

You should add comments to your codes, and you do this with hashtags. For example

Code
# This is my first comment!
1+1 # The simplest calculation I could think of

# Other examples of running code
2+2
3+3
## [1] 2
## [1] 4
## [1] 6
1
A line starting with # is a comment; R ignores it.
2
Anything after # on a line of code is also a comment.
3
Each line is executed in turn when you run the chunk.

Now try some other mathematical operations

Code
2-3 #subtraction
## [1] -1
2*3 #multiplication
## [1] 6
2/3 #division
## [1] 0.6666667
2^3 #powers
## [1] 8

Now try some more complex examples

Code
# Example 1
5+2/10
## [1] 5.2
(5+2)/10 # notice the difference
## [1] 0.7

# Example 2
2^3/10 # notice the differences
## [1] 0.8
2/10^3
## [1] 0.002
(2/10)^3
## [1] 0.008

Reading This Textbook.

In later chapters, there are also special boxes for especially important statistical examples.

This box contains need to know examples. Such as

Code
2 + 7
## [1] 9

This box contains test yourself examples and questions. Such as

Code
(2 + 7)^3 / 10
## [1] 72.9

To understand each chunk of code:

  • Copy/paste it into your RStudio
  • Run it
  • Predict what happens if changed
  • Change it
  • Break it
  • Fix it

E.g., Use the following code to see if the empty space matters

Code
(2 + 7)^3 / 10
## [1] 72.9

Assignment.

You can create “variables” that store values. For example,

Code
x <- 1
x + 1
## [1] 2
1
Assign the value 1 to a variable named x using the <- operator.
2
Use x in a calculation; R substitutes its stored value.
Code
x <- 23 #Another example
x + 1
## [1] 24
Code
y <- x + 1 #Another example
y
## [1] 24

Your variables must be defined in order to use them. Otherwise you get an error. For example,

Code
X +   1 # notice that R is sensitive to capitalization 
## Error:
## ! object 'X' not found

Scripting.

  • Create a folder on your computer to save your scripts. For example: Desktop/ECON_XXXX/Code
  • Save your work as Script_01.R in your folder
  • Close RStudio
  • Open your script and re-run it

As you work through the material, make sure to both execute and save your scripts. Add lots of commentary to your scripts. Name your scripts systematically.

There are often many ways to accomplish the same goal. You first scripts will be very basic and rough, but you can edit them later based on what you learn. And you can always ask R for help

Code
sum(x, 2)
?sum
1
sum() is a built-in function; here it returns x + 2.
2
Prefix any function name with ? to open its help page.

We write script in the top left so that we can edit common mistakes.

Code
# Mistake 1: using undefined objects
Y

#  Mistake 2: spelling and spacing
Y < - 43
Y_plus_z <- Y + z

# Mistake 3: half-completed code
x + y + 
x_plus_y_plus_z <- x + y + z
# Seeing '+' in the bottom console?
# press 'Escape' and try again

Your variable names do not matter technically, but they should be informative to help avoid common mistakes.

1.3 Mathematical Objects

Before you can analyze data in R, you need to know what shapes the data can take.

ImportantKey Definition

A scalar is a single number. A vector is an ordered list of numbers of the same type. A matrix is a rectangular grid of numbers with rows and columns, where every entry has the same type.

Each shape suits a different kind of dataset: scalars hold single nu

mbers (e.g., you total income for the year), vectors hold one variable across observations (e.g., the income of each person in class), and matrices hold two or more variables across observations (e.g., the income and education level of every person in class). Vectors are probably your most common object in R, but we will start with scalars.

Scalars.

Make your first scalar

Code
xs <- 2
xs
## [1] 2
1
Assign a single number to xs; this is a scalar.
2
Typing the object’s name at the console prints its value.

Perform simple calculations and see how R is doing the math for you

Code
xs + 2
## [1] 4
xs*2 # Perform and print a simple calculation
## [1] 4
(xs+1)^2 # Perform and print a simple calculation
## [1] 9
xs + NA # often used for missing values
## [1] NA

Now change xs, predict what will happen, then re-run the code.

Vectors.

Make your first vector

Code
x <- c(0, 1, 3, 10, 6)
x
x[2]
x + 2
x*2
x^2
## [1]  0  1  3 10  6
## [1] 1
## [1]  2  3  5 12  8
## [1]  0  2  6 20 12
## [1]   0   1   9 100  36
1
Combine values into a vector with c().
2
Print the whole vector.
3
Use square brackets [ ] to extract the 2nd element.
4
Arithmetic is applied elementwise to each entry of x.

Apply mathematical calculations elementwise

Code
x+x
## [1]  0  2  6 20 12
x*x
## [1]   0   1   9 100  36
x^x
## [1] 1.0000e+00 1.0000e+00 2.7000e+01 1.0000e+10 4.6656e+04

In R, scalars are treated as a vector with one element.

Code
c(1)
## [1] 1

Matrices.

Matrices are also common objects

Code
x1 <- c(1, 4, 9)
x2 <- c(3, 0, 2)
x_mat <- rbind(x1, x2)

x_mat
x_mat[2,  ]
x_mat[ , 2]
x_mat[2, 2]
##    [,1] [,2] [,3]
## x1    1    4    9
## x2    3    0    2
## [1] 3 0 2
## x1 x2 
##  4  0 
## x2 
##  0
1
Create two vectors of the same length.
2
Stack them as rows into a matrix with rbind() (use cbind() to stack as columns).
3
Print the full matrix.
4
Extract row 2: leave the column slot empty.
5
Extract column 2: leave the row slot empty.
6
Extract a single element by giving both row and column.

There are elementwise calculations

Code
x_mat+2
##    [,1] [,2] [,3]
## x1    3    6   11
## x2    5    2    4
x_mat*2
##    [,1] [,2] [,3]
## x1    2    8   18
## x2    6    0    4
x_mat^2
##    [,1] [,2] [,3]
## x1    1   16   81
## x2    9    0    4

x_mat + x_mat
##    [,1] [,2] [,3]
## x1    2    8   18
## x2    6    0    4
x_mat * x_mat
##    [,1] [,2] [,3]
## x1    1   16   81
## x2    9    0    4

1.4 Mathematical Functions

Functions.

Calculations you find yourself doing again and again deserve a single name and a single place to live.

ImportantKey Definition

A function is a named recipe that takes input values, performs a calculation, and returns an output. The input names are called arguments and the returned value is the function’s output.

Functions are useful for any calculation you intend to reuse: define the recipe once, and a single edit to the recipe propagates to every call. Naming the calculation also makes scripts easier to read, since a well-chosen function name documents what the code is doing.

Creating Simple Functions.

Functions are applied to objects

Code
add_two <- function(input) {
    output <- input + 2
    return(output)
}
x <- c(0, 1, 3, 10, 6)
add_two(input=x)
## [1]  2  3  5 12  8
1
Declare a function with one argument; input is a placeholder name.
2
Compute the result; output exists only inside the function.
3
Hand the result back to whoever called the function.
4
Build a vector to feed in.
5
Call the function; add_two(x) works the same as naming the argument.

Common mistakes:

Code
print(input)
print(output)
# These are not available globally, only locally (inside of the function)

# Double check typos
x  < - add_two(Input=X) 

# Seeing '+' in the bottom console
# often means you forgot to close the function with '}' 
# click the bottom left panel, press 'Escape', and try again in the top left panel
add_two <- function(input_vector) { 
    output_vector <- input_vector + 2 
    return(output_vector)
x <- c(0, 1, 3, 10, 6)
add_two(x)

There are many different functions. Many of which functions have defaults.

Code
add_scalar <- function(input_vector1, input_scalar2) {
    output_vector <- input_vector1 + input_scalar2
    return(output_vector)
}
add_scalar(x, 3)
## [1]  3  4  6 13  9
add_scalar(x, 4)
## [1]  4  5  7 14 10

add_scalar3 <- function(input_vector1, input_scalar2=3) {
    output_vector <- input_vector1 + input_scalar2
    return(output_vector)
}
add_scalar3(x)
## [1]  3  4  6 13  9
add_scalar3(x, 4)
## [1]  4  5  7 14 10

A function lets you name a calculation once and then reuse it. Here is one that computes the range of a vector: the largest value minus the smallest.

Code
my_range <- function(input) {
    output <- max(input) - min(input)
    return(output)
}
x <- c(0, 1, 3, 10, 6)
my_range(x)
## [1] 10

Common Functions.

Perhaps the most common function we will use is summation. You can see exactly what a function does with ?.

Code
x1 <- c(1, 4, 9)
x1
sum(x1)

x2 <- c(3, 0, 2)
x_mat <- rbind(x1, x2)
x_mat
sum(x_mat)

# ?sum
## [1] 1 4 9
## [1] 14
##    [,1] [,2] [,3]
## x1    1    4    9
## x2    3    0    2
## [1] 19
1
A vector with three entries.
2
sum() adds the entries of a vector.
3
Applied to a matrix, sum() adds every entry, not just one row or column.
4
Uncomment to open the help page for sum.

You can apply functions to each row or column of a matrix

Code
x_mat
##    [,1] [,2] [,3]
## x1    1    4    9
## x2    3    0    2

# Row sums
y_row <- apply(x_mat, 1, sum)
y_row
## x1 x2 
## 14  5

#check row sums are correct
x_row1 <- x_mat[1, ]
sum(x_row1)
## [1] 14
x_row2 <- x_mat[2, ]
sum(x_row2)
## [1] 5

# Column sums
y_col <- apply(x_mat, 2, sum)
y_col
## [1]  4  4 11

#check column sums are correct: DIY

Sometimes, we will use vectors that are entirely ordered. We make them with functions.

Code
seq(1, 7, by=1) #same as 1:7
## [1] 1 2 3 4 5 6 7
seq(1, 7, by=0.5)
##  [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0

# Ordering data
sort(x)
## [1]  0  1  3  6 10
x[order(x)]
## [1]  0  1  3  6 10

Loops.

Sometimes the same calculation must be performed on many inputs, with each result depending on the previous one or stored alongside the others.

ImportantKey Definition

A loop repeats the same block of code several times. A for loop runs the block once for each value of an index variable. We typically pre-allocate a vector to hold the results, then fill one entry per pass.

Loops are useful when each iteration depends on the previous one (recursion) or when you want to perform a sequence of operations whose order matters; for purely elementwise calculations, vectorized arithmetic on a single vector is usually faster and cleaner.

Applying the same function over and over again

Code
# Example 1: simple division
x <- rep(NA, 3)
for(i in seq(1, 3)){
    x[i] <- i/2
}
x
# Compare

# Example 2: using existing data
x <- c(1, 3, 9, 2)
y <- rep(NA, length(x))
for(i in seq(1, 4) ){
    y[i] <- x[i] + 1
}
y


#Example 3: recursion
x <- rep(NA, 4)
x[1] <- 1
for(i in seq(2, 4) ){
    x[i] <- x[i-1]^2
}
x
## [1] 0.5 1.0 1.5
## [1]  2  4 10  3
## [1] 1 1 1 1
1
Pre-allocate a length-3 vector of NAs to hold the results.
2
Loop with i taking the values 1, 2, 3 in turn.
3
On each pass, assign a value into the i-th slot of x.
4
Print the filled-in vector.

Predict the value of y after this loop runs, then check your answer in R.

Code
y <- rep(NA, 4)
y[1] <- 2
for(i in seq(2, 4)){
    y[i] <- y[i-1] + 3
}
y
## [1]  2  5  8 11

Logic.

Calculations that are either TRUE or FALSE

Code
x <- c(1, 2, 3, NA)

x == 2
any(x==2)
all(x==2)
2 %in% x
is.na(x)
## [1] FALSE  TRUE FALSE    NA
## [1] TRUE
## [1] FALSE
## [1] TRUE
## [1] FALSE FALSE FALSE  TRUE
1
A vector with a missing value (NA).
2
== tests each entry for equality; returns a vector of TRUE/FALSE.
3
any() returns TRUE if at least one entry of its input is TRUE.
4
all() returns TRUE only if every entry is TRUE.
5
%in% checks whether the left value appears anywhere on the right.
6
is.na() flags the missing entries.

The & and | commands are logical calculations that compare vectors to the left and right.

Code
x < 2
## [1]  TRUE FALSE FALSE    NA
x >= 1
## [1] TRUE TRUE TRUE   NA
(x >= 1) & (x < 2)
## [1]  TRUE FALSE FALSE    NA
(x >= 1) | (x < 2)
## [1] TRUE TRUE TRUE   NA

1.5 Working with AI

An AI assistant is a normal part of writing code now, and this book suggests one order for using one: you attempt the task first, and the assistant then evaluates what you produced. That order is what keeps you able to tell whether the output is right, which is most of what this book is about. Exercise 1 of every chapter, including this one, walks a script you already wrote through an eight-step review.

The full workflow, along with the prompts, the notes on what to upload, and a worked example of catching an assistant in a confident mistake, is in Working with AI.

1.6 Exercises

  1. Comment the script you wrote for this chapter, then restart R and check that it runs from a clean session, then check the script with AI as explained in Working with AI. Write three sentences from memory on the main statistical idea of this chapter, and ask the assistant what is wrong, vague, or missing. Finish with your own questions about whatever you found hardest.

  2. Explain the difference between replicable and reproducible research. Why is programming your analysis in R better for reproducibility than a point-and-click approach?

  3. Let x <- c(2, 5, 8, 3, 7). Without running the code, predict the output of sum(x) / length(x), then verify in R. Next, use sort(x) and extract the second element of the sorted vector with bracket indexing.

  4. Write a function called square_plus that takes a vector and a scalar as inputs, squares each element of the vector, and then adds the scalar. Test it on x <- c(1, 4, 9) with a scalar of 5. Confirm your result by computing the answer manually.

Further Reading.

Recall

This chapter introduced the R environment, the three basic objects (scalars, vectors, matrices), and the tools to manipulate them: functions, for loops, and logical comparisons. The my_range function in the Must Know box compressed the function pattern into four lines (take a vector input, compute max(input) - min(input), return the result), and applying it to x <- c(0, 1, 3, 10, 6) returned \(10\). In the next chapter we use these tools to read real datasets into R and to visualize the distribution of a single variable.

Herndon, Thomas, Michael Ash, and Robert Pollin. 2014. “Does High Public Debt Consistently Stifle Economic Growth? A Critique of Reinhart and Rogoff.” Cambridge Journal of Economics 38 (2): 257–79. https://doi.org/10.1093/cje/bet075.
JPMorgan Chase & Co. 2013. Report of JPMorgan Chase & Co. Management Task Force Regarding 2012 CIO Losses. Reproduced in S. Hrg. 113-96, U.S. Senate Permanent Subcommittee on Investigations. https://www.govinfo.gov/content/pkg/CHRG-113shrg80222/pdf/CHRG-113shrg80222.pdf.
Tufte, Edward. 2001. The Visual Display of Quantitative Information. 2nd ed. Graphics Press. https://www.google.de/books/edition/The_Visual_Display_of_Quantitative_Infor/qmjNngEACAAJ.

  1. Later, in Data Analysis we will also work with Quarto, so the text, code, and figures of a report can live in one file that rebuilds itself when the data change.↩︎