Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Lesson 6 — Importing Data: Built-in, CSV, Excel, URL, and the Formula Interface

1Objectives

By the end of this lesson you will be able to:

  1. Load a dataset that ships built into mosaic.

  2. Import your own data from a CSV file.

  3. Recognize how you’d import an Excel file, if you ever need to.

  4. Import data directly from a web address.

  5. Read the y ~ x formula interface — the one grammar that will describe almost everything you do with data for the rest of this course.

Every result on this page comes from data that is either genuinely built into mosaic, a small labeled example file, or pulled live from a public web address — nothing here is typed-up or made-up numbers.

2Setup

As of Lesson 5, every session starts the same way:

library(mosaic)
library(BSDA)

31. Built-in datasets

Both mosaic and its companion package mosaicData ship with real practice datasets already inside them — no importing required. One is KidsFeet: foot length and width measurements from a group of kids, with their sex and dominant hand recorded.

data(KidsFeet)
head(KidsFeet)
    name birthmonth birthyear length width sex biggerfoot domhand
1  David          5        88   24.4   8.4   B          L       R
2   Lars         10        87   25.4   8.8   B          L       L
3   Zach         12        87   24.5   9.7   B          R       R
4   Josh          1        88   25.2   9.8   B          L       R
5   Lang          2        88   25.1   8.9   B          L       R
6 Scotty          3        88   25.7   9.7   B          R       R

data(KidsFeet) makes the dataset available, and head() (from Lesson 4’s function pattern) shows its first six rows. Two more functions you’ll reach for constantly on any new dataset:

str(KidsFeet)
'data.frame':	39 obs. of  8 variables:
 $ name      : Factor w/ 36 levels "Abby","Alisha",..: 10 24 36 20 23 34 13 4 14 8 ...
 $ birthmonth: int  5 10 12 1 2 3 2 6 5 9 ...
 $ birthyear : int  88 87 87 88 88 88 88 88 88 88 ...
 $ length    : num  24.4 25.4 24.5 25.2 25.1 25.7 26.1 23 23.6 22.9 ...
 $ width     : num  8.4 8.8 9.7 9.8 8.9 9.7 9.6 8.8 9.3 8.8 ...
 $ sex       : Factor w/ 2 levels "B","G": 1 1 1 1 1 1 1 2 2 1 ...
 $ biggerfoot: Factor w/ 2 levels "L","R": 1 1 2 1 1 2 1 1 2 2 ...
 $ domhand   : Factor w/ 2 levels "L","R": 2 1 2 2 2 2 2 2 2 1 ...

str() (short for “structure”) lists every column, its type, and a preview of its values — the fastest way to get oriented in a new dataset. nrow() and names() answer two more questions you’ll always want first:

nrow(KidsFeet)
names(KidsFeet)
[1] 39
[1] "name"       "birthmonth" "birthyear"  "length"     "width"     
[6] "sex"        "biggerfoot" "domhand"   

39 kids, 8 columns — good habits: check the size and the column names before you try to analyze anything.

42. Importing your own CSV file

A CSV (“comma-separated values”) file is the most common way data gets shared — a plain text file where each line is a row and commas separate the columns; it opens in Excel, Google Sheets, or a plain text editor. R reads one with read.csv().

This example uses a small made-up practice file, coffee_wait_sim.csv — 20 customers timed at a campus coffee cart, some on a weekday morning, some on a weekend morning. It’s a teaching example, not real research data (the file name ends in _sim for exactly that reason — see the note below), stored in this book’s data/ folder.

coffee <- read.csv("data/coffee_wait_sim.csv")
head(coffee)
  customer_id wait_minutes day_type
1           1          3.7  Weekday
2           2          2.3  Weekday
3           3          1.4  Weekend
4           4          3.7  Weekend
5           5          5.9  Weekday
6           6          6.2  Weekend
str(coffee)
'data.frame':	20 obs. of  3 variables:
 $ customer_id : int  1 2 3 4 5 6 7 8 9 10 ...
 $ wait_minutes: num  3.7 2.3 1.4 3.7 5.9 6.2 5.9 2.3 3.7 2.6 ...
 $ day_type    : chr  "Weekday" "Weekday" "Weekend" "Weekend" ...

53. Importing an Excel file

R doesn’t read .xlsx Excel files with base functions the way it reads CSV — you need one more package (readxl, not part of this course’s two-package toolkit, so you’d only add it if a specific assignment calls for an Excel file). The pattern, for reference, looks like this:

# only needed if you're specifically handed an .xlsx file
install.packages("readxl")   # one time
library(readxl)               # each session
grades <- read_excel("data/gradebook.xlsx")

The easiest path for this course, if you ever have data in Excel: open the file in Excel, use File ▸ Save As ▸ CSV, and then import it with read.csv() exactly like the coffee example above — no extra package needed.

64. Importing data from a web address (URL)

You can point read.csv() straight at a web address instead of a file on your computer, wrapping the address in url(). Here’s a real, publicly hosted dataset — Gosset’s classic sleep-study data (extra hours of sleep gained by patients on two different drugs), mirrored at a long-standing, stable public repository of teaching datasets:

sleep_study <- read.csv(url(
  "https://raw.githubusercontent.com/vincentarelbundock/Rdatasets/master/csv/datasets/sleep.csv"
))
head(sleep_study)
  rownames extra group ID
1        1   0.7     1  1
2        2  -1.6     1  2
3        3  -0.2     1  3
4        4  -1.2     1  4
5        5  -0.1     1  5
6        6   3.4     1  6
nrow(sleep_study)
[1] 20

20 rows came back from the live web address — the exact same idea as read.csv() on a local file, just pointed at the internet instead of your computer.

75. The formula interface: y ~ x

Now that you can get data into R, here is the one idea that unlocks almost every mosaic function for the rest of this course: the formula, written y ~ x and read out loud as “y broken down by x.”

favstats(~ length, data = KidsFeet)
  min Q1 median   Q3  max     mean       sd  n missing
 21.6 24   24.5 25.6 27.5 24.72308 1.317586 39       0

A ~ with nothing on the left just means “summarize this one variable” — here, foot length for all 39 kids. Put a grouping variable on the left of ~, and the same function breaks the summary down by group:

favstats(length ~ sex, data = KidsFeet)
  sex  min    Q1 median   Q3  max     mean       sd  n missing
1   B 22.9 24.35  24.95 25.8 27.5 25.10500 1.216758 20       0
2   G 21.6 23.65  24.20 25.1 26.7 24.32105 1.330238 19       0

Same function, same dataset — but now you get separate rows for boys (B) and girls (G), because the formula reads “foot length, broken down by sex.”

The exact same ~ grammar works for counting a categorical variable with tally():

tally(~ domhand, data = KidsFeet)
domhand
 L  R 
 8 31 
tally(domhand ~ sex, data = KidsFeet)
       sex
domhand  B  G
      L  5  3
      R 15 16

“Dominant hand, broken down by sex” — a small two-way table, built with the same formula pattern you just used for summary statistics. And it works on your own imported data exactly the same way — here it is again on the coffee-wait data from earlier in this lesson:

favstats(wait_minutes ~ day_type, data = coffee)
  day_type min    Q1 median  Q3 max     mean       sd  n missing
1  Weekday 2.3 3.675   4.45 5.9 8.1 4.716667 1.752833 12       0
2  Weekend 1.4 2.100   2.70 3.1 6.2 2.925000 1.521043  8       0

Weekday wait times average about 4.7 minutes; weekend, about 2.9 — the same variable ~ group formula, working on a totally different dataset, because it’s one consistent grammar. You’ll see this exact ~ pattern again for graphs in Lesson 7, and for statistical tests in Lesson 9.

8Summary

9Check your understanding

  1. What are the first four functions you should run on any dataset you’ve never seen before, and what does each tell you?

  2. Why does this lesson call coffee_wait_sim.csv a “classroom-simulation” dataset instead of real data, and how could someone reproduce it exactly?

  3. Using the coffee data from this lesson, what R would you write to find the favstats of wait_minutes broken down by day_type? (You already saw the answer above — write it from memory first, then check.)

  4. In your own words, what does ~ mean when there’s nothing to its left?