AE04 - Getting to Know Your Data Types (key)

Suggested answers

Author

Dr. D

Published

September 25, 2026

Getting to Know You: Data Types

Purpose

In this application exercise you’ll import data directly from a live Google Sheet, then do some data cleaning as necessary.

Learning objectives

  • Import a dataset from Google Sheets with googlesheets4, including authenticating with your own Google account
  • Identify the data type R assigns to a variable and compare it to what that variable conceptually should be
  • Diagnose and repair errors

Data

The data come from the “Getting to know you” survey everyone filled out at the start of the semester. Before you import anything, open the survey itself — and look through the questions and answer choices. You’ll be comparing what you see there to what shows up in the data later in this AE.

Setup

library(tidyverse)
library(googlesheets4)

A quick word on googlesheets4

googlesheets4 reads a Google Sheet straight into R as a data frame, avoiding the need to download and reimport a copy. This particular Sheet is not public — it’s only viewable if you’re signed into a Google account that has access to it.

The first time you run a chunk that calls read_sheet(), R will kick off an authentication flow: a browser window opens and asks you to sign into a Google account, then grants the Tidyverse API Packages app permission to read your Sheets. A few things to expect:

  • Sign in with your @csuchico.edu Google account — that’s what has access to this Sheet.
  • Once you’ve signed in, googlesheets4 caches that token, so you shouldn’t have to repeat this every single time you render.
  • If you get a “permission denied” error instead of your data, it usually means you authenticated with the wrong account — run googlesheets4::gs4_auth() on its own to be prompted again and pick a different one.

For more than this AE covers:

Step 1: Import

Google Forms turns each question into a column name, which makes for very long column names. We’ll rename them as we import to something easier to type.

raw <- read_sheet("https://docs.google.com/spreadsheets/d/1e8XSidxeT3SIE10g1jiEuALRa7REpmYU64_3V3TNKKs/edit?usp=sharing") %>%
  rename(
    timestamp       = Timestamp,
    zipcode         = `What is the zipcode of your hometown?`,
    stats_before    = `Have you taken any statistics courses before?`,
    prog_experience = `How much experience do you have with programming?`,
    languages       = `If you've programmed before, which languages have you used, and how comfortable do you feel with each? If you haven't programmed before, please leave this question blank.`,
    data_interest   = `What types of data interest you?`,
    learn_best      = `How do you learn best?`,
    commute_min     = `How long does it take you to commute from home to this classroom, in minutes? Please enter a number only.`
  )

Confirm the token is cached

googlesheets4 (via the gargle package) caches your token in a local folder on your computer (typically ~/.R/gargle/gargle-oauth). This means you shouldn’t have to re-login to google, just specify to use the stored token.

  1. Fully quit RStudio.
  2. Reopen RStudio in this AE project
  3. Run the import chunk again.
  4. Read what happens. You should see something about reusing a cached token rather than a fresh browser sign-in. If gargle shows you a menu of cached accounts in the console, read it and choose your @csuchico.edu account, rather than signing in again.

Step 2: Data type audit

Before working with the data let’s assess two variables and assess what type does R currently see each as, and what should it be, given the question that was actually asked?

“How long does it take you to commute from home to this classroom, in minutes? Please enter a number only.”

class(raw$commute_min)
[1] "list"

That’s supposed to be a number. That means functions like mean won’t work.

mean(raw$commute_min)
[1] NA

What’s going on? Let’s unlist this variable and look at the unique values.

unlist(raw$commute_min) |> unique()
 [1] "10"      "7"       "15"      "21"      "35"      "25"      "30"     
 [8] "70"      "20"      "16"      "22"      "forever"

Ah.. someone wrote in a word instead of providing a number.

“How much experience do you have with programming?”

class(raw$prog_experience)
[1] "character"
table(raw$prog_experience)

A lot — I use programming regularly and feel confident writing code 
                                                                 11 
                                                               None 
                                                                  1 
       Some — I’ve worked on a few projects or used it occasionally 
                                                                 18 

This should be treated as ordinal, and it’s missing a category.

Skim the rest

glimpse(raw)
Rows: 30
Columns: 8
$ timestamp       <dttm> 2026-08-24 15:32:06, 2026-08-24 15:32:19, 2026-08-24 …
$ zipcode         <dbl> 95618, 95129, 95932, 94526, 95973, 94550, 96080, 94510…
$ stats_before    <chr> "Yes, I have taken another college course on statistic…
$ prog_experience <chr> "A lot — I use programming regularly and feel confiden…
$ languages       <chr> "C/C++ (very comfortable), Python (somewhat comfortabl…
$ data_interest   <chr> "- Crime, - Economics, - Environment/Climate, - Politi…
$ learn_best      <chr> "Engaging lectures", "In person classes and lectures",…
$ commute_min     <list> 10, 7, 10, 10, 15, 21, 35, 25, 15, <NULL>, 30, 15, 70…

zipcode and stats_before should be categorical, the rest are as expected. We won’t work with them in this AE.

Step 3: Apply fixes

Commute time

While we could try to coerce list -> character -> numeric, it would be easier to here to specify data types on read.

survey <- read_sheet("https://docs.google.com/spreadsheets/d/1e8XSidxeT3SIE10g1jiEuALRa7REpmYU64_3V3TNKKs/edit?usp=sharing", 
                     col_types = c("Tccccccn")) %>%
  rename(
    timestamp       = Timestamp,
    zipcode         = `What is the zipcode of your hometown?`,
    stats_before    = `Have you taken any statistics courses before?`,
    prog_experience = `How much experience do you have with programming?`,
    languages       = `If you've programmed before, which languages have you used, and how comfortable do you feel with each? If you haven't programmed before, please leave this question blank.`,
    data_interest   = `What types of data interest you?`,
    learn_best      = `How do you learn best?`,
    commute_min     = `How long does it take you to commute from home to this classroom, in minutes? Please enter a number only.`
  )
Important

Warning message: NAs introduced by coercion

Always keep your eye out for this and ask yourself if this was expected. Here it was - the “forever” was not a number and so needed to be blanked out.

unique(survey$commute_min)
 [1] 10  7 15 21 35 25 NA 30 70 20 16 22

Recode & reorder prog_experience

The forcats package has a lot of useful functions for wrangling factors. Here are some refs for the functions we’re going to use

CautionExternal references
  1. First we confirm what’s actually in the data.
distinct(survey, prog_experience)
# A tibble: 3 × 1
  prog_experience                                                    
  <chr>                                                              
1 A lot — I use programming regularly and feel confident writing code
2 Some — I’ve worked on a few projects or used it occasionally       
3 None                                                               
  1. Then compare against the published survey.

The “a little” option was never selected by anyone, so it doesn’t show up in the data. But it should be represented on in visualizations to make it clear that it could have been chosen. That means something different than never being an option to begin with.

  1. Convert the variable to a factor with the current recorded levels.
survey <- survey %>%
  mutate(
    prog_experience = fct_recode(prog_experience,
      "None"     = "None",
      "Some"     = "Some — I've worked on a few projects or used it occasionally",
      "A lot"    = "A lot — I use programming regularly and feel confident writing code"
    )
  )

class(survey$prog_experience)
[1] "factor"
levels(survey$prog_experience)
[1] "A lot"                                                       
[2] "None"                                                        
[3] "Some — I’ve worked on a few projects or used it occasionally"
  1. Now that it’s reading as a factor, we can use fct_expand to add levels.
survey$prog_experience <- survey$prog_experience %>% fct_expand("A little")
levels(survey$prog_experience)
[1] "A lot"                                                       
[2] "None"                                                        
[3] "Some — I’ve worked on a few projects or used it occasionally"
[4] "A little"                                                    
  1. Last, respect the ordinal nature of this variable by putting the levels in increasing order.**
survey$prog_experience = fct_relevel(survey$prog_experience, "None", "A little", "Some", "A lot")

levels(survey$prog_experience)
[1] "None"                                                        
[2] "A little"                                                    
[3] "A lot"                                                       
[4] "Some — I’ve worked on a few projects or used it occasionally"