STA 9750
  • Syllabus
  • Pre-Assignments
  • Labs
  • Mini Projects
  • Course Project
  • Additional Resources and Course Policies
  • Learning Objectives
  • Prior Offerings
    • Spring 2026
    • Fall 2025
    • Spring 2025
    • Fall 2024

Warning - This page is for a prior offering of STA 9750. For the latest offering, click here.

On this page

  • Key Dates
  • Welcome to STA 9750 Mini Projects!
  • Introduction
    • Student Responsibilities
    • Rubric
    • Submission Instructions
  • Mini-Project #01: What We Watched: Exploring Netflix Viewing Data
    • Data Acquisition
    • Data Cleaning and Preparation
    • Initial Data Exploration
    • Final Deliverable: Platform Strategy Memo
  • AI Usage Statement
  • Extra Credit Opportunities
    • Gini Analysis (Up to 2 Points)
    • Data Visualization (2 point)
  • Edit this page
  • View source
  • Report an issue

STA 9750 Mini-Project #01: What We Watched: Exploring Netflix Viewing Data

\[\newcommand{\P}{\mathbb{P}} \newcommand{\E}{\mathbb{E}} \newcommand{\R}{\mathbb{R}}\]

Key Dates

  • Released to Students: 2026-09-22
  • Initial Submission: 2026-10-16 11:59pm ET on GitHub and Brightspace
  • Peer Feedback:
    • Peer Feedback Assigned: 2026-10-19 on GitHub
    • Peer Feedback Due: 2026-10-26 11:59pm ET on Brightspace
  • Estimated Return of Grades and Comments:
    • Initial Submission: 2026-10-23
    • Meta-Review: 2026-11-01

Estimated Time to Complete: 13-15 Hours

Estimated Time for Peer Feedback: 1 Hour


Welcome to STA 9750 Mini Projects!

In the STA 9750 Mini-Projects, you will perform basic data analyses intended to model best practices for your course final project. (Note, however, that these are mini-projects; your final course project is expected to be far more extensive than any single MP.)

Introduction

The global streaming giant Netflix needs no introduction. Following Netflix’s original pivot-to-streaming (2010-2011) and move into original content (2013 House of Cards), Netflix has defined a new type of media company that leverages an enormous library of licensed and original content in a bid to capture as much viewing time as possible. For years, Netflix’s actual viewership data was a closely guarded secret, but in recent years, two factors have forced Netflix to be more transparent:

  • The rise of an advertising tier: advertisers want to know how many people are likely to actually see their ads and to know which shows drive the most eyeballs
  • The development of profit participation for creators: historically, Hollywood allowed creatives to own some of the equity in their products, so more successful productions would lead to higher pay on the backend. Netflix resisted this model for a long time-preferring to provide larger ‘up-front’ payments to talent-but recent pressure from the creative community has forced Netflix to relent. In order to ensure that creators receive fair and accurate backend compensation, Netflix has had to share data with the larger Hollywood community.

To make this data available, Netflix has published a “What We Watched” report every six months starting in 2023.1 These WWW reports aggregate total global viewership for almost the entire Netflix catalog over six month periods.2 Netflix has argued that these statistics show the depth and success of their programming, but they have also recently announced their intent to release data less frequently and not at the same time as financial statements so you can judge for yourself.

In this mini-project, you will explore the WWW data to get a sense of what types of programming captures the bulk of Netflix watch time. Along the way, you will use your dplyr data manipulation skills and the gt package to provide sophisticated well-formatted insights. Your findings will be summarized in a “strategy memo” for Netflix senior leadership, in which you advise them on how to most effectively spend their 2027 budget to maximize leadership.

Student Responsibilities

For purposes of MPs, we are dividing the basic data analytic workflow into several major stages:

  • Data Ingest and Cleaning: Given a data source, read it into R and transform it to a reasonably useful and standardized (‘tidy’) format.
  • Data Combination and Alignment: Combine multiple data sources to enable insights not possible from a single source.
  • Descriptive Statistical Analysis: Take a data table and compute informative summary statistics from both the entire population and relevant subgroups
  • Data Visualization: Generate insightful data visualizations to spur insights not attainable from point statistics
  • Inferential Statistical Analysis and Modeling: Develop relevant predictive models and statistical analyses to generate insights about the underlying population and not simply the data at hand.

In this course, our primary focus is on the first four stages: you will take other courses that develop analytical and modeling techniques for a variety of data types. As we progress through the course, you will eventually be responsible for the first four steps. Specifically, you are responsible for the following stages of each mini-project:

Students’ Responsibilities in Mini-Project Analyses
Ingest and Cleaning Combination and Alignment Descriptive Statistical Analysis Visualization
Mini-Project #01 ✓
Mini-Project #02 ✓ ✓ ½
Mini-Project #03 ½ ✓ ✓ ✓
Mini-Project #04 ✓ ✓ ✓ ✓

In early stages of the course, such as this MP, I will ‘scaffold’ much of the analysis for you, leaving only those stages we have discussed in class for you to fill in. As the course progresses, the mini-projects will be more self-directed and results less standardized.

Rubric

STA 9750 Mini-Projects are evaluated using peer grading with meta-review by the course staff (GTAs and the instructor). The following basic rubric will be used for all mini-projects:

Course Element Excellent (9-10) Great (7-8) Good (5-6) Adequate (3-4) Needs Improvement (1-2)
Written Communication Report is very well-written and flows naturally. Motivation for key steps is clearly explained to reader without excessive detail. Key findings are highlighted and appropriately given sufficient context, including reference to related work where appropriate. Report has no grammatical or writing issues.3 Writing is accessible and flows naturally. Key findings are highlighted and clearly explained, but lack suitable motivation and context. Report has no grammatical or writing issues. Key findings are present but insufficiently highlighted or unclearly explained. Writing is intelligible, but has some grammatical errors. Key findings are difficult to discern. Report exhibits significant weakness in written communication. Key points are nearly impossible to identify.
Project Skeleton Code completes all instructor-provided tasks correctly. Responses to open-ended tasks are especially insightful and creative. Code completes all instructor-provided tasks satisfactorily. Responses to open-ended tasks are insightful, creative, and do not have any minor flaws. Response to one instructor provided task is skipped, incorrect, or otherwise incomplete. Responses to open-ended tasks are solid and without serious flaws. Responses to two instructor provided tasks are skipped, incorrect, or otherwise incomplete. Responses to open-ended tasks are acceptable, but have at least one serious flaw. Response to three or more instructor provided tasks are skipped, incorrect, or otherwise incomplete. Responses to open-ended tasks are seriously lacking.
Tables & Document Presentation Tables go beyond standard publication-quality formatting, using advanced features like color formatting, interactivity, or embedded visualization. Tables are well-formatted, with publication-quality selection of data to present, formatting of table contents (e.g., significant figures) and column names. Tables are well-formatted, but still have room for improvement in one of these categories: subsetting and selection of data to present, formatting of table contents (e.g., significant figures), column names. Tables lack significant ‘polish’ and need improvement in substance (filtering and down-selecting of presented data) or style. Document is difficult to read due to distracting formatting choices. Unfiltered ‘data dump’ instead of curated table. Document is illegible at points.
Data Visualization Figures go beyond standard publication-quality formatting, using advanced features like animation, interactivity, or advanced plot types implemented in ggplot2 extension packages. Figures are ‘publication-quality,’ with suitable axis labels, well-chosen structure, attractive color schemes, titles, subtitles, and captions, etc. Figures are above ‘exploratory-quality’ and reflect a moderate degree of polish, but do not reach full ‘publication-quality’ in one-to-two ways. Figures are above ‘exploratory-quality’ and reflect a moderate degree of polish, but do not reach full ‘publication-quality’ in three or more distinct ways. Figures are suitable to support claims made, but are ‘exploratory-quality,’ reflecting zero-to-minimal effort to customize and ‘polish’ beyond ggplot2 defaults.
Exploratory Data Analysis Deep and ‘story-telling’ EDA identifying non-obvious patterns that are then used to drive further analysis in support of the project. All patterns and irregularities are noted and well characterized, demonstrating mastery and deep understanding of all data sets used. Meaningful ‘story-telling’ EDA identifying non-obvious patterns in the data. Major and pinor patterns and irregularities are noted and well characterized at a level sufficient to achieve the goals of the analysis. EDA demonstrates clear understanding of all data sets used. Extensive EDA that thoroughly explores the data, but lacks narrative and does not deliver a meaningful ‘story’ to the reader. Obvious patterns or irregularities noted and well characterized, but more subtle structure may be overlooked or not fully discussed. EDA demonstrates competence and basic understanding of the data sets used. Solid EDA that identifies major structure to the data, but does not fully explore all relevant structure. Obvious patterns or irregularities ignored or missed. EDA demonstrates familiarity with high-level structure of the data sets used. Minimal EDA, covering only standard summary statistics, and providing limited insight into data patterns or irregularities. EDA fails to demonstrate familiarity with even the most basic properties of the data sets being analyzed.

Code Quality

Code is (near) flawless. Intent is clear throughout and all code is efficient, clear, and fully idiomatic.

Code passes all styler and lintr type analyses without issue.

Comments give context and structure of the analysis, not simply defining functions used in a particular line. Intent is clear throughout, but code can be minorly improved in certain sections.

Code has well-chosen variable names and basic comments. Intent is generally clear, though some sections may be messy and code may have serious clarity or efficiency issues.

Code executes properly, but is difficult to read. Intent is generally clear and code is messy or inefficient.

Code fails to execute properly.

Data Preparation Data import is fully-automated and efficient, taking care to only download from web-sources if not available locally. All data cleaning steps are fully-automated and robustly implemented, yielding a clean data set that can be widely used. Data is imported and prepared effectively, in an automated fashion with minimal hard-coding of URLs and file paths. Data cleaning is fully-automated and sufficient to address all issues relevant to the analysis at plan. Data is imported and prepared effectively, though source and destination file names are hard-coded. Data cleaning is rather manual and hard-codes most transformations. Data is imported in a manner likely to have errors. Data cleaning is insufficient and fails to address clear problems. Data is hard-coded and not imported from an external source.
Analysis and Findings Analysis demonstrates uncommon insight and quality, providing unexpected and subtle insights. Analysis is clear and convincing, leaving essentially no doubts about correctness. Analysis clearly appears to be correct and passes the “sniff test” for all findings, but a detailed review notes some questions remain unanswered. Analysis is not clearly flawed at any point and is likely to be within the right order of magnitude for all findings. Analysis is clearly incorrect in at least one major finding, reporting clearly implausible results that are likely off by an order of magnitude or more.

Note that the “Excellent” category for most elements applies only to truly exceptional “above-and-beyond” work. Most student submissions will likely fall in the “Good” to “Great” range.

At this early point, you are not responsible for all elements of this rubric. In particular, all submissions will receive an automatic 10/10 for Data Visualization as this is outside the scope of this mini-project. Furthermore, because I am providing code to download the data, load it into R, and prepare it for analysis, all reports submitted using my code will receive an automatic 10/10 for the ‘Data Preparation’ element of the rubric. Finally, reports completing all tasks described under Data Integration and Exploration below should receive a 10/10 for the ‘Exploratory Data Analysis’ rubric element.

Taken together, you are only really responsible for these portions of the rubric:

  • Written Communication
  • Project Skeleton
  • Tables & Document Presentation
  • Code Quality
  • Analysis and Findings

Reports completing all key steps outlined below essentially start with 30 free points. Note however that you must submit this assignment to get these points: no points are given for submitting nothing, but it’s worth submitting something even if you do not have a fully complete and polished assignment.

Data Visualization;Exploratory Data Analysis;Data Preparation
WarningWriting Requirements

Note that you are evaluated on writing and communication in these Mini-Projects. You are required to write a report in the prescribed style, culminating in an Op-Ed. A submission that performs the instructor-specified tasks, but does not write and give appropriate context and commentary will score very poorly on the relevant rubric elements.

In particular, if a submission does not include a clearly delineated Op-Ed and only answers the instructor prompts in narrative text, peer evaluators should judge it to have “Good” quality Written Communication (at best) as key findings are not conveyed appropriately.

Quarto’s code folding functionality is useful for “hiding” code so that it doesn’t break the flow of your writing.

You can also make use of Quarto’s contents shortcode to present code and findings in an order other than how the code should be executed. This is particularly useful if you want to include a figure or table in an “Executive Summary” at the top of your submission.

For this mini-project, no more than 4 total points of extra credit can be be awarded. Opportunities for extra credit exist for students who go above and beyond the instructor-provided scaffolding. Specific opportunities for extra credit can be found below.

Students pursuing careers in data analytics are strongly encouraged to go beyond the strict ambit of the mini-projects to

  1. further refine their skills;
  2. learn additional techniques that can be used in the final course project; and
  3. develop a more impressive professional portfolio.

Because students are encouraged to use STA 9750 mini-projects as the basis for a professional portfolio, the basic skeleton of each project will be released under a fairly permissive usage license. Take advantage of it!

Submission Instructions

After completing the analysis, write up your findings, showing all of your code, using a dynamic quarto document and post it to your course repository. The qmd file should be named mp01.qmd (lower case!) so the rendered document can be found at docs/mp01.html in the student’s repository and will be served at the URL:4

https://YOUR_GITHUB_ID.github.io/STA9750-2026-FALL/mp01.html

You can use the helper function mp_start available at in the Course Helper Functions to create a file with the appropriate name and some meta-data already included. Do so by running the following command at the R Console:

source("https://michael-weylandt.com/STA9750/load_helpers.R"); mp_start(N=01)

After completing this mini-project, upload your rendered output and necessary ancillary files to GitHub to make sure your site works. The mp_submission_ready function in the Course Helper Functions can perform some of these checks automatically. You can run this function by running the following commands at the R Console:

source("https://michael-weylandt.com/STA9750/load_helpers.R"); mp_submission_ready(N=01)

Once you confirm this website works (substituting YOUR_GITHUB_ID for the actual GitHub username provided to the professor in MP#00 of course), open a GitHub issue on the instructor’s repository to submit your completed work.

The easiest way to do so is by use of the mp_submission_create function in the Course Helper Functions, which can be used by running the following command at the R Console:

source("https://michael-weylandt.com/STA9750/load_helpers.R"); mp_submission_create(N=01)

Alternatively, if you wish to submit manually, open a new issue at

https://github.com/michaelweylandt/STA9750-2026-FALL/issues/new .

Title the issue STA 9750 YOUR_GITHUB_ID MiniProject #01 and fill in the following text for the issue:

Hi @michaelweylandt!

I've uploaded my work for MiniProject #**01** - check it out!

<https://YOUR_GITHUB_ID.github.io/STA9750-2026-FALL/mp01.html>

At various points before and after the submission deadline, the instructor will run some automated checks to ensure your submission has all necessary components. Please respond to any issues raised in a timely fashion as failing to address them may lead to a lower set of scores when graded.

Additionally, a PDF export of this report should be submitted on Brightspace. To create a PDF from the uploaded report, simply use your browser’s ‘Print to PDF’ functionality.

NB: The analysis outline below specifies key tasks you need to perform within your write up. Your peer evaluators will check that you complete these. You are encouraged to do extra analysis, but the bolded Tasks are mandatory.

NB: Your final submission should look like a report, not simply a list of facts answering questions. Add introductions, conclusions, and your own commentary. You should be practicing both raw coding skills and written communication in all mini-projects. There is little value in data points stated without context or motivation.

Mini-Project #01: What We Watched: Exploring Netflix Viewing Data

Data Acquisition

The following code can be used to acquire data from Netflix’s corporate relations website. Specifically, once run, this code will download and aggregate the previous seven WWW reports (first-half 2023 2023H1 to first-half 2026 2026H1). Netflix provides slightly different data from each report, so this function standardizes on a small set of key features including: the ‘watch window’, the title of the program, the runtime, the total hours viewed, the original release date of the program, whether the program is available in all countries in which Netflix is available, and whether the program is pre-recorded or live.

To be efficient, this function will save a copy of the downloaded data in a folder called data/mp01 and use that copy to avoid re-downloading a file if it is already present on your computer. This will make your code faster to run and will avoid putting unnecessary stress on the Netflix servers.

#' Acquire Netflix What We Watched Reports
#' 
#' This function will acquire and standardize all data for MP#01
#' from Netflix. Because Netflix hosts the data files behind a CDN, we
#' are accessing the release pages and automatically extracting links to the
#' relevant files (with CDN hash). 
#' 
#' After import, files are stacked vertically and some basic cleaning is
#' performed. 
load_netflix_data <- function(){
  # Note to students: Make sure you have installed the tidyverse and fs packages
  #                   before beginning this assignment. If you aren't sure,
  #                   simply run `library(tidyverse)` at your R Console and, if
  #                   you don't see an error message, `tidyverse` has been 
  #                   installed. (Same for `fs`) If you still need to install
  #                   either package, use the `install.packages` function as 
  #                   demonstrated in class.
  library(tidyverse)
  library(rvest)
  library(readxl)
  library(fs)
  
  data_dir <- path("data", "mp01")
    
  if(!dir_exists(data_dir)){
    dir_create(data_dir, showWarnings=FALSE, recurse=TRUE)
  }
  
  NETFLIX_URLS <- list(
    `2023H1` = "https://about.netflix.com/news/what-we-watched-a-netflix-engagement-report",
    `2023H2` = "https://about.netflix.com/news/what-we-watched-the-second-half-of-2023",
    `2024H1` = "https://about.netflix.com/news/what-we-watched-the-first-half-of-2024",
    `2024H2` = "https://about.netflix.com/news/what-we-watched-the-second-half-of-2024",
    `2025H1` = "https://about.netflix.com/news/what-we-watched-the-first-half-of-2025",
    `2025H2` = "https://about.netflix.com/news/what-we-watched-the-second-half-of-2025",
    `2026H1` = "https://about.netflix.com/news/what-we-watched-the-first-half-of-2026"
  )
  
  download_if_needed <- function(url, local){
    if(!file_exists(local)){
      download.file(url, local, quiet = TRUE, mode = "wb")
    }
    
    return(local)
  }
    
  NETFLIX_URLS |> 
    map(read_html) |> 
    map(html_element, xpath = "//a[contains(@href, '.xlsx')]") |> 
    map_chr(html_attr, "href") |> 
    enframe("period", "url") |> 
   mutate(path = path(data_dir, paste0(period, ".xlsx")), 
          path = map2(url, path, download_if_needed), 
          data = map(path, read_excel, skip=3, na="*"), 
          data = map(data, \(x) x |> mutate(`Release Date` = as.Date(`Release Date`)))) |>
    unnest(data) |> 
    select(-url, -path) |> 
    mutate(year=str_sub(period, 1, 4), 
           half=str_sub(period, start=6), 
           period_start = make_date(year, if_else(half==1, 1, 7), 1), 
           period_end = make_date(year, if_else(half==1, 7, 12), if_else(half==1, 30, 31))) |> 
    filter(!is.na(`Hours Viewed`)) |> 
    mutate(live_event = !is.na(Runtime) & str_detect(Runtime, "\\d+:\\d+\\*"), 
           clean_time = str_remove(Runtime, fixed("*")),
           Runtime = 60 * hour(hm(clean_time)) + minute(hm(clean_time))) |>
    select(-clean_time) |>
    mutate(Runtime = coalesce(Runtime, mean(Runtime, na.rm=TRUE)), 
           .by=Title, 
           Title = stringi::stri_trans_general(Title, "Latin-ASCII"),
           Title = str_remove(Title, " // .*"), 
           Title = str_remove(Title, "[^[:ascii:]].*"), 
           Title = str_trim(Title)) |>
    filter_out(Title == "") |>
    select(year, 
           period, 
           period_start, 
           period_end, 
           Title, 
           -half, 
           Runtime, 
           Views, 
           `Hours Viewed`, 
           `Release Date`,
           `Available Globally?`, 
           live_event)
}

NETFLIX_DATA <- load_netflix_data()

This creates a data frame called NETFLIX_DATA that has 61892 rows and 11 columns in your local environment. This data will be used for the remainder of this mini-project.

TipTask 1: Data Acquisition

Using the code above, acquire the Netflix “What We Watched” data. Copy the code into your Quarto document and make sure it runs successfully.

CautionDo Not git add Data Files

Make sure that git is set to ignore data files, such as the one created above. Check the git pane in RStudio and make sure that the files in data/mp01 do not appear. (If you set up your .gitignore file correctly in MP#00, it should already be ignored.) If it is appearing, you may need to edit your .gitignore file.

Removing a large data file from git is possible, but difficult. Don’t get into a bad state!

Data Cleaning and Preparation

The Netflix “What We Watched” reports provide a high-level view of Netflix’s internal viewership data. While still interesting for our analysis, this data has several limitations, you keep in mind throughout this Mini-Project. I note some of them below in the description of each column.

The NETFLIX_DATA from above has several columns:

  • year, period, period_start, and period_end. These reflect the period over which the viewership data was aggregated, e.g., 2024H1 refers to the first half of 2024 (January 1, 2024 to June 30, 2024). I have created the period_start and period_end columns as dates which may be more useful for filtering and comparing against the published release dates.
  • Title. The title of the show or movie, roughly standardized.5 Note that Netflix is a bit inconsistent in how it represents different seasons of TV shows; we have Seinfeld: Season 1 and Seinfeld: Season 3, but Stranger Things and Stranger Things 3.
  • Runtime. The run time in minutes of the show or movie (aggregated across all episodes for a show). It is not clear why certain catalog entries do not have a published run time (e.g., Season 1 of Suits has no run time, but later seasons do). Here, we can only work with what Netflix gives us.
  • Hours Viewed. The global aggregate view time (in hours) during the period for that title. Note that this seems to be rounded to the nearest 100,000 hours and low viewership shows (those with less than 50,000 hours of view time) are omitted. This makes it hard to compare the popularity of two not-so popular shows, but we can still make some sense of major titles.
  • Views. The approximate number of views, again rounded. Note that these are “implied views” (computed by dividing Hours Viewed by Runtime) that assume all viewers watched a title in its entirety. This measure of Views cannot distinguish 600 people watching 10 minutes of a show and turning it off from one person watching the entirety of a 100 hour documentary.6
  • Release Date: The date on which a title was released. This is inconsistently available and should be used with caution.
  • Available Globally?: Was this title available in all Netflix territories (typical for Netflix Originals) or only in certain territories (typical for content made available under license from a different creator).
  • live_event: Was the title a live sporting event (a new area of focus for Netflix)?

Before we can begin to look more closely at this data, we have a little bit more clean-up we need to complete to get this data in its most usable form.

One requirement for data to be easily manipulated is easy column names. Since we use base column names in many tidyverse functions, including all of the dplyr functions we have covered to this point, we want to ensure that our column names are valid R variable names and easily typed. This means that we want:

  • Only numbers and simple letters, no punctuation or accents
  • Starting with a letter
  • All lower-case
  • If multi-word, separated by underscores (_) not spaces

So a column name like Flipper Length (mm) will be hard to work with, while one like flipper_length_mm will be fine.7 Compare the column names of the penguins data set, which have been “tidied up” for easy use, to those of the penguins_raw which reflect the original data source.

To get nice tidy names, we will use the rename() function from the dplyr package. The rename() function works similarly to the mutate function, but we can only rename and cannot perform transformations. This might seem like a limitation, but it makes the point of our code clearer.

The rename function works like this:

library(tidyverse)
iris |>
  rename(petal_length = Petal.Length, 
         petal_width  = Petal.Width, 
         ...)

Each argument is a pair of the form NEW_NAME = OLD_NAME and, by adding more names in the ..., we can perform even more renamings at once. If the old names are sufficiently nasty that they are not even valid (but ugly) names, we need to surround them with backticks (`), such as:

library(tidyverse)
iris |>
  rename(petal_length = `Petal.Length`, # Note backticks around old names
         petal_width  = `Petal.Width`, 
         ...)

Anything placed between two backticks will be interpreted as a name.

TipTask 2: Fix Column Titles

Modify the code you copied in Task 1 to ensure that we have nice “tidy” column names satisfying the four rules listed above.

You can do this by either:

  1. Adding a rename() step to the end of the pipeline in my acquire_netflix_data() function. (Recommended)
  2. Adding a rename() line after my acquire_netflix_data() function. (If you do this, make sure to assign your modified data back into a variable.)

Additionally, we want to make sure our data is all reasonably typed. I have done most of the clean-up work for you and only two columns need to be modified. Because you are actually changing the values from one type to another, we have to actually use the mutate() function, and not rename(), but this idiom will work well:

data |>
  mutate(column = some_function(column))

Here, the new column is created by calling a function (some_function) but then assigned back to the old name, having the effect of changing the column’s values in place.

TipTask 3: Fix Column Types

To proceed, we need to fix the year column and the Available Globally? column (which will have a slightly different name after Task 2).

The year column is rather easy. Right now, it is string values (“2023”, “2024”, etc.) but we want to convert these to numbers so that they can be used as such. This is a simple “like-for-like” change that can be done with the as.integer() (or as.numeric()) coercion function.

The global availability column requires a bit more care At the end of my code, it consists of the string values "Yes" and "No", but we would really like to use logical TRUE / FALSE values. Unfortunately, the as.logical() function does not do what we want here:

as.logical("Yes") # We want TRUE
[1] NA

Instead, we want to use a vectorized check to see whether the value is "Yes", in which case we will convert to TRUE, or something else that will be converted to FALSE.

Complete the following code snippet to perform these two conversions:

|> mutate(
  ... = as.integer(...), 
  ... = ... == ... # Recall that double equals (==) checks for equality
)

As in the previous task, either insert your code into the end of my acquire_netflix_data() function or call it on the output of my code.

Initial Data Exploration

Before moving to our final analysis, we will do a bit of Exploratory Data Analysis (EDA). EDA serves many purposes in data science– quality control, hypothesis generation, outlier identification, etc.–but perhaps the most important is simply knowing what information can be found in a novel data set. Now that our data is imported and cleaned, it’s almost time to start our EDA. Before we do EDA, however, we should pause briefly to think about how we want to display data.

Displaying Data in Tables

While we could continue investigating our data using R’s basic print-outs, this is a good time to introduce the gt package which can be used to create complex tables natively in R.

What follows here is a very brief introduction to the gt package. You do not need to copy this into your submission - it is provided only as background. You will use the gt package to format your answers to the next few tasks. Click on the blue bar below to read the introduction to gt.

NoteMaking Attractive Tables in R

For this introduction, I am going to use the penguins data, but the same functions can be applied to any data that you are analyzing.

Let’s first look at what a “basic” or “raw” display of a data frame gives us:

penguins
      species    island bill_len bill_dep flipper_len body_mass    sex year
1      Adelie Torgersen     39.1     18.7         181      3750   male 2007
2      Adelie Torgersen     39.5     17.4         186      3800 female 2007
3      Adelie Torgersen     40.3     18.0         195      3250 female 2007
4      Adelie Torgersen       NA       NA          NA        NA   <NA> 2007
5      Adelie Torgersen     36.7     19.3         193      3450 female 2007
6      Adelie Torgersen     39.3     20.6         190      3650   male 2007
7      Adelie Torgersen     38.9     17.8         181      3625 female 2007
8      Adelie Torgersen     39.2     19.6         195      4675   male 2007
9      Adelie Torgersen     34.1     18.1         193      3475   <NA> 2007
10     Adelie Torgersen     42.0     20.2         190      4250   <NA> 2007
11     Adelie Torgersen     37.8     17.1         186      3300   <NA> 2007
12     Adelie Torgersen     37.8     17.3         180      3700   <NA> 2007
13     Adelie Torgersen     41.1     17.6         182      3200 female 2007
14     Adelie Torgersen     38.6     21.2         191      3800   male 2007
15     Adelie Torgersen     34.6     21.1         198      4400   male 2007
16     Adelie Torgersen     36.6     17.8         185      3700 female 2007
17     Adelie Torgersen     38.7     19.0         195      3450 female 2007
18     Adelie Torgersen     42.5     20.7         197      4500   male 2007
19     Adelie Torgersen     34.4     18.4         184      3325 female 2007
20     Adelie Torgersen     46.0     21.5         194      4200   male 2007
21     Adelie    Biscoe     37.8     18.3         174      3400 female 2007
22     Adelie    Biscoe     37.7     18.7         180      3600   male 2007
23     Adelie    Biscoe     35.9     19.2         189      3800 female 2007
24     Adelie    Biscoe     38.2     18.1         185      3950   male 2007
25     Adelie    Biscoe     38.8     17.2         180      3800   male 2007
26     Adelie    Biscoe     35.3     18.9         187      3800 female 2007
27     Adelie    Biscoe     40.6     18.6         183      3550   male 2007
28     Adelie    Biscoe     40.5     17.9         187      3200 female 2007
29     Adelie    Biscoe     37.9     18.6         172      3150 female 2007
30     Adelie    Biscoe     40.5     18.9         180      3950   male 2007
31     Adelie     Dream     39.5     16.7         178      3250 female 2007
32     Adelie     Dream     37.2     18.1         178      3900   male 2007
33     Adelie     Dream     39.5     17.8         188      3300 female 2007
34     Adelie     Dream     40.9     18.9         184      3900   male 2007
35     Adelie     Dream     36.4     17.0         195      3325 female 2007
36     Adelie     Dream     39.2     21.1         196      4150   male 2007
37     Adelie     Dream     38.8     20.0         190      3950   male 2007
38     Adelie     Dream     42.2     18.5         180      3550 female 2007
39     Adelie     Dream     37.6     19.3         181      3300 female 2007
40     Adelie     Dream     39.8     19.1         184      4650   male 2007
41     Adelie     Dream     36.5     18.0         182      3150 female 2007
42     Adelie     Dream     40.8     18.4         195      3900   male 2007
43     Adelie     Dream     36.0     18.5         186      3100 female 2007
44     Adelie     Dream     44.1     19.7         196      4400   male 2007
45     Adelie     Dream     37.0     16.9         185      3000 female 2007
46     Adelie     Dream     39.6     18.8         190      4600   male 2007
47     Adelie     Dream     41.1     19.0         182      3425   male 2007
48     Adelie     Dream     37.5     18.9         179      2975   <NA> 2007
49     Adelie     Dream     36.0     17.9         190      3450 female 2007
50     Adelie     Dream     42.3     21.2         191      4150   male 2007
51     Adelie    Biscoe     39.6     17.7         186      3500 female 2008
52     Adelie    Biscoe     40.1     18.9         188      4300   male 2008
53     Adelie    Biscoe     35.0     17.9         190      3450 female 2008
54     Adelie    Biscoe     42.0     19.5         200      4050   male 2008
55     Adelie    Biscoe     34.5     18.1         187      2900 female 2008
56     Adelie    Biscoe     41.4     18.6         191      3700   male 2008
57     Adelie    Biscoe     39.0     17.5         186      3550 female 2008
58     Adelie    Biscoe     40.6     18.8         193      3800   male 2008
59     Adelie    Biscoe     36.5     16.6         181      2850 female 2008
60     Adelie    Biscoe     37.6     19.1         194      3750   male 2008
61     Adelie    Biscoe     35.7     16.9         185      3150 female 2008
62     Adelie    Biscoe     41.3     21.1         195      4400   male 2008
63     Adelie    Biscoe     37.6     17.0         185      3600 female 2008
64     Adelie    Biscoe     41.1     18.2         192      4050   male 2008
65     Adelie    Biscoe     36.4     17.1         184      2850 female 2008
66     Adelie    Biscoe     41.6     18.0         192      3950   male 2008
67     Adelie    Biscoe     35.5     16.2         195      3350 female 2008
68     Adelie    Biscoe     41.1     19.1         188      4100   male 2008
69     Adelie Torgersen     35.9     16.6         190      3050 female 2008
70     Adelie Torgersen     41.8     19.4         198      4450   male 2008
71     Adelie Torgersen     33.5     19.0         190      3600 female 2008
72     Adelie Torgersen     39.7     18.4         190      3900   male 2008
73     Adelie Torgersen     39.6     17.2         196      3550 female 2008
74     Adelie Torgersen     45.8     18.9         197      4150   male 2008
75     Adelie Torgersen     35.5     17.5         190      3700 female 2008
76     Adelie Torgersen     42.8     18.5         195      4250   male 2008
77     Adelie Torgersen     40.9     16.8         191      3700 female 2008
78     Adelie Torgersen     37.2     19.4         184      3900   male 2008
79     Adelie Torgersen     36.2     16.1         187      3550 female 2008
80     Adelie Torgersen     42.1     19.1         195      4000   male 2008
81     Adelie Torgersen     34.6     17.2         189      3200 female 2008
82     Adelie Torgersen     42.9     17.6         196      4700   male 2008
83     Adelie Torgersen     36.7     18.8         187      3800 female 2008
84     Adelie Torgersen     35.1     19.4         193      4200   male 2008
85     Adelie     Dream     37.3     17.8         191      3350 female 2008
86     Adelie     Dream     41.3     20.3         194      3550   male 2008
87     Adelie     Dream     36.3     19.5         190      3800   male 2008
88     Adelie     Dream     36.9     18.6         189      3500 female 2008
89     Adelie     Dream     38.3     19.2         189      3950   male 2008
90     Adelie     Dream     38.9     18.8         190      3600 female 2008
91     Adelie     Dream     35.7     18.0         202      3550 female 2008
92     Adelie     Dream     41.1     18.1         205      4300   male 2008
93     Adelie     Dream     34.0     17.1         185      3400 female 2008
94     Adelie     Dream     39.6     18.1         186      4450   male 2008
95     Adelie     Dream     36.2     17.3         187      3300 female 2008
96     Adelie     Dream     40.8     18.9         208      4300   male 2008
97     Adelie     Dream     38.1     18.6         190      3700 female 2008
98     Adelie     Dream     40.3     18.5         196      4350   male 2008
99     Adelie     Dream     33.1     16.1         178      2900 female 2008
100    Adelie     Dream     43.2     18.5         192      4100   male 2008
101    Adelie    Biscoe     35.0     17.9         192      3725 female 2009
102    Adelie    Biscoe     41.0     20.0         203      4725   male 2009
103    Adelie    Biscoe     37.7     16.0         183      3075 female 2009
104    Adelie    Biscoe     37.8     20.0         190      4250   male 2009
105    Adelie    Biscoe     37.9     18.6         193      2925 female 2009
106    Adelie    Biscoe     39.7     18.9         184      3550   male 2009
107    Adelie    Biscoe     38.6     17.2         199      3750 female 2009
108    Adelie    Biscoe     38.2     20.0         190      3900   male 2009
109    Adelie    Biscoe     38.1     17.0         181      3175 female 2009
110    Adelie    Biscoe     43.2     19.0         197      4775   male 2009
111    Adelie    Biscoe     38.1     16.5         198      3825 female 2009
112    Adelie    Biscoe     45.6     20.3         191      4600   male 2009
113    Adelie    Biscoe     39.7     17.7         193      3200 female 2009
114    Adelie    Biscoe     42.2     19.5         197      4275   male 2009
115    Adelie    Biscoe     39.6     20.7         191      3900 female 2009
116    Adelie    Biscoe     42.7     18.3         196      4075   male 2009
117    Adelie Torgersen     38.6     17.0         188      2900 female 2009
118    Adelie Torgersen     37.3     20.5         199      3775   male 2009
119    Adelie Torgersen     35.7     17.0         189      3350 female 2009
120    Adelie Torgersen     41.1     18.6         189      3325   male 2009
121    Adelie Torgersen     36.2     17.2         187      3150 female 2009
122    Adelie Torgersen     37.7     19.8         198      3500   male 2009
123    Adelie Torgersen     40.2     17.0         176      3450 female 2009
124    Adelie Torgersen     41.4     18.5         202      3875   male 2009
125    Adelie Torgersen     35.2     15.9         186      3050 female 2009
126    Adelie Torgersen     40.6     19.0         199      4000   male 2009
127    Adelie Torgersen     38.8     17.6         191      3275 female 2009
128    Adelie Torgersen     41.5     18.3         195      4300   male 2009
129    Adelie Torgersen     39.0     17.1         191      3050 female 2009
130    Adelie Torgersen     44.1     18.0         210      4000   male 2009
131    Adelie Torgersen     38.5     17.9         190      3325 female 2009
132    Adelie Torgersen     43.1     19.2         197      3500   male 2009
133    Adelie     Dream     36.8     18.5         193      3500 female 2009
134    Adelie     Dream     37.5     18.5         199      4475   male 2009
135    Adelie     Dream     38.1     17.6         187      3425 female 2009
136    Adelie     Dream     41.1     17.5         190      3900   male 2009
137    Adelie     Dream     35.6     17.5         191      3175 female 2009
138    Adelie     Dream     40.2     20.1         200      3975   male 2009
139    Adelie     Dream     37.0     16.5         185      3400 female 2009
140    Adelie     Dream     39.7     17.9         193      4250   male 2009
141    Adelie     Dream     40.2     17.1         193      3400 female 2009
142    Adelie     Dream     40.6     17.2         187      3475   male 2009
143    Adelie     Dream     32.1     15.5         188      3050 female 2009
144    Adelie     Dream     40.7     17.0         190      3725   male 2009
145    Adelie     Dream     37.3     16.8         192      3000 female 2009
146    Adelie     Dream     39.0     18.7         185      3650   male 2009
147    Adelie     Dream     39.2     18.6         190      4250   male 2009
148    Adelie     Dream     36.6     18.4         184      3475 female 2009
149    Adelie     Dream     36.0     17.8         195      3450 female 2009
150    Adelie     Dream     37.8     18.1         193      3750   male 2009
151    Adelie     Dream     36.0     17.1         187      3700 female 2009
152    Adelie     Dream     41.5     18.5         201      4000   male 2009
153    Gentoo    Biscoe     46.1     13.2         211      4500 female 2007
154    Gentoo    Biscoe     50.0     16.3         230      5700   male 2007
155    Gentoo    Biscoe     48.7     14.1         210      4450 female 2007
156    Gentoo    Biscoe     50.0     15.2         218      5700   male 2007
157    Gentoo    Biscoe     47.6     14.5         215      5400   male 2007
158    Gentoo    Biscoe     46.5     13.5         210      4550 female 2007
159    Gentoo    Biscoe     45.4     14.6         211      4800 female 2007
160    Gentoo    Biscoe     46.7     15.3         219      5200   male 2007
161    Gentoo    Biscoe     43.3     13.4         209      4400 female 2007
162    Gentoo    Biscoe     46.8     15.4         215      5150   male 2007
163    Gentoo    Biscoe     40.9     13.7         214      4650 female 2007
164    Gentoo    Biscoe     49.0     16.1         216      5550   male 2007
165    Gentoo    Biscoe     45.5     13.7         214      4650 female 2007
166    Gentoo    Biscoe     48.4     14.6         213      5850   male 2007
167    Gentoo    Biscoe     45.8     14.6         210      4200 female 2007
168    Gentoo    Biscoe     49.3     15.7         217      5850   male 2007
169    Gentoo    Biscoe     42.0     13.5         210      4150 female 2007
170    Gentoo    Biscoe     49.2     15.2         221      6300   male 2007
171    Gentoo    Biscoe     46.2     14.5         209      4800 female 2007
172    Gentoo    Biscoe     48.7     15.1         222      5350   male 2007
173    Gentoo    Biscoe     50.2     14.3         218      5700   male 2007
174    Gentoo    Biscoe     45.1     14.5         215      5000 female 2007
175    Gentoo    Biscoe     46.5     14.5         213      4400 female 2007
176    Gentoo    Biscoe     46.3     15.8         215      5050   male 2007
177    Gentoo    Biscoe     42.9     13.1         215      5000 female 2007
178    Gentoo    Biscoe     46.1     15.1         215      5100   male 2007
179    Gentoo    Biscoe     44.5     14.3         216      4100   <NA> 2007
180    Gentoo    Biscoe     47.8     15.0         215      5650   male 2007
181    Gentoo    Biscoe     48.2     14.3         210      4600 female 2007
182    Gentoo    Biscoe     50.0     15.3         220      5550   male 2007
183    Gentoo    Biscoe     47.3     15.3         222      5250   male 2007
184    Gentoo    Biscoe     42.8     14.2         209      4700 female 2007
185    Gentoo    Biscoe     45.1     14.5         207      5050 female 2007
186    Gentoo    Biscoe     59.6     17.0         230      6050   male 2007
187    Gentoo    Biscoe     49.1     14.8         220      5150 female 2008
188    Gentoo    Biscoe     48.4     16.3         220      5400   male 2008
189    Gentoo    Biscoe     42.6     13.7         213      4950 female 2008
190    Gentoo    Biscoe     44.4     17.3         219      5250   male 2008
191    Gentoo    Biscoe     44.0     13.6         208      4350 female 2008
192    Gentoo    Biscoe     48.7     15.7         208      5350   male 2008
193    Gentoo    Biscoe     42.7     13.7         208      3950 female 2008
194    Gentoo    Biscoe     49.6     16.0         225      5700   male 2008
195    Gentoo    Biscoe     45.3     13.7         210      4300 female 2008
196    Gentoo    Biscoe     49.6     15.0         216      4750   male 2008
197    Gentoo    Biscoe     50.5     15.9         222      5550   male 2008
198    Gentoo    Biscoe     43.6     13.9         217      4900 female 2008
199    Gentoo    Biscoe     45.5     13.9         210      4200 female 2008
200    Gentoo    Biscoe     50.5     15.9         225      5400   male 2008
201    Gentoo    Biscoe     44.9     13.3         213      5100 female 2008
202    Gentoo    Biscoe     45.2     15.8         215      5300   male 2008
203    Gentoo    Biscoe     46.6     14.2         210      4850 female 2008
204    Gentoo    Biscoe     48.5     14.1         220      5300   male 2008
205    Gentoo    Biscoe     45.1     14.4         210      4400 female 2008
206    Gentoo    Biscoe     50.1     15.0         225      5000   male 2008
207    Gentoo    Biscoe     46.5     14.4         217      4900 female 2008
208    Gentoo    Biscoe     45.0     15.4         220      5050   male 2008
209    Gentoo    Biscoe     43.8     13.9         208      4300 female 2008
210    Gentoo    Biscoe     45.5     15.0         220      5000   male 2008
211    Gentoo    Biscoe     43.2     14.5         208      4450 female 2008
212    Gentoo    Biscoe     50.4     15.3         224      5550   male 2008
213    Gentoo    Biscoe     45.3     13.8         208      4200 female 2008
214    Gentoo    Biscoe     46.2     14.9         221      5300   male 2008
215    Gentoo    Biscoe     45.7     13.9         214      4400 female 2008
216    Gentoo    Biscoe     54.3     15.7         231      5650   male 2008
217    Gentoo    Biscoe     45.8     14.2         219      4700 female 2008
218    Gentoo    Biscoe     49.8     16.8         230      5700   male 2008
219    Gentoo    Biscoe     46.2     14.4         214      4650   <NA> 2008
220    Gentoo    Biscoe     49.5     16.2         229      5800   male 2008
221    Gentoo    Biscoe     43.5     14.2         220      4700 female 2008
222    Gentoo    Biscoe     50.7     15.0         223      5550   male 2008
223    Gentoo    Biscoe     47.7     15.0         216      4750 female 2008
224    Gentoo    Biscoe     46.4     15.6         221      5000   male 2008
225    Gentoo    Biscoe     48.2     15.6         221      5100   male 2008
226    Gentoo    Biscoe     46.5     14.8         217      5200 female 2008
227    Gentoo    Biscoe     46.4     15.0         216      4700 female 2008
228    Gentoo    Biscoe     48.6     16.0         230      5800   male 2008
229    Gentoo    Biscoe     47.5     14.2         209      4600 female 2008
230    Gentoo    Biscoe     51.1     16.3         220      6000   male 2008
231    Gentoo    Biscoe     45.2     13.8         215      4750 female 2008
232    Gentoo    Biscoe     45.2     16.4         223      5950   male 2008
233    Gentoo    Biscoe     49.1     14.5         212      4625 female 2009
234    Gentoo    Biscoe     52.5     15.6         221      5450   male 2009
235    Gentoo    Biscoe     47.4     14.6         212      4725 female 2009
236    Gentoo    Biscoe     50.0     15.9         224      5350   male 2009
237    Gentoo    Biscoe     44.9     13.8         212      4750 female 2009
238    Gentoo    Biscoe     50.8     17.3         228      5600   male 2009
239    Gentoo    Biscoe     43.4     14.4         218      4600 female 2009
240    Gentoo    Biscoe     51.3     14.2         218      5300   male 2009
241    Gentoo    Biscoe     47.5     14.0         212      4875 female 2009
242    Gentoo    Biscoe     52.1     17.0         230      5550   male 2009
243    Gentoo    Biscoe     47.5     15.0         218      4950 female 2009
244    Gentoo    Biscoe     52.2     17.1         228      5400   male 2009
245    Gentoo    Biscoe     45.5     14.5         212      4750 female 2009
246    Gentoo    Biscoe     49.5     16.1         224      5650   male 2009
247    Gentoo    Biscoe     44.5     14.7         214      4850 female 2009
248    Gentoo    Biscoe     50.8     15.7         226      5200   male 2009
249    Gentoo    Biscoe     49.4     15.8         216      4925   male 2009
250    Gentoo    Biscoe     46.9     14.6         222      4875 female 2009
251    Gentoo    Biscoe     48.4     14.4         203      4625 female 2009
252    Gentoo    Biscoe     51.1     16.5         225      5250   male 2009
253    Gentoo    Biscoe     48.5     15.0         219      4850 female 2009
254    Gentoo    Biscoe     55.9     17.0         228      5600   male 2009
255    Gentoo    Biscoe     47.2     15.5         215      4975 female 2009
256    Gentoo    Biscoe     49.1     15.0         228      5500   male 2009
257    Gentoo    Biscoe     47.3     13.8         216      4725   <NA> 2009
258    Gentoo    Biscoe     46.8     16.1         215      5500   male 2009
259    Gentoo    Biscoe     41.7     14.7         210      4700 female 2009
260    Gentoo    Biscoe     53.4     15.8         219      5500   male 2009
261    Gentoo    Biscoe     43.3     14.0         208      4575 female 2009
262    Gentoo    Biscoe     48.1     15.1         209      5500   male 2009
263    Gentoo    Biscoe     50.5     15.2         216      5000 female 2009
264    Gentoo    Biscoe     49.8     15.9         229      5950   male 2009
265    Gentoo    Biscoe     43.5     15.2         213      4650 female 2009
266    Gentoo    Biscoe     51.5     16.3         230      5500   male 2009
267    Gentoo    Biscoe     46.2     14.1         217      4375 female 2009
268    Gentoo    Biscoe     55.1     16.0         230      5850   male 2009
269    Gentoo    Biscoe     44.5     15.7         217      4875   <NA> 2009
270    Gentoo    Biscoe     48.8     16.2         222      6000   male 2009
271    Gentoo    Biscoe     47.2     13.7         214      4925 female 2009
272    Gentoo    Biscoe       NA       NA          NA        NA   <NA> 2009
273    Gentoo    Biscoe     46.8     14.3         215      4850 female 2009
274    Gentoo    Biscoe     50.4     15.7         222      5750   male 2009
275    Gentoo    Biscoe     45.2     14.8         212      5200 female 2009
276    Gentoo    Biscoe     49.9     16.1         213      5400   male 2009
277 Chinstrap     Dream     46.5     17.9         192      3500 female 2007
278 Chinstrap     Dream     50.0     19.5         196      3900   male 2007
279 Chinstrap     Dream     51.3     19.2         193      3650   male 2007
280 Chinstrap     Dream     45.4     18.7         188      3525 female 2007
281 Chinstrap     Dream     52.7     19.8         197      3725   male 2007
282 Chinstrap     Dream     45.2     17.8         198      3950 female 2007
283 Chinstrap     Dream     46.1     18.2         178      3250 female 2007
284 Chinstrap     Dream     51.3     18.2         197      3750   male 2007
285 Chinstrap     Dream     46.0     18.9         195      4150 female 2007
286 Chinstrap     Dream     51.3     19.9         198      3700   male 2007
287 Chinstrap     Dream     46.6     17.8         193      3800 female 2007
288 Chinstrap     Dream     51.7     20.3         194      3775   male 2007
289 Chinstrap     Dream     47.0     17.3         185      3700 female 2007
290 Chinstrap     Dream     52.0     18.1         201      4050   male 2007
291 Chinstrap     Dream     45.9     17.1         190      3575 female 2007
292 Chinstrap     Dream     50.5     19.6         201      4050   male 2007
293 Chinstrap     Dream     50.3     20.0         197      3300   male 2007
294 Chinstrap     Dream     58.0     17.8         181      3700 female 2007
295 Chinstrap     Dream     46.4     18.6         190      3450 female 2007
296 Chinstrap     Dream     49.2     18.2         195      4400   male 2007
297 Chinstrap     Dream     42.4     17.3         181      3600 female 2007
298 Chinstrap     Dream     48.5     17.5         191      3400   male 2007
299 Chinstrap     Dream     43.2     16.6         187      2900 female 2007
300 Chinstrap     Dream     50.6     19.4         193      3800   male 2007
301 Chinstrap     Dream     46.7     17.9         195      3300 female 2007
302 Chinstrap     Dream     52.0     19.0         197      4150   male 2007
303 Chinstrap     Dream     50.5     18.4         200      3400 female 2008
304 Chinstrap     Dream     49.5     19.0         200      3800   male 2008
305 Chinstrap     Dream     46.4     17.8         191      3700 female 2008
306 Chinstrap     Dream     52.8     20.0         205      4550   male 2008
307 Chinstrap     Dream     40.9     16.6         187      3200 female 2008
308 Chinstrap     Dream     54.2     20.8         201      4300   male 2008
309 Chinstrap     Dream     42.5     16.7         187      3350 female 2008
310 Chinstrap     Dream     51.0     18.8         203      4100   male 2008
311 Chinstrap     Dream     49.7     18.6         195      3600   male 2008
312 Chinstrap     Dream     47.5     16.8         199      3900 female 2008
313 Chinstrap     Dream     47.6     18.3         195      3850 female 2008
314 Chinstrap     Dream     52.0     20.7         210      4800   male 2008
315 Chinstrap     Dream     46.9     16.6         192      2700 female 2008
316 Chinstrap     Dream     53.5     19.9         205      4500   male 2008
317 Chinstrap     Dream     49.0     19.5         210      3950   male 2008
318 Chinstrap     Dream     46.2     17.5         187      3650 female 2008
319 Chinstrap     Dream     50.9     19.1         196      3550   male 2008
320 Chinstrap     Dream     45.5     17.0         196      3500 female 2008
321 Chinstrap     Dream     50.9     17.9         196      3675 female 2009
322 Chinstrap     Dream     50.8     18.5         201      4450   male 2009
323 Chinstrap     Dream     50.1     17.9         190      3400 female 2009
324 Chinstrap     Dream     49.0     19.6         212      4300   male 2009
325 Chinstrap     Dream     51.5     18.7         187      3250   male 2009
326 Chinstrap     Dream     49.8     17.3         198      3675 female 2009
327 Chinstrap     Dream     48.1     16.4         199      3325 female 2009
328 Chinstrap     Dream     51.4     19.0         201      3950   male 2009
329 Chinstrap     Dream     45.7     17.3         193      3600 female 2009
330 Chinstrap     Dream     50.7     19.7         203      4050   male 2009
331 Chinstrap     Dream     42.5     17.3         187      3350 female 2009
332 Chinstrap     Dream     52.2     18.8         197      3450   male 2009
333 Chinstrap     Dream     45.2     16.6         191      3250 female 2009
334 Chinstrap     Dream     49.3     19.9         203      4050   male 2009
335 Chinstrap     Dream     50.2     18.8         202      3800   male 2009
336 Chinstrap     Dream     45.6     19.4         194      3525 female 2009
337 Chinstrap     Dream     51.9     19.5         206      3950   male 2009
338 Chinstrap     Dream     46.8     16.5         189      3650 female 2009
339 Chinstrap     Dream     45.7     17.0         195      3650 female 2009
340 Chinstrap     Dream     55.8     19.8         207      4000   male 2009
341 Chinstrap     Dream     43.5     18.1         202      3400 female 2009
342 Chinstrap     Dream     49.6     18.2         193      3775   male 2009
343 Chinstrap     Dream     50.8     19.0         210      4100   male 2009
344 Chinstrap     Dream     50.2     18.7         198      3775 female 2009

This has several problems:

  1. We are showing way too much data. A reader will not be able to easily find meaningful trends or patterns in a big data set like this.

    As a general rule, you should rarely have more than 10-15 rows in a table; even then, you will still want to guide your reader to the point of the table.

  2. The column names are rather ugly. Some, like species are not too bad, though it would still be better if they were capitalized. Others, like bill_len are pretty terrible: bill_len is not an English word, the underscore exists only to separate two words “in code” (recall R’s restrictions on variable names), and the unit isn’t clear. In this case, a column name like Bill Length (mm) would be far preferable.8

  1. The row numbers are essentially pointless and just take up space, adding no value. Any content that is not adding value is simply distracting the reader from the content that has value.

  2. The “point” of the table is unclear. What is a reader supposed to get from this? As a data analyst - doing work on behalf of a reader who may not be a data analyst - you have a responsibility to clearly convey the “story” of your findings and this does not do so.

    I may want to use this data to show that Gentoo penguins are, on average, heavier than the other two species in this data set, but this is far from clear.

  3. It’s just a bit ugly.

Good table design requires us to take on the mindset of the reader. Tools like gt can help pretty things up, but you still have to think about what you want to display. Well-formatted garbage is still garbage.

To start improving this table, let’s do the calculations for our reader instead of expecting them to do it all manually:

library(tidyverse)
penguins |> 
    group_by(species) |> 
    summarize(n_species = n(), 
              avg_body_mass = mean(body_mass, na.rm=TRUE)) |>
    arrange(desc(avg_body_mass))
# A tibble: 3 × 3
  species   n_species avg_body_mass
  <fct>         <int>         <dbl>
1 Gentoo          124         5076.
2 Chinstrap        68         3733.
3 Adelie          152         3701.

We’re definitely not done - but here the “point” of the table is clear, at least if we also put some text surround it.

To improve this further, we can also pass this smaller summary data frame to the gt function from the package of the same name:

library(gt)
penguins |> 
    group_by(species) |> 
    summarize(n_species = n(), 
              avg_body_mass = mean(body_mass, na.rm=TRUE)) |>
    arrange(desc(avg_body_mass)) |>
    gt()
species n_species avg_body_mass
Gentoo 124 5076.016
Chinstrap 68 3733.088
Adelie 152 3700.662

Note here that gt recognizes we are rendering an HTML page and produces a “real” HTML table here. If you were to copy and paste the table above into “table” software, e.g. Google Sheets or Microsoft Excel, it would be properly and automatically handled. For us, the table is the end-point, but it’s a nice courtesy to your reader who may want to use your results in their own presentations.

The gt package provides many functions for tweaking and improving the appearance of a table. You will almost always want to, at a minimum, use these for:

  • Ordering and (re-)naming columns
  • Adding titles and footers
  • Formatting values

Let’s to through these one at a time. Firstly, we want to rename and reorder the columns. This can be done in pure dplyr with the select and rename columns, but we’ll show the gt way here:

library(gt)
penguins |> 
    group_by(species) |> 
    summarize(n_species = n(), 
              avg_body_mass = mean(body_mass, na.rm=TRUE)) |>
    arrange(desc(avg_body_mass)) |>
    gt() |>
    cols_move_to_end(n_species) |>
    cols_label(species="Species", 
               avg_body_mass = "Avg. Body Mass (g)", 
               n_species = "Number of Penguins in Sample") 
Species Avg. Body Mass (g) Number of Penguins in Sample
Gentoo 5076.016 124
Chinstrap 3733.088 68
Adelie 3700.662 152

Here, we used the cols_move_to_end() function to move the n_species column to the end (no surprise!). In other contexts, we might want to use the cols_move_to_start() function to move a column to the leftmost side of a table or cols_move() to put a column in the middle of the table.

The cols_label() function essentially serves as a renaming operation: the left side of each parentheses is the old column name in the table and the right side gives the new name. (Note, a bit confusingly, that this is the reverse of dplyr::rename().) While we can just pass a basic string here, we can also use the md() function to pass Markdown which lets us do some custom formatting:

penguins |> 
    group_by(species) |> 
    summarize(n_species = n(), 
              avg_body_mass = mean(body_mass, na.rm=TRUE)) |>
    arrange(desc(avg_body_mass)) |>
    gt() |>
    cols_move_to_end(n_species) |>
    cols_label(species=md("**Species**"), 
               avg_body_mass = md("Avg. Body Mass (*g*)"), 
               n_species = md("*Number of Penguins in Sample*"))
Species Avg. Body Mass (g) Number of Penguins in Sample
Gentoo 5076.016 124
Chinstrap 3733.088 68
Adelie 3700.662 152

Here, we could use boldface and italics for certain text using standard Markdown syntax.

Next, we can add a table title and subtitle to make the content and point of this table clear to our reader:

penguins |> 
    group_by(species) |> 
    summarize(n_species = n(), 
              avg_body_mass = mean(body_mass, na.rm=TRUE)) |>
    arrange(desc(avg_body_mass)) |>
    gt() |>
    cols_move_to_end(n_species) |>
    cols_label(species=md("**Species**"), 
               avg_body_mass = md("Avg. Body Mass (*g*)"), 
               n_species = md("*Number of Penguins in Sample*")) |>
    tab_header(title="Average Body Mass of Three Penguin Species", 
               subtitle="Gentoo penguins are the largest in the study")
Average Body Mass of Three Penguin Species
Gentoo penguins are the largest in the study
Species Avg. Body Mass (g) Number of Penguins in Sample
Gentoo 5076.016 124
Chinstrap 3733.088 68
Adelie 3700.662 152

While we can and should describe our analysis in more detail in the main text, I like this pattern of having the super-simple one-liner present directly in the table. This also makes it convenient to clip the table (or a screenshot thereof) for use in other documents and presentations.

Next, we should always note the source of the data used to get our results. In this case, the original penguins data comes from this article so we can cite that in our work Note the use of Markdown (md()) to let us include a link to the original source within our table:

penguins |> 
    group_by(species) |> 
    summarize(n_species = n(), 
              avg_body_mass = mean(body_mass, na.rm=TRUE)) |>
    arrange(desc(avg_body_mass)) |>
    gt() |>
    cols_move_to_end(n_species) |>
    cols_label(species=md("**Species**"), 
               avg_body_mass = md("Avg. Body Mass (*g*)"), 
               n_species = md("*Number of Penguins in Sample*")) |>
    tab_header(title="Average Body Mass of Three Penguin Species", 
               subtitle="Gentoo penguins are the largest in the study") |>
    tab_source_note(md("Data originally published in by K.B. Gorman, T.D. Williams, 
                       and W. R. Fraser in 'Ecological Sexual Dimorphism and 
                       Environmental Variability within a Community of Antarctic 
                       Penguins (Genus *Pyogscelis*). *PLoS One* 9(3): e90081.
                       <https://doi.org/10.1371/journal.pone.0090081>. Later 
                       popularized via the `R` package
                       [`palmerpenguins`](https://allisonhorst.github.io/palmerpenguins/)"))
Average Body Mass of Three Penguin Species
Gentoo penguins are the largest in the study
Species Avg. Body Mass (g) Number of Penguins in Sample
Gentoo 5076.016 124
Chinstrap 3733.088 68
Adelie 3700.662 152
Data originally published in by K.B. Gorman, T.D. Williams, and W. R. Fraser in ’Ecological Sexual Dimorphism and Environmental Variability within a Community of Antarctic Penguins (Genus Pyogscelis). PLoS One 9(3): e90081. https://doi.org/10.1371/journal.pone.0090081. Later popularized via the R package palmerpenguins

A small, but lovely, quality of life feature here is the fact that md() will automatically re-align the text to the fit the dimensions of the rendered table. This lets us put new lines within our citation text so that our code doesn’t exceed the 80 characters-per-line guideline.

Finally, we want to make sure the number values are formatted appropriately. For these numbers, plain formatting really isn’t much of a problem, but for very large or small numbers, we might want to use scientific notation; for dates, we might want to control the formatting; etc.. This is done with the fmt_* family of functions.

Each fmt_ function takes one or more column names and applies a formatting transformation to that column. The specifics of the formatting can be controlled with additional optional arguments. For example, if we want to round the average weight to the nearest gram, we would use the fmt_number() function with the argument deicmals=0:

penguins |> 
    group_by(species) |> 
    summarize(n_species = n(), 
              avg_body_mass = mean(body_mass, na.rm=TRUE)) |>
    arrange(desc(avg_body_mass)) |>
    gt() |>
    cols_move_to_end(n_species) |>
    cols_label(species=md("**Species**"), 
               avg_body_mass = md("Avg. Body Mass (*g*)"), 
               n_species = md("*Number of Penguins in Sample*")) |>
    tab_header(title="Average Body Mass of Three Penguin Species", 
               subtitle="Gentoo penguins are the largest in the study") |>
    tab_source_note(md("Data originally published in by K.B. Gorman, T.D. Williams, 
                       and W. R. Fraser in 'Ecological Sexual Dimorphism and 
                       Environmental Variability within a Community of Antarctic 
                       Penguins (Genus *Pyogscelis*). *PLoS One* 9(3): e90081.
                       <https://doi.org/10.1371/journal.pone.0090081>. Later 
                       popularized via the `R` package
                       [`palmerpenguins`](https://allisonhorst.github.io/palmerpenguins/)")) |>
    fmt_number(avg_body_mass, decimals=0)
Average Body Mass of Three Penguin Species
Gentoo penguins are the largest in the study
Species Avg. Body Mass (g) Number of Penguins in Sample
Gentoo 5,076 124
Chinstrap 3,733 68
Adelie 3,701 152
Data originally published in by K.B. Gorman, T.D. Williams, and W. R. Fraser in ’Ecological Sexual Dimorphism and Environmental Variability within a Community of Antarctic Penguins (Genus Pyogscelis). PLoS One 9(3): e90081. https://doi.org/10.1371/journal.pone.0090081. Later popularized via the R package palmerpenguins

In this case, it may be more appropriate to display the body mass in kilograms and we can do so semi-automatically with the format_number_si() formatter:

penguins |> 
    group_by(species) |> 
    summarize(n_species = n(), 
              avg_body_mass = mean(body_mass, na.rm=TRUE)) |>
    arrange(desc(avg_body_mass)) |>
    gt() |>
    cols_move_to_end(n_species) |>
    cols_label(species=md("**Species**"), 
               avg_body_mass = md("Avg. Body Mass "), 
               n_species = md("*Number of Penguins in Sample*")) |>
    tab_header(title="Average Body Mass of Three Penguin Species", 
               subtitle="Gentoo penguins are the largest in the study") |>
    tab_source_note(md("Data originally published in by K.B. Gorman, T.D. Williams, 
                       and W. R. Fraser in 'Ecological Sexual Dimorphism and 
                       Environmental Variability within a Community of Antarctic 
                       Penguins (Genus *Pyogscelis*). *PLoS One* 9(3): e90081.
                       <https://doi.org/10.1371/journal.pone.0090081>. Later 
                       popularized via the `R` package
                       [`palmerpenguins`](https://allisonhorst.github.io/palmerpenguins/)")) |>
    fmt_number_si(avg_body_mass, 
                  decimals=2, 
                  unit = "g")
Average Body Mass of Three Penguin Species
Gentoo penguins are the largest in the study
Species Avg. Body Mass Number of Penguins in Sample
Gentoo 5.08 kg 124
Chinstrap 3.73 kg 68
Adelie 3.70 kg 152
Data originally published in by K.B. Gorman, T.D. Williams, and W. R. Fraser in ’Ecological Sexual Dimorphism and Environmental Variability within a Community of Antarctic Penguins (Genus Pyogscelis). PLoS One 9(3): e90081. https://doi.org/10.1371/journal.pone.0090081. Later popularized via the R package palmerpenguins

Note that, because fmt_number_si() automatically includes the unit and transforms it to the most natural scale (here kg), we can remove the unit from the column name. gt has many more advanced options that can be used for further customization; refer to the package documentation for more details or ask on the course discussion board.

Exploratory Analysis

When faced with a new data set, it is tempting to look only at the first few rows to get a sense of the data: R does this by default. In practice, I recommend viewing a random selection of rows instead. This won’t guarantee you find any issues, but it increases the probability of finding issues in older parts of a data set. The slice_sample() function can be used for this.

While EDA can be an extensive activity on its own, at an absolute minimum, I recommend you always do at least two basic checks:

  • Ensure that you know what R thinks your data is. You might see a value like "2025-12-01" and think that R is reading it as a date value, but R might instead interpret it as a string value.9 Then, when you try to do “date things” you will run into trouble. To avoid this, you often need to explicitly convert object types in R, but knowing when to convert requires you to first know what type R thinks something is. You have several options for determining object type in R, but when working with a data frame, I’d recommend the glimpse() function from the dplyr package: e.g.

    glimpse(penguins)
    Rows: 344
    Columns: 8
    $ species     <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Ad…
    $ island      <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgersen, Tor…
    $ bill_len    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, 42.0, …
    $ bill_dep    <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, 20.2, …
    $ flipper_len <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186, 180,…
    $ body_mass   <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, 4250, …
    $ sex         <fct> male, female, female, NA, female, male, female, male, NA, …
    $ year        <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…

    After getting the basic dimensions of this data frame, glimpse() will print a line summary of each column giving its name, type, and the first few values in the table.

    In this case, since I did most of the data prep for you, all columns should be of the correct type after you complete Task 3, but this is a quick and easy check. If there are issues with your data types, it’s better to catch them early than to have silent and hard to identify errors further down the line. (“Fail fast” is great advice in any programming exercise.)

  • Take a quick look at some basic (univariate) summary statistics for each column. There are several functions for this in base R: e.g.,

    summary(penguins)
          species          island       bill_len        bill_dep    
     Adelie   :152   Biscoe   :168   Min.   :32.10   Min.   :13.10  
     Chinstrap: 68   Dream    :124   1st Qu.:39.23   1st Qu.:15.60  
     Gentoo   :124   Torgersen: 52   Median :44.45   Median :17.30  
                                     Mean   :43.92   Mean   :17.15  
                                     3rd Qu.:48.50   3rd Qu.:18.70  
                                     Max.   :59.60   Max.   :21.50  
                                     NA's   :2       NA's   :2      
      flipper_len      body_mass        sex           year     
     Min.   :172.0   Min.   :2700   female:165   Min.   :2007  
     1st Qu.:190.0   1st Qu.:3550   male  :168   1st Qu.:2007  
     Median :197.0   Median :4050   NA's  : 11   Median :2008  
     Mean   :200.9   Mean   :4202                Mean   :2008  
     3rd Qu.:213.0   3rd Qu.:4750                3rd Qu.:2009  
     Max.   :231.0   Max.   :6300                Max.   :2009  
     NA's   :2       NA's   :2                                 

    But I actually prefer the skim() function from the skimr package as it provides a bit more type-specific information and has more handsome formatting:

    library(skimr)
    skim(penguins)
    Data summary
    Name penguins
    Number of rows 344
    Number of columns 8
    _______________________
    Column type frequency:
    factor 3
    numeric 5
    ________________________
    Group variables None

    Variable type: factor

    skim_variable n_missing complete_rate ordered n_unique top_counts
    species 0 1.00 FALSE 3 Ade: 152, Gen: 124, Chi: 68
    island 0 1.00 FALSE 3 Bis: 168, Dre: 124, Tor: 52
    sex 11 0.97 FALSE 2 mal: 168, fem: 165

    Variable type: numeric

    skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
    bill_len 2 0.99 43.92 5.46 32.1 39.23 44.45 48.5 59.6 ▃▇▇▆▁
    bill_dep 2 0.99 17.15 1.97 13.1 15.60 17.30 18.7 21.5 ▅▅▇▇▂
    flipper_len 2 0.99 200.92 14.06 172.0 190.00 197.00 213.0 231.0 ▂▇▃▅▂
    body_mass 2 0.99 4201.75 801.95 2700.0 3550.00 4050.00 4750.0 6300.0 ▃▇▆▃▂
    year 0 1.00 2008.03 0.82 2007.0 2007.00 2008.00 2009.0 2009.0 ▇▁▇▁▇

    You’ll see that this gives some nice overview about data structure and types, identifies grouping structure (if any is present), and gives summaries appropriate to the type of each column (here factors, i.e., categorical variables and numeric). I like that this summary gives means, standard deviations, minima (p0), maxima (p100), medians (p50), and a cute little histogram of each variable.

    Note that this type of summary only reveals univariate structure: if there are interesting multi-dimensional outliers or weird correlation patterns, they won’t appear here.

TipTask 4: Initial EDA Pass

Perform the two checks described above on the Netflix data you loaded and processed above. Include the code to perform the checks, the output of the checks, and describe what you see.

In general, you shouldn’t include this in analysis reports, but we’re making an exception here to practice a good habit. I would advise against including code in your future mini-project or course project reports, but these steps are easy and very valuable, so I recommend you make them part of your standard EDA workflow. (Remember, not everything you do as part of EDA needs to be included in your final submission, especially outside of a classroom setting. Make sure you are maximizing signal-to-noise for your intended readers.)

We are finally ready to begin some EDA. Analysts organize their EDA in a variety of ways, but one of my favorites is to think of a variety of interesting questions relevant to the data set and to attempt to answer them. When the answers don’t match my intuition, I know I’ve found somewhere I want to dig deeper. For the first few mini-projects, I will provide these exploratory questions. Later in the course, particularly after we have discussed the role of plotting and graphics in EDA, you will have opportunities to organize your EDA in other fashions.

TipTask 5: Exploratory Questions - Inline Values

Using dplyr tools, answer the following six questions. Each of these questions can be answered with one or two scalar values. Use Quarto’s inline code functionality to place the values in a sentence; that is, you should answer in complete sentences, written as normal text with inline code for computed values.

  1. What date range is covered by this data set?

  2. How many different shows and movies are covered in this data set?

    (Don’t worry about combining seasons for now: you can treat “Stranger Things 2” and “Stranger Things 3” as different shows.)

  3. How many total hours have been spent watching shows from the Bridgerton universe?

    Hint: The str_detect() function can be used to test whether a string (like a name) contains a substring:10 e.g.,

    # True because "CUNY" (2nd arg) is in the longer string (1st arg)
    str_detect("CUNY Bernard M. Baruch College", "CUNY")
    [1] TRUE
    # False because "Hunter" is nowhere in the first argument
    str_detect("CUNY Bernard M. Baruch College", "Hunter")
    [1] FALSE

    As with other functions in R, str_detect() is vectorized, making it easy to use inside of other functions, such as filter().

    names <- c("City College-Miami", "CUNY City College", "CUNY Hunter College")
    str_detect(names, "CUNY")
    [1] FALSE  TRUE  TRUE
  1. How many total hours have been spent watching the five seasons of Stranger Things? For this question, we only want the “real” Stranger Things shows and not the companion behind-the-scenes show (“Beyond Stranger Things”), the animated spin-off (“Tales from ’85”), or the background music (“Stranger Things: Fireplace”).

    To answer this question, you will need to use a combination of filter() and filter_out() statements to sequentially apply multiple str_detect() steps.

    Hint: Recall that you generally shouldn’t combine multiple steps in a single filter_out() as the results can be a bit unintuitive.

  2. What percentage of total watch time was spent on the Top 10 titles of 2026H1?

  3. What fraction of Netflix’s catalog is globally available? (Answer this both by title and weighted by hours viewed)

As you go through these questions, you may find it useful to create new variables in the data to avoid repeated lengthy calculations, e.g., is_stranger_things. Do this is you find it useful, but it is not strictly required.

Where appropriate, the scales package can be used to format numbers attractively: e.g.,

library(scales)
comma(12345.6789)
[1] "12,346"
comma(12345.6789, accuracy=0.01)
[1] "12,345.68"
dollar(12345.6789)
[1] "$12,345.68"
percent(0.1234)
[1] "12%"
percent(0.1234, accuracy=0.01)
[1] "12.34%"

The next set of questions have slightly more complex answers and should be answered with a table, formatted using the techniques described above. Longer term, you will prefer plots to tables as they are a bit easier to interpret (humans being visual creatures) but these are the types of questions you might use to create plots as well.

TipTask 6: Exploratory Questions - Table Answers

Using dplyr tools, answer the following questions. Each of these questions can be answered with a table of just a few rows. Use the gt package, as introduced above, to present your results in an attractive ‘publication-quality’ format, not just a “raw” R output.

  1. What was the top show (by total hours viewed) in each period and what fraction of total viewership did it capture?

  2. How has Netflix’s catalog changed in size over the periods for which we have questions? You should consider both the number of titles and the total runtime of content.

  3. Which shows have had the most consistently high viewership across all periods? These shows are likely to be ‘staples’ that viewers fall back on as ‘comfort food’, e.g., re-runs of Friends.

    Hint: To answer this question, you might want to compute the average veiwership, the minimum viewership, and the standard deviation of viewership across different periods and develop a filter using some combination of these quantities.

  4. Within each period, what fraction of time was spent on ‘shows’ vs movies?

    Unfortunately our data does not clearly delineate shows from movies, so you will need to come up with a heuristic for doing so. I’d recommend some combination of:

    • Length: anything over 4-ish hours is almost certainly a TV show, not a movie
    • “Season”: if a title has “Season” in it, it is almost certainly a TV show

    You might think of other filters or thresholds that make sense and can incorporate them into your analysis.

    This is a problem that commonly arises in real data analysis: the data is not quite what we might want to answer a question, but we could definitely construct the feature manually if we were willing to put in the effort. In this case, we have to come up with an approximate way of implementing our feature that (roughly) captures our human intuition.11

  5. How does the performance of live events compare to pre-taped content? Does the average live event draw more viewership than an average piece of pre-taped content? How about a ‘top tier’ live event vs ‘top tier’ pre-taped content?

There are many ways you might choose to approach these questions, and there isn’t a single correct answer. Make sure to clearly explain any analytical choices you make.

Final Deliverable: Platform Strategy Memo

At this point, you have acquired your data, cleaned and prepared it, and performed your EDA. Now, you are ready to get to work on the final deliverable of your analysis. Everything that comes before this is important, but typically less visible to your final customer.

TipTask 7: Corporate Strategy Memo

Write a brief (no more than 750 words) corporate strategy memo addressed to Netflix leadership. Your memo should help inform Netflix’s original content strategy for 2027 and beyond.

You can use the calculations performed above - or something similar - to include specific numerical evidence in support of your recommendations. For example, you should not say “live events are an increasingly large share of viewership” and should instead prefer a more specific claim like “live events have risen from X% to Y% of total watch time.”

Your memo should touch on at least 2 of the following possible topics:

  • Globally available vs. regionally licensed content
  • TV shows vs. movies
  • ‘Big hits’ vs. the long-tail of smaller titles
  • Shorter ‘bite sized’ vs. longer content
  • ‘Burstiness’ of viewership: do titles have a rush of viewership immediately after release (to partially answer this, you can use the period end and release date columns to get a “days available” value; combine this with a focus on titles that release near a period end)
  • Trends over time: identify time changes in the data, don’t simply aggregate 2023 to the present.

You may also address other structure or trends in the data you find interesting.

You may include additional tables or even visualizations if you want, but these do not replace the requirement to write the core strategy memo. Your memo should stand “alone” and not be mixed in with your code. Place the code necessary to perform the relevant supporting calculations in a separate section and use inline code chunks to include results of your analysis in the text of your strategy memo. Deliverables that hard-code calculated values will be penalized.

AI Usage Statement

At the end of your report, you must include a description of the extent to which you used Generative AI tools to complete the mini-project. This should be a one paragraph section clearly deliniated using a collapsable Quarto “Callout Note”. Failure to include an AI disclosure will result in an automatic 25% penalty.

E.g.,

NoteAI Usage Statement

No Generative AI tools were used to complete this mini-project.

or

NoteAI Usage Statement

GitHub Co-Pilot Pro was used via RStudio integration while completing this project. No other generative AI tools were used.

or

NoteAI Usage Statement

ChatGPT was used to help write the code in this project, but all non-code text was generated without the use of any Generative AI tools. Additionally, ChatGPT was used to provide additional background information on the topic and to brainstorm ideas for the final open-ended prompt.

Recall that Generative AI may not be used to write or edit any non-code text in this course.

These blocks should be created using the following syntax:


::: {.callout-note title="AI Usage Statement" collapse="true"}

Your text goes here. 

:::

Make sure to use this specific type of callout (.callout-note), title, and collapse="true" setting.

Please contact the instructor if you have any questions about appropriate AI usage in this course.

Extra Credit Opportunities

There are optional Extra Credit Opportunities where extra points can be awarded for specific additional tasks in this mini-project. The amount of the extra credit is typically not proportional to the work required to complete these tasks, but I provide these for students who want to dive deeper into this project and develop additional data analysis skills not covered in the main part of this mini-project.

For this mini-project, no more than 4 total points of extra credit may be awarded. Even with extra credit, your grade on this mini-project cannot exceed 80 points total.

Gini Analysis (Up to 2 Points)

When analyzing data with a ‘long tail’, it is often interesting to look at inequality in the data. We know that viewership data will be ‘top-heavy’ and that some shows will be major hits with meaningful cultural footprints, while others will be watched by only a small number of viewers. To wit,

To put some numbers of this phenomenon, we can adapt the idea of a Gini coefficient from economics. Wikipedia gives several useful formulas for the Gini coefficient. For example, suppose a country has only 5 citizens, and their incomes are as follows:

Citizen Income
Alice $20K
Barbara $200K
Carol $0K
Debbie $50K
Emily $40K

The Gini coefficient of this distribution can be computed as:

\[G = \frac{2}{n} \frac{\sum_{i=1}^n i y_{(i)}}{\sum_{i=1}^n y_{(i)}} - \frac{n+1}{n}\]

where \(y_{(i)}\) are the ordered incomes (\(y_{(1)} = 0 \leq y_{(2)} = 20 \leq y_{(3)} = 40 \leq y_{(4)} = 50 \leq y_{(5)} = 200\)). This gives a Gini coefficient of around 55.5% for this country. (Make sure you can replicate this number.)

Up to two points of extra credit will be given to submissions that include a Gini-coefficient analysis in their strategy memo. Submissions must (briefly) define the Gini coefficient in non-technical language. When computing the Gini coefficient, make sure to consider whether it makes sense to look at raw view time or some sort of length-normalized viewership metric.

Data Visualization (2 point)

Inclusion of a well-formatted visual element to accompany your memo may earn up to 2 points of extra credit.


This work ©2026 by Michael Weylandt is licensed under a Creative Commons BY-NC-SA 4.0 license.

Footnotes

  1. The WWW reports give global data for all of Netflix. Netflix also releases country-specific Top 10 data. See https://michael-weylandt.com/STA9750/archive/AY-2025-FALL/miniprojects/mini01.html for a prior mini-project using this data.↩︎

  2. Shows with less than 100,000 hours of watch time are omitted and viewership is founded to the nearest 100,000, so this data doesn’t capture small differences in unpopular shows. The ‘winners’ are still quite clear in this data.↩︎

  3. This the level of “ChatGPT-level” prose, without obvious flaws but lacking the style and elegance associated with true quality writing.↩︎

  4. Throughout this section, replace YOUR_GITHUB_ID with your GitHub ID from Mini-Project #00. Note that the automated course infrastructure will be looking for precise formatting, so follow these instructions closely.↩︎

  5. To keep this analysis simple, I have restricted the data set to shows with titles that are fully-ASCII (roughly, English language characters). We will discuss the challenges associated with non-English characters later in the semester. For now, just be aware that your results are restricted to shows with an English title, so if a show is popular in a country with a non-ASCII alphabet (e.g., Japan or Korea) but was never released with an English title, it may be excluded from our analysis.↩︎

  6. Netflix defines “Views” differently in other contexts. At one point, a user was said to have “viewed” a show if they watched two or more minutes of it. This, predictably, lead Netflix to debut the “most viewed show ever” with surprising regularity.↩︎

  7. Don’t worry too much about the length of variable names: tab-completion is a wonderful thing and code is read more than written)↩︎

  8. I know this is the opposite of the advice given about names earlier. The “best practices” for code are not the “best practices” for final presentations.↩︎

  9. In one famous (and slightly tragic) example, Microsoft Excel silently misinterpreted the names of various genes as numeric values and changed them from (what it thought was) scientific notation to (what it thought was) standard numeric formatting. This wound up ruining several important scientific studies. Always check your data types! The original study identifying this problem can be found here and a popular news summary is here.↩︎

  10. str_detect() can actually be used to perform significantly more complex string analysis than simple “does it contain this subset of letters” but we won’t cover that sort of string processing for a few more weeks.↩︎

  11. This is an interesting place where LLMs can augment data analysts. It would be pretty easy - but a bit beyond this assignment - to query your favorite LLM to classify these titles as TV shows or movies. See https://tidydesign.substack.com/i/214337800/structured-data for a discussion of these ideas.↩︎

  • Edit this page
  • View source
  • Report an issue