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 in R. My main sell to you is that “R programming” is in your own self-interest, not mine.

Repeat and Extend Your Work

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. Written as a script, you simply swap the data file and rerun it. The same code that summarizes 100 observations summarizes one million. Asking an AI assistant to simply do the analysis may get you different results when you simply want to repeat an analysis. Instead, you can use AI to help you generate and check your reproducible scripts.

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. We test hypotheses by simulating what the data would look like if there were no effect. We also follow good visualization conventions, such as showing 2D data without unnecessary 3D effects. See Tufte (2001) and https://clauswilke.com/dataviz/no-3d.html.

Check and Explain Your Results

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. A spreadsheet can display a plausible number even when the calculation behind it is wrong.

  • 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, understating risk in a portfolio that ultimately lost at least US$6.2 billion (JPMorgan Chase & Co. 2013, 124 and 128).

None of these were hard problems. They were ordinary mistakes that went undetected. Recording and rerunning the steps makes mistakes easier to find. See https://retractionwatch.com/ and https://econjwatch.org/ for more examples of what happens when academics don’t check their work. Search for the “worst Excel errors” and note the frequency they arise from copy/paste via the “point-and-click” approach.

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 carries over to any job where somebody has to defend a number.

Why R and RStudio

We program with R because it is particularly good for both introductory statistics and later use in academia and industry. It is free on any machine, and it stays free after you graduate and after you leave whatever employer paid for your other software.

We will work in R through a second piece of software, RStudio. R performs the analysis while RStudio provides the workspace for writing code, inspecting data, and viewing results. RStudio is a popular choice in academia and business.

Excel is useful for data entry and a quick inspection, while R is stronger for work that must be updated, checked, explained, or scaled. 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

Install in two steps

  1. Install R (see also the R Installation and Administration Manual).
  2. 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

You can use + to add any numbers. 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!
# R ignores any line that starts with #
1+1 # R also ignores anything after # on a line of code
## [1] 2

# R runs each line in turn, top to bottom
2+2
## [1] 4
3+3
## [1] 6

The comments in this chapter say what each line does, because the syntax is new to you. In your own scripts, comments are most useful when they say why a line is there; see Code Conventions for examples.

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

Throughout this textbook, there are special boxes for especially important statistical examples.

ImportantKey Definition

This box contains key definitions. For example, an R script is a sequence of instructions we write in RStudio for a computer to automate statistical analysis.

This box contains need to know examples. For example

Code
2 + 7
## [1] 9

This box contains test yourself examples and questions. For example

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   # <- stores the value 1 in a variable named x
x + 1    # R replaces x with its stored value
## [1] 2
Code
x <- 23 #Another example
x + 1
## [1] 24
Code
y <- x + 1 #Another example
y
## [1] 24

Also note that your variable names do not matter technically, but they should be informative to help avoid common mistakes.

Code
x_plus_1 <- x + 1  #less confusing
y_times_2 <- x + 1 #more confusing

Common Mistakes

You will make many mistakes. Here are some of the most common ones to look out for.

Code
#  Mistake 1: spelling and spacing
X +   1  # notice that R is sensitive to capitalization (x is not X)
## Error:
## ! object 'X' not found
Y < - 43 # notice that < - is not <- 
## Error:
## ! object 'Y' not found
Y + 1    # notice that Y was not actually created above, even if you thought it was
## Error:
## ! object 'Y' not found

# Mistake 2: half-completed code
x + y + 
x_plus_y_plus_z <- x + y + z +
x
## Error:
## ! object 'z' not found
# Seeing '+' in the bottom console? press 'Escape' and try again

Ask your peers or AI to check your code and error messages if you cannot figure out the issue.

Note that there are often many ways to accomplish the same goal

Code
x + 2 + 3
## [1] 28
sum(x,2,3)  # sum() is a built-in function that adds its inputs
## [1] 28

You can always ask R for help

Code
?sum        # put ? before a function name to open its help page

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.

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 numbers (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
x <- 2   # a single number is a scalar
x        # typing an object's name prints its value
## [1] 2

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

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

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

Vectors

Make your first vector The name x_hat will identify sample values throughout the book.

Code
x_hat <- c(0, 1, 3, 10, 6)   # c() combines values into a vector
x_hat
## [1]  0  1  3 10  6
x_hat[2]                     # square brackets extract the 2nd element
## [1] 1

# Arithmetic applies to each entry of x_hat
x_hat + 2
## [1]  2  3  5 12  8
x_hat*2
## [1]  0  2  6 20 12
x_hat^2
## [1]   0   1   9 100  36

Apply mathematical calculations elementwise

Code
x_hat+x_hat
## [1]  0  2  6 20 12
x_hat*x_hat
## [1]   0   1   9 100  36
x_hat^x_hat
## [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
# Two vectors of the same length
x1_hat <- c(1, 4, 9)
x2_hat <- c(3, 0, 2)
# Stack them as rows (cbind() would stack them as columns)
x_mat <- rbind(x1_hat, x2_hat)

x_mat
##        [,1] [,2] [,3]
## x1_hat    1    4    9
## x2_hat    3    0    2
x_mat[2,  ]   # row 2: leave the column slot empty
## [1] 3 0 2
x_mat[ , 2]   # column 2: leave the row slot empty
## x1_hat x2_hat 
##      4      0
x_mat[2, 2]   # one entry: give both row and column
## x2_hat 
##      0

There are elementwise calculations

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

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

1.4 Mathematical Functions

A function is a named recipe that takes input objects, performs a calculation, and returns an output.

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

Code
x_hat
## [1]  0  1  3 10  6
sum(x_hat)   # adds the entries of a vector
## [1] 20
# ?sum       # delete the first # to open the help page

mean(x_hat)
## [1] 4
max(x_hat)
## [1] 10
ImportantKey Definition

An indicator function \(\mathbf{1}(\cdot)\) takes a logical statement and returns \(1\) if the statement is TRUE and \(0\) if it is FALSE.

Summing an indicator counts how many observations satisfy the condition. For example, \(\sum_{i=1}^{n}\mathbf{1}\left(\hat{x}_{i}=x\right)\) counts the number of observations equal to \(x\). In R, 1*(x_hat == 3) computes \(\mathbf{1}(\hat{x}_{i}=3)\) for each entry: the comparison gives TRUE or FALSE, and multiplying by 1 turns these into \(1\) and \(0\).

Code
1*(x_hat == 3)    # 1 if the entry equals 3, 0 otherwise
## [1] 0 0 1 0 0
sum(x_hat == 3)   # how many entries equal 3
## [1] 1
mean(x_hat == 3)  # proportion of entries that equal 3
## [1] 0.2

Sometimes, we will use vectors that are entirely ordered.

Code
x_hat
## [1]  0  1  3 10  6
order(x_hat)
## [1] 1 2 3 5 4
x_hat[order(x_hat)]
## [1]  0  1  3  6 10
sort(x_hat)
## [1]  0  1  3  6 10

We can also make ordered vectors 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

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.

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

Code
p_hat <- c(NA, NA, NA, NA, NA)
for(x in seq(1, 3)){
    p_hat[x] <- mean(x_hat==x)
}
p_hat
## [1] 0.2 0.0 0.2  NA  NA

Applying the same function over and over again

Code
# Example 1: simple division
x_hat <- rep(NA, 3)      # pre-allocate NAs to hold the results
x_hat
## [1] NA NA NA
for(i in seq(1, 3)){     # i takes the values 1, 2, 3 in turn
    x_hat[i] <- i/2      # fill the i-th entry on each pass
}
x_hat                    # now filled in
## [1] 0.5 1.0 1.5


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


#Example 3: recursion
x_hat <- rep(NA, 4)
x_hat[1] <- 1
for(i in seq(2, 4) ){
    x_hat[i] <- x_hat[i-1]^2
}
x_hat
## [1] 1 1 1 1

Creating Functions

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.

Code
add_two <- function(input) {   # input is a placeholder name
    output <- input + 2        # output exists only inside the function
    return(output)             # hand the result back to the caller
}
x_hat <- c(0, 1, 3, 10, 6)
add_two(input=x_hat)           # add_two(x_hat) works the same
## [1]  2  3  5 12  8

Common mistakes:

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

# Double check typos
y_hat  < - add_two(Input=X_hat)

# 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_hat <- c(0, 1, 3, 10, 6)
add_two(x_hat)

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_hat, 3)
## [1]  3  4  6 13  9
add_scalar(x_hat, 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_hat)
## [1]  3  4  6 13  9
add_scalar3(x_hat, 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_hat <- c(0, 1, 3, 10, 6)
my_range(x_hat)
## [1] 10

Logic

Calculations that are either TRUE or FALSE

Code
x_hat <- c(1, 2, 3, NA)   # NA marks a missing value

x_hat == 2                # TRUE or FALSE for each entry
## [1] FALSE  TRUE FALSE    NA
any(x_hat==2)             # TRUE if at least one entry is TRUE
## [1] TRUE
all(x_hat==2)             # TRUE only if every entry is TRUE
## [1] FALSE
2 %in% x_hat              # does 2 appear anywhere in x_hat?
## [1] TRUE
is.na(x_hat)              # flags the missing entries
## [1] FALSE FALSE FALSE  TRUE

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

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

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

Functions for Matrices

You can apply functions to all matrix elements

Code
x1_hat <- c(1, 4, 10)
x2_hat <- c(3, 0, 2)
x_mat <- rbind(x1_hat, x2_hat)
x_mat
##        [,1] [,2] [,3]
## x1_hat    1    4   10
## x2_hat    3    0    2
sum(x_mat)   # adds every entry, not just one row or column
## [1] 20

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

Code
# Row sums
y_row <- apply(x_mat, 1, sum) # the 1 applies sum() to each row
y_row
## x1_hat x2_hat 
##     15      5

#check row sums are correct
sum(x_mat[1, ])
## [1] 15
sum(x_mat[2, ])
## [1] 5
Code
# Column sums
y_col <- apply(x_mat, 2, sum)
y_col
## [1]  4  4 12

#check column sums are correct: DIY

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_hat <- c(2, 5, 8, 3, 7). Without running the code, predict the output of sum(x_hat) / length(x_hat), then verify in R. Next, use sort(x_hat) 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_hat <- 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 and loops. The p_hat loop in the Must Know box computes proportions in loop and applies it to x_hat <- c(0, 1, 3, 10, 6) data for \(x~\text{in}~\{1,2,3\}\).

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.