
1 Getting Started with Data in R
- Distinguish between R (the language) and RStudio (the environment for using it)
- Install and load R packages from CRAN
- Explore a data frame using functions like
glimpse()andView() - Identify whether a variable is categorical or quantitative
Before we can start exploring data in R, there are some key concepts to understand first:
- What are R and RStudio?
- How do I code in R?
- What are R packages?
We’ll introduce these concepts in the upcoming Section 1.1–Section 1.3. If you are already somewhat familiar with these concepts, feel free to skip to Section 1.4 where we’ll introduce our first dataset: all domestic flights departing one of the three main New York City (NYC) airports in 2023. We will explore this dataset in depth for much of the rest of this book.
1.1 What are R and RStudio?
Throughout this book, we will assume that you are using R via RStudio. First time users often confuse the two. At its simplest, R is like a car’s engine while RStudio is like a car’s dashboard as illustrated in Figure 1.1.
More precisely, R is a programming language that runs computations, whereas RStudio is an integrated development environment (IDE) that provides an interface by adding many convenient features and tools. So just as the way of having access to a speedometer, rear-view mirrors, and a navigation system makes driving much easier, using RStudio’s interface makes using R much easier as well.
1.1.1 Installing R and RStudio
Note about RStudio Server or Posit (formerly RStudio) Cloud: If your instructor has provided you with a link and access to RStudio Server or Posit Cloud, then you can skip this section. We do recommend after a few months of working on RStudio Server/Posit Cloud that you return to these instructions to install this software on your own computer though.
You will first need to download and install both R and RStudio (Desktop version) on your computer. It is important that you install R first and then install RStudio.
-
You must do this first: Download and install R by going to https://cloud.r-project.org/.
- If you are a Windows user: Click on “Download R for Windows,” then click on “base,” then click on the Download link.
- If you are macOS user: Click on “Download R for macOS,” then under “Latest release:” click on R-X.X.X.pkg, where R-X.X.X is the version number. For example, the latest version of R as of December 4, 2024 was R-4.4.2.
- If you are a Linux user: Click on “Download R for Linux” and choose your distribution for more information on installing R for your setup.
-
You must do this second: Download and install RStudio at https://posit.co/download/rstudio-desktop/.
- Scroll down to “All Installers and Tarballs” near the bottom of the page.
- Click on the download link corresponding to your computer’s operating system.
1.1.2 Using R via RStudio
Recall our car analogy from earlier. Much as we don’t drive a car by interacting directly with the engine but rather by interacting with elements on the car’s dashboard, we won’t be using R directly but rather we will use RStudio’s interface. After you install R and RStudio on your computer, you’ll have two new programs (also called applications) you can open. We’ll always work in RStudio and not in the R application. Figure 1.2 shows what icon you should be clicking on your computer.
After you open RStudio, you should see something similar to Figure 1.3. (Note that slight differences might exist if the RStudio interface is updated to not be this by default.)
Note the three panes which are three panels dividing the screen: the console pane, the files pane, and the environment pane. Over the course of this chapter, you’ll come to learn what purpose each of these panes serves.
1.2 How do I code in R?
Now that you’re set up with R and RStudio, you are probably asking yourself, “OK. Now how do I use R?”. The first thing to note is that unlike other statistical software programs like Excel, SPSS, or Minitab that provide point-and-click interfaces, R is an interpreted language. This means you have to type in commands written in R code. In other words, you have to code/program in R. Note that we’ll use the terms “coding” and “programming” interchangeably in this book.
While it is not required to be a seasoned coder/computer programmer to use R, there is still a set of basic programming concepts that new R users need to understand. Consequently, while this book is not a book on programming, you will still learn just enough of these basic programming concepts needed to explore and analyze data effectively.
1.2.1 Basic programming concepts and terminology
We now introduce some basic programming concepts and terminology. Instead of asking you to memorize all these concepts and terminology right now, we’ll guide you so that you’ll “learn by doing.” To help you learn, we will always use a different font to distinguish regular text from computer_code. The best way to master these topics is, in our opinions, through deliberate practice with R and lots of repetition.
- Basics:
- Console pane: where you enter in commands.
- Running code: the act of telling R to perform an act by giving it commands in the console.
- Objects: where values are saved in R. We’ll show you how to assign values to objects and how to display the contents of objects.
-
Data types: integers, doubles/numerics, logicals, and characters. Integers are values like -1, 0, 2, 4092. Doubles or numerics are a larger set of values containing both the integers but also fractions and decimal values like -24.932 and 0.8. Logicals are either
TRUEorFALSEwhile characters are text such as “cabbage,” “Hamilton,” “The Wire is the greatest TV show ever,” and “This ramen is delicious.” Note that characters are often denoted with the quotation marks around them.
-
Vectors: a series of values. These are created using the
c()function, wherec()stands for “combine” or “concatenate.” For example,c(6, 11, 13, 31, 90, 92)creates a six element series of positive integer values . - Factors: categorical data are commonly represented in R as factors. Categorical data can also be represented as strings. We’ll study this difference as we progress through the book.
- Data frames: rectangular spreadsheets. They are representations of datasets in R where the rows correspond to observations and the columns correspond to variables that describe the observations. We’ll cover data frames later in Section 1.4.
-
Conditionals:
- Testing for equality in R using
==(and not=, which is typically used for assignment). For example,2 + 1 == 3compares2 + 1to3and is correct R code, while2 + 1 = 3will return an error. - Boolean algebra:
TRUE/FALSEstatements and mathematical operators such as<(less than),<=(less than or equal), and!=(not equal to). For example,4 + 2 >= 3will returnTRUE, but3 + 5 <= 1will returnFALSE. - Logical operators:
&representing “and” as well as|representing “or.” For example,(2 + 1 == 3) & (2 + 1 == 4)returnsFALSEsince both clauses are notTRUE(only the first clause isTRUE). On the other hand,(2 + 1 == 3) | (2 + 1 == 4)returnsTRUEsince at least one of the two clauses isTRUE.
- Testing for equality in R using
-
Functions, also called commands: Functions perform tasks in R. They take in inputs called arguments and return outputs. You can either manually specify a function’s arguments or use the function’s default values.
- For example, the function
seq()in R generates a sequence of numbers. If you just runseq()it will return the value 1. That doesn’t seem very useful! This is because the default arguments are set asseq(from = 1, to = 1). Thus, if you don’t pass in different values forfromandtoto change this behavior, R just assumes all you want is the number 1. You can change the argument values by updating the values after the=sign. If we try outseq(from = 2, to = 5)we get the result2 3 4 5that we might expect. - We’ll work with functions a lot throughout this book and you’ll get lots of practice in understanding their behaviors. To further assist you in understanding when a function is mentioned in the book, we’ll also include the
()after them as we did withseq()above.
- For example, the function
This list is by no means an exhaustive list of all the programming concepts and terminology needed to become a savvy R user; such a list would be so large it wouldn’t be very useful, especially for novices. Rather, we feel this is a minimally viable list of programming concepts and terminology you need to know before getting started. We feel that you can learn the rest as you go. Remember that your mastery of all of these concepts and terminology will build as you practice more and more.
1.2.2 Errors, warnings, and messages
One thing that intimidates new R and RStudio users is how it reports errors, warnings, and messages. R reports errors, warnings, and messages in a glaring red font, which makes it seem like it is scolding you. However, seeing red text in the console is not always bad.
R will show red text in the console pane in three different situations:
-
Errors: when the red text is a legitimate error, it will be prefaced with “Error in…” and will try to explain what went wrong. Generally when there’s an error, the code will not run. For example, we’ll see in Section 1.3.3 if you see
Error in ggplot(...) : could not find function "ggplot", it means that theggplot()function is not accessible because the package that contains the function (ggplot2) was not loaded withlibrary(ggplot2). Thus you cannot use theggplot()function without theggplot2package being loaded first. -
Warnings: when the red text is a warning, it will be prefaced with “Warning:” and R will try to explain why there’s a warning. Generally your code will still work, but with some caveats. For example, you will see in Chapter 2 if you create a scatterplot based on a dataset where two of the rows of data have missing entries that would be needed to create points in the scatterplot, you will see this warning:
Warning: Removed 2 rows containing missing values (geom_point). R will still produce the scatterplot with all the remaining non-missing values, but it is warning you that two of the points aren’t there. -
Messages: when the red text doesn’t start with either “Error” or “Warning,” it’s just a friendly message. You’ll see these messages when you load R packages in the upcoming Section 1.3.2 or when you read data saved in spreadsheet files with the
read_csv()function as you’ll see in Chapter 4. These are helpful diagnostic messages and they don’t stop your code from working. Additionally, you’ll see these messages when you install packages too usinginstall.packages()as discussed in Section 1.3.1.
Remember, when you see red text in the console, don’t panic. It doesn’t necessarily mean anything is wrong. Rather:
- If the text starts with “Error,” figure out what’s causing it. Think of errors as a red traffic light: something is wrong!
- If the text starts with “Warning,” figure out if it’s something to worry about. For instance, if you get a warning about missing values in a scatterplot and you know there are missing values, you’re fine. If that’s surprising, look at your data and see what’s missing. Think of warnings as a yellow traffic light: everything is working fine, but watch out/pay attention.
- Otherwise, the text is just a message. Read it, wave back at R, and thank it for talking to you. Think of messages as a green traffic light: everything is working fine and keep on going!
1.2.3 Tips on learning to code
Learning to code/program is quite similar to learning a foreign language. It can be daunting and frustrating at first. Such frustrations are common and it is normal to feel discouraged as you learn. However, just as with learning a foreign language, if you put in the effort and are not afraid to make mistakes, anybody can learn and improve.
Here are a few useful tips to keep in mind as you learn to program:
- Remember that computers are not actually that smart: You may think your computer or smartphone is “smart,” but really people spent a lot of time and energy designing them to appear “smart.” In reality, you have to tell a computer everything it needs to do. Furthermore, the instructions you give your computer can’t have any mistakes in them, nor can they be ambiguous in any way.
- Take the “copy, paste, and tweak” approach: Especially when you learn your first programming language or you need to understand particularly complicated code, it is often much easier to take existing code that you know works and modify it to suit your ends. This is as opposed to trying to type out the code from scratch. We call this the “copy, paste, and tweak” approach. So early on, we suggest not trying to write code from memory, but rather take existing examples we have provided you, then copy, paste, and tweak them to suit your goals. After you start feeling more confident, you can slowly move away from this approach and write code from scratch. Think of the “copy, paste, and tweak” approach as training wheels for a child learning to ride a bike. After getting comfortable, they won’t need them anymore.
- The best way to learn to code is by doing: Rather than learning to code for its own sake, we find that learning to code goes much smoother when you have a goal in mind or when you are working on a particular project, like analyzing data that you are interested in and that is important to you.
- Practice is key: Just as the only method to improve your foreign language skills is through lots of practice and speaking, the only method to improving your coding skills is through lots of practice. Don’t worry, however, we’ll give you plenty of opportunities to do so!
1.3 What are R packages?
Another point of confusion with many new R users is the idea of an R package. R packages extend the functionality of R by providing additional functions, data, and documentation. They are written by a worldwide community of R users and can be downloaded for free from the internet.
For example, among the many packages we will use in this book are the ggplot2 package (Wickham, Chang, et al. 2026) for data visualization in Chapter 2, the dplyr package (Wickham, François, et al. 2026) for data wrangling in Chapter 3, the moderndive package (Kim and Ismay 2026) that accompanies this book, and the infer package (Bray et al. 2025) for “tidy” and transparent statistical inference in Chapter 8, Chapter 9, and Chapter 10.
A good analogy for R packages is they are like apps you can download onto a mobile phone like in Figure 1.4:
So R is like a new mobile phone: while it has a certain amount of features when you use it for the first time, it doesn’t have everything. R packages are like the apps you can download onto your phone from Apple’s App Store or Android’s Google Play.
Let’s continue this analogy by considering the Instagram app for editing and sharing pictures. Say you have purchased a new phone and you would like to share a photo you have just taken with friends on Instagram. You need to:
- Install the app: Since your phone is new and does not include the Instagram app, you need to download the app from either the App Store or Google Play. You do this once and you’re set for the time being. You might need to do this again in the future when there is an update to the app.
- Open the app: After you’ve installed Instagram, you need to open it.
Once Instagram is open on your phone, you can then proceed to share your photo with your friends and family. The process is very similar for using an R package. You need to:
- Install the package: This is like installing an app on your phone. Most packages are not installed by default when you install R and RStudio. Thus if you want to use a package for the first time, you need to install it first. Once you’ve installed a package, you likely won’t install it again unless you want to update it to a newer version.
- “Load” the package: “Loading” a package is like opening an app on your phone. Packages are not “loaded” by default when you start RStudio on your computer; you need to “load” each package you want to use every time you start RStudio.
Let’s perform these two steps for the ggplot2 package for data visualization.
1.3.1 Package installation
Note about RStudio Server or Posit Cloud: If your instructor has provided you with a link and access to RStudio Server or Posit Cloud, you might not need to install packages, as they might be preinstalled for you by your instructor. That being said, it is still a good idea to know this process for later on when you are not using RStudio Server or Posit Cloud, but rather RStudio Desktop on your own computer.
There are two ways to install an R package: an easy way and a more advanced way. Let’s install the ggplot2 package the easy way first as shown in Figure 1.5. In the Files pane of RStudio:
- Click on the “Packages” tab.
- Click on “Install” next to Update.
- Type the name of the package under “Packages (separate multiple with space or comma):” In this case, type
ggplot2. - Click “Install.”
An alternative but slightly less convenient way to install a package is by typing install.packages("ggplot2") in the console pane of RStudio and pressing Return/Enter on your keyboard. Note you must include the quotation marks around the name of the package.
Much like an app on your phone, you only have to install a package once. However, if you want to update a previously installed package to a newer version, you need to re-install it by repeating the earlier steps.
Learning Check
(LC1.1) Repeat the earlier installation steps, but for the dplyr, nycflights23, and knitr packages. This will install the earlier mentioned dplyr package for data wrangling, the nycflights23 package containing data on all domestic flights leaving a New York City airport in 2023, and the knitr package for generating easy-to-read tables in R. We’ll use these packages in the next section.
In RStudio → Packages tab → Install → enter dplyr, nycflights23, knitr → Install. (Or run install.packages(c("dplyr","nycflights23","knitr")) in the Console.)
1.3.2 Package loading
Recall that after you’ve installed a package, you need to “load it.” In other words, you need to “open it.” We do this by using the library() command.
For example, to load the ggplot2 package, run the following code in the console pane. What do we mean by “run the following code”? Either type or copy-and-paste the following code into the console pane and then hit the Enter key.
If after running the earlier code, a blinking cursor returns next to the > “prompt” sign, it means you were successful and the ggplot2 package is now loaded and ready to use. If, however, you get a red “error message” that reads ...
Error in library(ggplot2) : there is no package called ‘ggplot2’
... it means that you didn’t successfully install it. This is an example of an “error message” we discussed in Section 1.2.2. If you get this error message, go back to Section 1.3.1 on R package installation and make sure to install the ggplot2 package before proceeding.
1.3.3 Package use
One very common mistake new R users make when wanting to use particular packages is they forget to “load” them first by using the library() command we just saw. Remember: you have to load each package you want to use every time you start RStudio. If you don’t first “load” a package, but attempt to use one of its features, you’ll see an error message similar to:
Error: could not find function
This is a different error message than the one you just saw on a package not having been installed yet. R is telling you that you are trying to use a function in a package that has not yet been “loaded.” R doesn’t know where to find the function you are using. Almost all new users forget to do this when starting out, and it is a little annoying to get used to doing it. However, you’ll remember with practice and after some time it will become second nature for you.
1.4 Explore your first datasets
Let’s put everything we’ve learned so far into practice and start exploring some real data! Data comes to us in a variety of formats, from pictures to text to numbers. Throughout this book, we’ll focus on datasets that are saved in “spreadsheet”-type format. This is probably the most common way data are collected and saved in many fields. Remember from Section 1.2.1 that these “spreadsheet”-type datasets are called data frames in R. We’ll focus on working with data saved as data frames throughout this book.
Let’s first load all the packages needed for this chapter, assuming you’ve already installed them. Read Section 1.3 for information on how to install and load R packages if you haven’t already.
At the beginning of all subsequent chapters in this book, we’ll always have a list of packages that you should have installed and loaded in order to work with that chapter’s R code.
1.4.1 nycflights23 package
Many of us have flown on airplanes or know someone who has. Air travel has become an ever-present aspect of many people’s lives. If you look at the Departures flight information board at an airport, you will frequently see that some flights are delayed for a variety of reasons. Are there ways that we can understand the reasons that cause flight delays?
We’d all like to arrive at our destinations on time whenever possible. (Unless you secretly love hanging out at airports. If you are one of these people, pretend for a moment that you are very much anticipating being at your final destination.) Throughout this book, we’re going to analyze data related to all domestic flights departing from one of New York City’s three main airports in 2023: Newark Liberty International (EWR), John F. Kennedy International (JFK), and LaGuardia Airport (LGA). We’ll access this data using the nycflights23 R package, which contains five datasets saved in five data frames:
-
flights: Information on all flights. -
airlines: A table matching airline names and their two-letter International Air Transport Association (IATA) airline codes (also known as carrier codes) for 14 airline companies. For example, “DL” is the two-letter code for Delta. -
planes: Information about each of the 4,840 physical aircraft used. -
weather: Hourly meteorological data for each of the three NYC airports. This data frame has 26,207 rows, roughly corresponding to the \(365 \times 24 \times 3 = 26,280\) possible hourly measurements one can observe at three locations over the course of a year. -
airports: Names, codes, and locations of the 1,255 domestic destinations.
The nycflights23 package is an updated version of the classic nycflights13 R package. nycflights23 was authored by ModernDive co-author Chester Ismay using the anyflights R package developed by Simon Couch. Simon granted permission to the ModernDive team to create nycflights23 and submit the package to CRAN.
1.4.2 flights data frame
We’ll begin by exploring the flights data frame and get an idea of its structure. Run the following code in your console, either by typing it or by cutting-and-pasting it. It displays the contents of the flights data frame in your console. Note that depending on the size of your monitor, the output may vary slightly.
flights# A tibble: 435,352 × 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2023 1 1 1 2038 203 328 3
2 2023 1 1 18 2300 78 228 135
3 2023 1 1 31 2344 47 500 426
4 2023 1 1 33 2140 173 238 2352
5 2023 1 1 36 2048 228 223 2252
6 2023 1 1 503 500 3 808 815
7 2023 1 1 520 510 10 948 949
8 2023 1 1 524 530 -6 645 710
9 2023 1 1 537 520 17 926 818
10 2023 1 1 547 545 2 845 852
# ℹ 435,342 more rows
# ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
Let’s unpack this output:
-
A tibble: 435,352 x 19: Atibbleis a specific kind of data frame in R. This particular data frame has-
435,352rows corresponding to different observations. Here, each observation is a flight. -
19columns corresponding to 19 variables describing each observation.
-
-
year,month,day,dep_time,sched_dep_time,dep_delay, andarr_timeare the different columns, in other words, the different variables of this dataset. - We then have a preview of the first 10 rows of observations corresponding to the first 10 flights. R is only showing the first 10 rows, because if it showed all
435,352rows, it would overwhelm your screen. -
... with 435,342 more rows` and 11 more variables:indicating to us that 435,342 more rows of data and 11 more variables could not fit in this screen.
Unfortunately, this output does not allow us to explore the data very well, but it does give a nice preview. Let’s look at some different ways to explore data frames.
1.4.3 Exploring data frames
There are many ways to get a feel for the data contained in a data frame such as flights. We present three functions that take as their “argument” (their input) a data frame and a fourth method for exploring one column of a data frame:
- Using the
View()function, which brings up RStudio’s built-in data viewer. - Using the
glimpse()function, which is included in thedplyrpackage. - Using the
kable()function, which is included in theknitrpackage. - Using the
$“extraction operator,” which is used to view a single variable.
1. View():
Run View(flights) in your console in RStudio, either by typing it or cutting-and-pasting it into the console pane. Explore this data frame in the resulting pop up viewer. You should get into the habit of viewing any data frames you encounter. Note the uppercase V in View(). R is case-sensitive, so you’ll get an error message if you run view(flights) instead of View(flights).
Learning Check
(LC1.3) What does any ONE row in this flights dataset refer to?
- A. Data on an airline
- B. Data on a flight
- C. Data on an airport
- D. Data on multiple flights
B. Data on a flight (one departure) from a NYC airport in 2023.
By running View(flights), we can explore the different variables listed in the columns. Observe that there are many different types of variables. Some of the variables like distance, day, and arr_delay are what we will call quantitative variables. These variables are numerical in nature. Other variables here are categorical.
If you look in the leftmost column of the View(flights) output, you’ll see a column of numbers. These are the row numbers of the dataset. Glancing across a row with the same number, say row 5, you can get an idea of what each row represents. This allows you to identify what object is being described in a given row by taking note of the values of the columns in that specific row. This is often called the observational unit. The observational unit in this example is an individual flight departing from New York City in 2023. You can identify the observational unit by determining what “thing” is being measured or described by each of the variables. We’ll talk more about observational units in Section 1.4.4 on identification and measurement variables.
2. glimpse():
The second way we’ll cover to explore a data frame is using the glimpse() function included in the dplyr package. Thus, you can only use the glimpse() function after you’ve loaded the dplyr package by running library(dplyr). This function provides us with an alternative perspective for exploring a data frame than the View() function:
glimpse(flights)Rows: 435,352
Columns: 19
$ year <int> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2…
$ month <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ day <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ dep_time <int> 1, 18, 31, 33, 36, 503, 520, 524, 537, 547, 549, 551, 5…
$ sched_dep_time <int> 2038, 2300, 2344, 2140, 2048, 500, 510, 530, 520, 545, …
$ dep_delay <dbl> 203, 78, 47, 173, 228, 3, 10, -6, 17, 2, -10, -9, -7, -…
$ arr_time <int> 328, 228, 500, 238, 223, 808, 948, 645, 926, 845, 905, …
$ sched_arr_time <int> 3, 135, 426, 2352, 2252, 815, 949, 710, 818, 852, 901, …
$ arr_delay <dbl> 205, 53, 34, 166, 211, -7, -1, -25, 68, -7, 4, -13, -14…
$ carrier <chr> "UA", "DL", "B6", "B6", "UA", "AA", "B6", "AA", "UA", "…
$ flight <int> 628, 393, 371, 1053, 219, 499, 996, 981, 206, 225, 800,…
$ tailnum <chr> "N25201", "N830DN", "N807JB", "N265JB", "N17730", "N925…
$ origin <chr> "EWR", "JFK", "JFK", "JFK", "EWR", "EWR", "JFK", "EWR",…
$ dest <chr> "SMF", "ATL", "BQN", "CHS", "DTW", "MIA", "BQN", "ORD",…
$ air_time <dbl> 367, 108, 190, 108, 80, 154, 192, 119, 258, 157, 164, 1…
$ distance <dbl> 2500, 760, 1576, 636, 488, 1085, 1576, 719, 1400, 1065,…
$ hour <dbl> 20, 23, 23, 21, 20, 5, 5, 5, 5, 5, 5, 6, 5, 6, 6, 6, 6,…
$ minute <dbl> 38, 0, 44, 40, 48, 0, 10, 30, 20, 45, 59, 0, 59, 0, 0, …
$ time_hour <dttm> 2023-01-01 20:00:00, 2023-01-01 23:00:00, 2023-01-01 2…
Observe that glimpse() will give you the first few entries of each variable in a row after the variable name. In addition, the data type (see Section 1.2.1) of the variable is given immediately after each variable’s name inside < >. Here, int and dbl refer to “integer” and “double,” which are computer coding terminology for quantitative/numerical variables. “Doubles” take up twice the size to store on a computer compared to integers.
In contrast, chr refers to “character,” which is computer terminology for text data. In most forms, text data, such as the carrier or origin of a flight, are categorical variables. The time_hour variable is another data type: dttm. These types of variables represent date and time combinations. However, we won’t work with dates and times in this book; we leave this topic for other data science books like Data Science: A First Introduction by Tiffany-Anne Timbers, Melissa Lee, and Trevor Campbell or R for Data Science (Grolemund and Wickham 2017).
Learning Check
(LC1.4) What are some other examples in this dataset of categorical variables? What makes them different than quantitative variables?
Hint: Type ?flights in the console to see what all the variables mean!
- Categorical:
-
carrierthe company -
destthe destination -
flightthe flight number. Even though this is a number, its simply a label. Example United 1545 is not less than United 1714
-
- Quantitative:
-
distancethe distance in miles -
time_hourtime
-
3. kable():
The final way to explore the entirety of a data frame is using the kable() function from the knitr package. Let’s explore the different carrier codes for all the airlines in our dataset two ways. Run both of these lines of code in the console:
airlines
kable(airlines)At first glance, it may not appear that there is much difference in the outputs. However, when using tools for producing reproducible reports such as R Markdown, the latter code produces output that is much more legible and reader-friendly. You’ll see us use this reader-friendly style in many places in the book when we want to print a data frame as a nice table.
4. $ operator
Lastly, the $ operator allows us to extract and then explore a single variable within a data frame. For example, run the following in your console:
airlines$nameWe used the $ operator to extract only the name variable and return it as a vector of length 14. We’ll only be occasionally exploring data frames using the $ operator, instead favoring the View() and glimpse() functions.
1.4.4 Identification and measurement variables
There is a subtle difference between the kinds of variables that you will encounter in data frames. There are identification variables and measurement variables. For example, let’s explore the airports data frame by showing the output of glimpse(airports):
glimpse(airports)Rows: 1,255
Columns: 8
$ faa <chr> "AAF", "AAP", "ABE", "ABI", "ABL", "ABQ", "ABR", "ABY", "ACK", "…
$ name <chr> "Apalachicola Regional Airport", "Andrau Airpark", "Lehigh Valle…
$ lat <dbl> 29.7, 29.7, 40.7, 32.4, 67.1, 35.0, 45.4, 31.5, 41.3, 31.6, 41.0…
$ lon <dbl> -85.0, -95.6, -75.4, -99.7, -157.9, -106.6, -98.4, -84.2, -70.1,…
$ alt <dbl> 20, 79, 393, 1791, 334, 5355, 1302, 197, 47, 516, 221, 75, 18, 7…
$ tz <dbl> -5, -6, -5, -6, -9, -7, -6, -5, -5, -6, -8, -5, -10, -6, -9, -6,…
$ dst <chr> "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",…
$ tzone <chr> "America/New_York", "America/Chicago", "America/New_York", "Amer…
The variables faa and name are identification variables that uniquely identify each airport. faa provides the airport’s unique FAA code, while name gives its official name. These variables are used to uniquely identify each row in a data frame. The remaining variables (lat, lon, alt, tz, dst, tzone) are often called measurement or characteristic variables: variables that describe properties of each observational unit. For example, lat and long describe the latitude and longitude of each airport.
Furthermore, sometimes a single variable might not be enough to uniquely identify each observational unit: combinations of variables might be needed. While it is not an absolute rule, for organizational purposes it is considered good practice to have your identification variables in the leftmost columns of your data frame.
Learning Check
(LC1.5) What properties of each airport do the variables lat, lon, alt, tz, dst, and tzone describe in the airports data frame? Take your best guess.
-
lat= latitude,lon= longitude -
alt= airport altitude (likely feet) -
tz= time zone offset from UTC (hours) -
dst= daylight savings time code/indicator -
tzone= time zone name (IANA string)
(LC1.6) Provide the names of variables in a data frame with at least three variables where one of them is an identification variable and the other two are not.
In the weather data frame, the combination of origin, year, month, day, hour are identification variables as they identify the observation in question. * Anything else pertains to observations: temp, humid, wind_speed, etc.
1.4.5 Help files
Another nice feature of R are help files, which provide documentation for various functions and datasets. You can bring up help files by adding a ? before the name of a function or data frame and then run this in the console. You will then be presented with a page showing the corresponding documentation if it exists. For example, let’s look at the help file for the flights data frame.
?flightsThe help file should pop up in the Help pane of RStudio. If you have questions about a function or data frame included in an R package, you should get in the habit of consulting the help file right away.
Learning Check
(LC1.7) Look at the help file for the airports data frame. Revise your earlier guesses about what the variables lat, lon, alt, tz, dst, and tzone each describe.
-
lat,lon: geographic latitude/longitude of the airport -
alt: altitude (feet) -
tz: hours offset from UTC (e.g., −5 for Eastern Standard Time) -
dst: daylight saving time indicator (e.g., “A” = observes DST, etc., per help file coding) -
tzone: IANA time zone name (e.g.,"America/New_York")
This documentation is also available on the package website here.
1.4.6 Looking ahead to end-of-chapter exercises
Starting with Chapter 2, each chapter ends with a set of end-of-chapter exercises that go beyond the nycflights23 data and ask you to apply what you’ve learned to other real-world datasets. The first new dataset arrives in Chapter 2: a tidied collection of every Olympic athlete from 1896 to 2026, in the olympicAthletes package.
The end-of-chapter exercises come in two kinds. Coding exercises include a live, editable code editor — press Run Code to run R right in your browser (powered by webR), with no installation required, and edit the code to experiment. Conceptual exercises ask for a short written answer and have no code cell. If you’d rather work locally in RStudio, the install steps below set up the same packages on your own machine.
Because olympicAthletes is not yet on CRAN, you’ll install it from GitHub using the remotes package:
install.packages("remotes")
remotes::install_github("moderndive/olympicAthletes")This is a one-time install. Once olympicAthletes is on CRAN (it will be eventually), you’ll be able to install it the usual way with install.packages("olympicAthletes"). Either way, you load it the same way:
We’ll also introduce four other datasets later in the book — episodes of Rick Steves’ Europe (steves), Bob Ross paintings (bob_ross from fivethirtyeight), confirmed exoplanets (exoplanetdata), and Holocene volcanoes (volcanoes). Each will be introduced when it first appears.
Quick checks
Ten questions to assess your understanding. Several are designed around common misconceptions — read each option carefully before peeking at the answer.
Q1-1. What is the difference between R and RStudio?
- R is the programming language; RStudio is an interface for using R
- R is a web browser; RStudio is a desktop application
- R is a graphical point-and-click interface; RStudio is a command-line tool
- They are two different names for the same software
(a) R is the programming language and engine that runs your code. RStudio is an IDE, a friendlier interface for writing R code, viewing data, and managing projects. The chapter’s analogy: R is the engine, RStudio is the dashboard.
Q1-2. A column of phone numbers stored as text like "(555) 123-4567". This variable is best classified as:
- Numerical, because you could perform calculations on the digits
- Both numerical and categorical
- Categorical, because the values label rather than measure
- Numerical, because it contains digits
(c) The test for “numerical” is whether arithmetic on the values is meaningful, not whether digits appear. Adding two phone numbers makes no sense, they’re identifiers, so they’re categorical. Same logic applies to ZIP codes, customer IDs, and area codes.
Q1-3. After running install.packages("dplyr") once, you close R and reopen it the next day. To use glimpse() again, you need to:
- Nothing; packages stay loaded forever once installed
- Re-install the package
- Run
library(dplyr)again - Type
glimpse()and R will auto-load the package
(c) Installation is a one-time act per machine. Loading with library(pkg) happens at the start of every new R session, that’s why scripts begin with library() calls.
Q1-4. You run code to create a scatterplot and red text appears in the console, beginning with Warning: Removed 2 rows containing missing values (geom_point). What happened?
- R is scolding you and you must restart RStudio before continuing
- It’s just a friendly diagnostic message with no effect on the output
- The code failed to run and no output was produced
- The scatterplot was drawn without the two rows with missing values
(d) Red text starting with “Warning:” is a yellow traffic light: your code still works, but with some caveats to pay attention to. Here the scatterplot is still drawn, just without the two rows that had missing values. Red text starting with “Error” is a red light (the code did not run), and any other red text is just a friendly message: a green light.
Q1-5. You want to check whether 2 + 1 equals 3 in R. Which code correctly tests for equality?
equals(2 + 1, 3)2 + 1 == 32 + 1 === 32 + 1 = 3
(b) Testing for equality in R uses ==, not =; the single = is typically used for assignment, such as setting a function’s argument values like seq(from = 2, to = 5). So 2 + 1 == 3 is correct R code (it returns TRUE), while 2 + 1 = 3 returns an error. There is no === operator in R, and equals() is not a base R function.
Q1-6. What’s the difference between flights and "flights" in R?
-
flightsnames an object;"flights"is a text string -
"flights"names an object;flightsis a text string -
flightsnames a column;"flights"names the data frame - There is no difference; R treats them identically
(a) Quotes turn something into a literal string. Without quotes, R looks for an object by that name. This distinction matters in library(dplyr) (no quotes, refer to the package by name) vs install.packages("dplyr") (with quotes, pass the name as a string).
Q1-7. Which is a quantitative variable?
- ZIP code
- Phone area code
- Customer ID number
- Temperature
(d) Temperature has meaningful arithmetic; you can average two temperatures, take their difference, etc. The others are identifiers stored as digits.
Q1-8. A user runs View(flights) to inspect the data. Then they edit values in the spreadsheet view. What happens to flights?
- A new data frame called
flights_editedis created - Nothing happens; the display is read-only
- R errors
- The data frame is updated with the edits
Q1-9. A tibble differs from a base R data.frame mainly because:
- A tibble can hold mixed-type columns; a data frame cannot
- A tibble prints fewer rows and shows column types
- They are identical
- A tibble can be passed to dplyr verbs; a data frame cannot
(b) Both can hold mixed types and both work with dplyr. The differences are usability: tibble printing truncates and displays types; subsetting a single column returns a tibble (not a vector); strings aren’t auto-converted to factors.
Q1-10. You run glimpse(flights) and see 435,352 Rows and 19 Columns. Each row of flights represents:
- One flight
- An airline
- A passenger
- An airport
(a) The observational unit, what one row represents, is the most important question to answer about any new dataset, because every later analysis (“average delay per carrier”, “flights from JFK in June”) is implicitly grouping or filtering at that unit. For flights, each row is one flight: same plane on a different day is a different row, and one flight has one carrier, one origin, one destination, one departure time.
| Function / verb | What it does | Quick example |
|---|---|---|
install.packages("pkg") |
Install a package from CRAN (quotes around name) | install.packages("dplyr") |
library(pkg) |
Load an already-installed package (no quotes) | library(dplyr) |
View(df) |
Open a data frame in RStudio’s spreadsheet viewer1 | View(flights) |
glimpse(df) |
Compact, transposed summary of a data frame | glimpse(flights) |
kable(df) |
Render a data frame as a formatted table | kable(airlines) |
Exercises
A short set of warm-up exercises using the olympic_athletes dataset introduced in Section 1.4.6. These prompts focus on inspecting a real-world data frame — they’re shorter than later chapters’ sets to match Chapter 1’s introductory scope. Solutions are available to instructors separately.
Difficulty stars: ★ warm-up, ★★ standard application, ★★★ critical thinking. Solutions are available to instructors separately.
What are R and RStudio?
EX1.1 (★) A classmate insists “R and RStudio are the same thing, RStudio is just a newer name for R.” In 2–3 sentences, set them straight using an everyday analogy of your choice (car & dashboard, engine & cockpit, kitchen & recipe, whatever clicks for you). Be specific about which one runs the code and which one is the interface you actually click around in.
How do I code in R?
EX1.2 (★) Matching. For each R expression on the left, identify what type of object it represents from the list on the right. Each type is used at most once, and one type will be left over.
| Expression | Type |
|---|---|
(a) 3.14
|
1. character |
(b) "ModernDive"
|
2. data frame |
(c) TRUE
|
3. double (numeric) |
(d) c(1, 2, 3)
|
4. factor |
(e) seq()
|
5. function |
(f) olympic_athletes
|
6. logical |
| 7. vector |
EX1.3 (★) Distinguish between an error, a warning, and a message in R. Which of the three halts execution, and which let the rest of your script keep running? Use the chapter’s traffic-light analogy (red, yellow, green) to explain how you should react to each one when you see it in red text in the console.
EX1.14 (★) Predict, then verify. Section 1.2.1 introduces comparisons like ==, <=, and != plus the logical operators & (“and”) and | (“or”). For each expression below, write down what R will return, TRUE, FALSE, or an error, before you run it. Then run each line in the console to check your predictions.
3 * 5 == 1510 <= 9"R" != "r"(2 + 3 == 5) & (10 < 4)(2 + 3 == 5) | (10 < 4)7 = 7
One of the six isn’t a TRUE/FALSE question at all. Which one, and why does R react the way it does?
Need a hint?
The chapter makes a point of the difference between == and =.
What are R packages?
EX1.4 (★) What’s the difference between library(olympicAthletes) and install.packages("olympicAthletes")? Why do you only need to do one of them once per machine?
EX1.5 (★) Suppose you start a fresh R session and run glimpse(olympic_athletes) without first running library(olympicAthletes) (and without library(dplyr)). What error do you expect, and what’s the fix?
Explore your first datasets
EX1.6 (★) Run glimpse(olympic_athletes). How many rows and how many columns does the data frame have?
EX1.7 (★) What does each row of olympic_athletes represent?
Need a hint?
It’s not “one athlete”, it’s something more specific.
EX1.8 (★) Run View(olympic_athletes) (in RStudio) or head(olympic_athletes, 10). What does each column represent? Pick three columns and write a one-line description for each.
EX1.9 (★) Among the columns, identify two identification variables and three measurement variables. Justify each.
EX1.10 (★) Classify each of these columns as numerical or categorical: sex, age, height, year, sport, medal. Justify any that are tricky.
EX1.11 (★) What does running ?olympic_athletes do? Try it in RStudio. What does the help file tell you about the medal column?
EX1.12 (★) What do you think the noc column abbreviates? Look at a few rows of olympic_athletes to confirm (the team column gives the full country name, which should help), or open its help file with ?olympic_athletes and read the column description directly.
EX1.13 (★) Look at the medal_table data frame (also from olympicAthletes). Describe one row of medal_table in plain English. How does its observational unit differ from olympic_athletes?
Extensions
The exercises below deliberately introduce functions and concepts beyond what this chapter teaches — log transformations, predict(), new packages, foreshadowing later chapters. They are optional, aimed at readers who want to push further. The main Exercises and Quick checks above stick strictly to what this chapter covers.
EX1.15 (◆◆) RStudio Projects. A .Rproj file marks a folder as an RStudio Project, opening it sets R’s working directory to that folder, scopes the History panel to it, and (importantly) makes scripts portable across machines because they reference files relative to the project root instead of absolute paths like /Users/yourname/Downloads/....
Create a new RStudio Project for your ModernDive work (File → New Project → New Directory → New Project). Save one script inside it that runs library(olympicAthletes); glimpse(olympic_athletes). Close RStudio, reopen by double-clicking the .Rproj file, and re-run the script. Briefly: what changed about the working directory between the two sessions, and why does that matter when you share code with someone else?
EX1.16 (◆◆) One-shot data exploration with tidy_summary(). The moderndive package provides tidy_summary(), which produces a one-stop tibble of column-by-column summaries: type, level breakdowns for categoricals, min/quartiles/max for numerics. Run it on weather from nycflights23 (the same package as the chapter’s flights); weather has a few missing values, so pass na.rm = TRUE so the summaries skip them. Compare its output to running glimpse(). Which of the two would you reach for first when meeting a new data frame for the first time?
EX1.17 (◆◆) View() that works inside Quarto/R Markdown. Base R’s utils::View() errors in non-interactive contexts (when you knit/render a .qmd or .Rmd), which can break documents. moderndive exports a drop-in View() wrapper that behaves identically interactively but in non-interactive contexts renders the data inline as a scrollable table instead, so the document still builds. Because a large client-side table bogs down on very large data, in non-interactive contexts View() shows a random sample of n rows (default 1000) when the data frame is larger, and prints a short message saying so. Run View(olympic_athletes) here and you’ll get a representative 1,000-row sample of the ≈ 315k rows rather than a slow table or a warning; use full = TRUE to see every row, n = ... to resize the sample, or seed = ... for a reproducible one. Briefly: when would you prefer the inline table over a static printed tibble in a Quarto report?
EX1.18 (◆◆) Managing function masking with conflicted. Here’s a wrinkle the chapter doesn’t cover: when two loaded packages export the same function name (e.g., dplyr::filter and stats::filter), R silently uses whichever package was loaded most recently, a behavior called masking. The conflicted package turns this silent behavior into a loud error and lets you declare your preferences. Try the starter snippet, note how conflicts_prefer() makes the choice explicit. When would you rather have a noisy error than silent overriding?
1.5 Conclusion
This chapter provides a small set of tools to explore data in R, but it’s far from exhaustive. Including everything would overwhelm rather than help. The best way to add to your toolbox is running and writing code in RStudio as much as possible.
1.5.1 Additional resources
If you are new to the world of coding, R, and RStudio and feel you could benefit from a more detailed introduction, we suggest the short book, Getting Used to R, RStudio, and R Markdown (Ismay and Kennedy 2024), previewed in Figure 1.6. It includes screencasts that you can follow along and pause as you learn. This book also contains an introduction to R Markdown, a tool used for reproducible research.
1.5.2 What’s to come?
We’re next heading into the “Data Science with tidyverse” portion in Chapter 2 as shown in Figure 1.7 with what we feel is the most important tool in a data scientist’s toolbox: data visualization. We’ll continue to explore the data included in the moderndive and nycflights23 packages using the ggplot2 package for data visualization. Data visualization is a powerful tool to add to your toolbox for data exploration that provides additional insight to what the View() and glimpse() functions can provide.
In the interactive code cells on this page,
View()comes from themoderndivepackage rather than from RStudio, since there is no viewer pane in the browser. It displays the data frame as a scrollable, searchable table directly below the cell instead. Loadingmoderndivegives you that same behavior when rendering an R Markdown or Quarto document, where RStudio’sView()would otherwise produce an error.↩︎






