Code
sudo dnf install 'dnf-command(copr)'
sudo dnf copr enable iucar/RStudio
sudo dnf install RStudio-desktopThis 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.
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.
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.
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
sudo dnf install 'dnf-command(copr)'
sudo dnf copr enable iucar/RStudio
sudo dnf install RStudio-desktopMake sure you have the latest version of R and RStudio for class. If not, then reinstall.
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+1The 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:
1 + 1
## [1] 2In this chapter, code annotations will help you
1+1
## [1] 2+ 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.
In later chapters, there are also special boxes for especially important statistical examples.
To understand each chunk of code:
E.g., Use the following code to see if the empty space matters
(2 + 7)^3 / 10
## [1] 72.9You can create “variables” that store values. For example,
x <- 1
x + 1
## [1] 21 to a variable named x using the <- operator.
x in a calculation; R substitutes its stored value.
x <- 23 #Another example
x + 1
## [1] 24y <- x + 1 #Another example
y
## [1] 24Your variables must be defined in order to use them. Otherwise you get an error. For example,
X + 1 # notice that R is sensitive to capitalization
## Error:
## ! object 'X' not foundDesktop/ECON_XXXX/CodeAs 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
sum(x, 2)
?sumsum() is a built-in function; here it returns x + 2.
? to open its help page.
We write script in the top left so that we can edit common mistakes.
# 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 againYour variable names do not matter technically, but they should be informative to help avoid common mistakes.
Before you can analyze data in R, you need to know what shapes the data can take.
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.
Make your first scalar
xs <- 2
xs
## [1] 2xs; this is a scalar.
Perform simple calculations and see how R is doing the math for you
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] NANow change xs, predict what will happen, then re-run the code.
Make your first vector
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 36c().
[ ] to extract the 2nd element.
x.
Apply mathematical calculations elementwise
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+04In R, scalars are treated as a vector with one element.
c(1)
## [1] 1Matrices are also common objects
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
## 0rbind() (use cbind() to stack as columns).
There are elementwise calculations
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 4Calculations you find yourself doing again and again deserve a single name and a single place to live.
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.
Functions are applied to objects
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 8input is a placeholder name.
output exists only inside the function.
add_two(x) works the same as naming the argument.
Common mistakes:
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.
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 10Perhaps the most common function we will use is summation. You can see exactly what a function does with ?.
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] 19sum() adds the entries of a vector.
sum() adds every entry, not just one row or column.
sum.
You can apply functions to each row or column of a matrix
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: DIYSometimes, we will use vectors that are entirely ordered. We make them with functions.
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 10Sometimes the same calculation must be performed on many inputs, with each result depending on the previous one or stored alongside the others.
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
# 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 1NAs to hold the results.
i taking the values 1, 2, 3 in turn.
i-th slot of x.
Calculations that are either TRUE or FALSE
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 TRUENA).
== tests each entry for equality; returns a vector of TRUE/FALSE.
any() returns TRUE if at least one entry of its input is TRUE.
all() returns TRUE only if every entry is TRUE.
%in% checks whether the left value appears anywhere on the right.
is.na() flags the missing entries.
The & and | commands are logical calculations that compare vectors to the left and right.
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 NAAn 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.
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.
Explain the difference between replicable and reproducible research. Why is programming your analysis in R better for reproducibility than a point-and-click approach?
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.
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.
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.
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.↩︎
Comments.
You should add comments to your codes, and you do this with hashtags. For example
Code
#is a comment; R ignores it.#on a line of code is also a comment.Now try some other mathematical operations
Code
Now try some more complex examples
Code