STA 9750 Mini-Project #04: Just the Fact(-Check)s, Ma’am!

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

Due Dates

  • Released to Students: 2025-11-01
  • Initial Submission: 2025-12-05 11:59pm ET on GitHub and Brightspace
  • Peer Feedback:
    • Peer Feedback Assigned: 2025-12-08 on GitHub
    • Peer Feedback Due: 2025-12-19 11:59pm ET on GitHub

Estimated Time to Complete: 5 Hours

Estimated Time for Peer Feedback: 1 Hour


Introduction

Welcome to Mini-Project #04!

On August 1st, 2025, President Donald Trump announced in a post on Truth Social that he was instructing his staff to fire Dr. Erika McEntarfer, the Commissioner of Labor Statistics. As the head of the Bureau of Labor Statistics, Dr. McEntarfer had responsibility for all of the BLS’s statistical programs and reporting. None of these reports is more closely watched than the BLS’s Monthly Current Employment Statistics (CES), colloquially known as the “jobs number”. The monthly jobs report regularly moves financial markets, is scrutinized and analyzed by economists, investors, and business leaders of every stripe, and is used by politicians and political analysts as the primary measure of “the economy,” alongside major stock indices.1

The sudden dismissal of Dr. McEntarfer was quickly and emphatically criticized by economists from both left- and right-of center who worried that even the appearance of politicization would permanently create doubt in the quality of BLS’s work. Defenders of the President’s actions pointed to the size and direction of recent revisions to CES numbers as a cause for concern. Supporters of BLS and Dr. McEntarer concede that BLS and CES face non-trivial challenges but deny any political valence to these challenges. Indeed, as one former BLS Commissioner has noted, the Commissioner has minimal-to-no ability to view or edit CES numbers before publication and that revisions are an expected part of the process:

This report, jointly published by Bloomberg News and the Petersen Institute for International Economics (a left-of-center think-tank), goes into great detail about the source, necessity, and procedures for month-over-month revisions.

In this final Mini-Project, you will investigate recent patterns in BLS CES estimates and revisions, with an eye to evaluating the truth of the President’s claimed rationale for firing Dr. McEntarfer. While briefer than the previous Mini-Projects, this project will bring together all of the skills you have developed in this course:

  • Accessing data from the web using HTTP requests (httr2)
  • Extracting data from HTML and cleaning it (rvest, stringr)
  • Joining together data from different tables (multi-table dplyr)
  • “Pivoting” and preparing data for analysis (single-table dplyr)
  • Exploring and visualizing data (ggplot2)
  • Statistical analysis and inference (infer or stats)
  • Communicating your findings using web-based reproducible research tools (Quarto)

For this mini-project, you will evaluate the veracity of these competing claims about the accuracy of BLS reports in the form of a political “fact check.” That is, you will find a claim made by a public figure and see whether the data supports, refutes, or - most likely - is only partially consistent with that claim.

There is no right answer to this analysis: as in so many things, the specific way you interpret question will dictate the answer you find. It is true that recent BLS revisions have been among the largest in history, but the working population is also among the largest in history, so proportionally these revisions may not be quite so large. As you complete this assignment, I strongly encourage you to attempt to work apolitically, letting the data and your analysis lead wherever they may: this is a complex question about statistical methodology and evaluation and people of good will may and do disagree on it.

Any sign of politics leaching into the peer evaluation process will be rapidly and forcefully addressed by the instructor.

Note that, compared to previous mini-projects, the scope of this project is relatively smaller: in light of this, and the more advanced skills you have spent the past 3 months developing, this mini-project should be the least demanding of the course. (It is still likely to be the most difficult simply because you are responsible for more steps of the data analysis than any prior project.) At this point in the course, you should be spending the majority of your out-of-class hours on your Course Project.

The Final Mini-Project

This mini-project completes our whirlwind tour of several different forms of data-driven writing:

  • Marketing and Press Releases
  • Policy Briefs and Political Lobbying
  • Program Design and Non-Profit Grant Writing
  • Fact Checking Controversial Claims

You have applied your skills to a wide range of topics, including trending content on Netflix, Forestry records of New York City, housing development permitting, and employment reports.

There are, of course, many other ways that data can be used to generate and communicate insights and many other topics where your skills can be applied, but hopefully this “hit parade” has given you a sense of just how widely your new skills can take you. In each of these domains, you have seen how sophisticated and thoughtful analysis - not simply computing a single mean or regression coefficient - has allowed deeper understanding of the complexities of real world problems. You have learned to think beyond the simple binary “correct/incorrect” of an analysis and to see that even superficially simple questions - “is this true?”, “what is the average?”, “is there a correlation?” - can lead down deep and rewarding rabbit holes of complexity. But those rabbit holes are where your real power as a data analyst can be found.

The tools of quantitative analysis and communication you have developed in this course can be used in essentially infinite contexts– we have only scratched the surface–and I’m excited to see what you do in the remainder of this course, in your remaining time at Baruch, and in your future careers.

Student Responsbilities

Recall our basic analytic workflow and table of student responsibilities:

  • Data Ingest and Cleaning: Given a single data source, read it into R and transform it to a reasonably useful standardized 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.
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 this mini-project, you are in charge of the whole pipeline, from data acquisition to statistical inference. The rubric below evaluates your work on all aspects of this project.

Rubric

STA 9750 Mini-Projects are evaluated using peer grading with meta-review by the course GTAs. The following rubric will be used for this mini-project:

Course Element Excellent (9-10) Great (7-8) Good (5-6) Adequate (3-4) Needs Improvements (1-2)
Written Communication Report is well-written and flows naturally. Motivation for key steps is clearly explained to reader without excessive detail. Key findings are highlighted and appropriately given context. Report has no grammatical or writing issues. Writing is accessible and flows naturally. Key findings are highlighted, but lack suitable motivation and context. Report has no grammatical or writing issues. Key findings are present but insufficiently highlighted. Writing is intelligible, but has some grammatical errors. Key findings are obscured. Report exhibits significant weakness in written communication. Key points are difficult to discern.
Project Skeleton Code completes all instructor-provided tasks correctly. Responses to open-ended tasks are particularly insightful and creative. Code completes all instructor-provided tasks satisfactorily. Response to one instructor provided task is skipped, incorrect, or otherwise incomplete. Responses to two instructor provided tasks are skipped, incorrect, or otherwise incomplete. Response to three or more instructor provided tasks are skipped, incorrect, or otherwise incomplete.

Formatting & Display

Tables and figures are full ‘publication-quality.’

Report includes at least one animated visualization designed to effectively communicate findings.

Tables have well-formatted column names, suitable numbers of digits, and attractive presentation.

Figures are ‘publication-quality,’ with suitable axis labels, well-chosen structure, attractive color schemes, titles, subtitles, and captions, etc.

Tables are well-formatted, but still have room for improvement.

Figures are above ‘exploratory-quality,’ but do not reach full ‘publication-quality.’

Tables lack significant ‘polish’ and need improvement in substance (filtering and down-selecting of presented data) or style.

Figures are suitable to support claims made, but are ‘exploratory-quality,’ reflecting minimal effort to customize and ‘polish’ beyond ggplot2 defaults.

Unfiltered ‘data dump’ instead of curated table.

Baseline figures that do not fully support claims made.

Code Quality

Code is (near) flawless.

Code passes all styler and lintr type analyses without issue.

Comments give context of the analysis, not simply defining functions used in a particular line.

Code has well-chosen variable names and basic comments.

Code executes properly, but is difficult to read.

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. Data is imported and prepared effectively, in an automated fashion with minimal hard-coding of URLs and file paths. Data is imported and prepared effectively, though source and destination file names are hard-coded. Data is imported in a manner likely to have errors. Data is hard-coded and not imported from an external source.

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 mp04.qmd (lower case!) so the rendered document can be found at docs/mp04.html in the student’s repository and will be served at the URL:2

https://<GITHUB_ID>.github.io/STA9750-2025-FALL/mp04.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=04)

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=04)

Once you confirm this website works (substituting <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=04)

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

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

Title the issue STA 9750 <GITHUB_ID> MiniProject #04 and fill in the following text for the issue:

Hi @michaelweylandt!

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

<https://<GITHUB_ID>.github.io/STA9750-2025-FALL/mp04.html>

Once the submission deadline passes, the instructor will tag classmates for peer feedback in this issue thread.

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 #04: Just the Fact(-Check)s, Ma’am!

Data Acquisition

Your analysis will depend on two separate data sources:

  • The (final) CES estimates of the total employment level of the United States; and
  • The cycle-to-cycle revisions of the CES estimate.

For this mini-project, will will exclusively focus on seasonally-adjusted total non-farm payroll as this is the most politically salient number that CES reports. Note also that CES principally computes the total payroll number, but the quantity of primary interest in political discussion is typically the change in this number.

Final CES Estimates

The Final CES Estimates are published by BLS in several places. We are going to access them through BLS Data Finder 1.1. Before attempting to access this data in R, it is useful to practice accessing them through your webbrowser.

Navigate to https://data.bls.gov/toppicks?survey=ce. Select the first row “Total Nonfarm Employment, Seasonally Adjusted” and hit “Retrieve Data” at the bottom of the page. You will then be taken to a page with the URL https://data.bls.gov/pdq/SurveyOutputServlet and approximately 10 years of data below. Adjust the years at the top of the page to start at 1979 and hit “Go” to view the full table.

Note that you cannot go directly to https://data.bls.gov/pdq/SurveyOutputServlet and get useful results. This page requires an HTTP request more sophisticated than a simple GET in order to work properly.

In order to complete this mini-project, you will need to make an equivalent HTTP request using httr2 to get the entire table.

Task 1: Download CES Total Nonfarm Payroll

Using httr2 and rvest, access and download the CES Total Nonfarm Payroll Seasonally Adjusted for each month from January 1979 to June of 2025.3 Return your results in a data frame of the following form:

date level
1979-01-01 88808
1979-02-01 89055

continued through 2025-06-01.

Replicating a suitable HTTP request in R using httr2 can be subtle, so I recommend following these steps:

  1. Use your browser’s introspection tools (Inspect, Developer Tools, or similar) to inspect the final HTTP request that shows the table starting in 1979.

  2. Replicate all elements of this HTTP request in httr2, including both

    • the correct HTTP verb and
    • the request body (using form-encoding via req_body_form())

    and confirm that your request is successful.

  3. View the HTML source of the page and identify the table element you want to extract.

  4. Using the tools of rvest, select the correct HTML element and turn it into an R data frame.

  5. Pivot that table into an appropriate format.

  6. Modify the column types as needed using the as.*****-family of functions for basic conversions or the functions from the lubridate package to parse dates and times. Finally, use drop_na() to remove any values that do not convert directly (including the footnote row about preliminary values).

    • The ym function from the lubridate package will be useful in parsing dates. It takes a string like 1979 Jan and returns a Date object of 1979-01-01. You may need to use string functions to combine multiple columns into a single string vector that can be passed to ym.
API Usage Required

You must use httr2 and rvest (not httr) to access and process the page directly to download this data.

A primary learning goal of this Mini-Project is to practice use of web scraping for data acquisition. If you download a data file manually, from a different source, use a “wrapper” package, or otherwise avoid scraping the page directly, you will receive a 0 for the Project Skeleton, Code Quality, and Data Preparation portions of your grade.

This does not need be a long bit of code when it is all done. My code to do all of these steps and to full clean and parse this data totals only 17 lines, generously formatted, after a bit of trial-and-error to see which elements of the HTTP request are not actually essential.

CES Revisions

Revisions to the CES Non-Farm Payroll Employment number are reported on a static page:

https://www.bls.gov/web/empsit/cesnaicsrev.htm

Task 2: Download CES Revisions Tables

Using httr2 and rvest, access and download the CES Revisions for each month from January 1979 to June of 2025.4 Return your results in a data frame of the following form:

date original final revision
1979-01-01 325 184 -82
1979-02-01 301 294 -7

continued through June 2025. Here the revision column is obtained by taking the difference in original (the first estimate) and final (the third estimate).

This structure of this page is somewhat complex, so I recommend that you follow the following steps:

  1. Review the source of the page linked above and identify the tables of interest. There is a pattern to the HTML identifiers used for these tables: note it for later use.

  2. Construct a suitable httr2 request and verify that it can indeed access the BLS page linked above.

    • A ‘default’ request will receive a 403 Forbidden error when trying to access the BLS page. Refer back to previous Mini-Projects for examples of how you can access BLS resources using httr2.
  3. Write a function to extract the desired data from the 2024 table. (It will be easier to develop your function on the 2024 table rather than the incomplete 2025 table.) Your function should take a single year as input and return a twelve-row data frame structured with the five columns as above.

    Some hints:

    • The column names of these tables are difficult to access since they are spread across three rows. It will likely be easier to select only the relevant table body, pass it to rvest::html_table after disabling header, and to manually set the relevant column names.

    • You will need to use the slice function (or some other slice_*-type function) to select only the first 12 rows from each table.

    • The select function can be used to select columns by position and to rename them at the same time: e.g.,

      library(dplyr)
      penguins |> select(
         bill_length = 3, 
         bill_depth  = 4, 
         body_mass   = 6
      ) |> head(n=5)
        bill_length bill_depth body_mass
      1        39.1       18.7      3750
      2        39.5       17.4      3800
      3        40.3       18.0      3250
      4          NA         NA        NA
      5        36.7       19.3      3450
    • The ym function from the lubridate package will be useful in parsing dates. It takes a string like 1979 Jan and returns a Date object of 1979-01-01. You may need to use string functions to combine multiple columns into a single string vector that can be passed to ym.

  4. Use either the map function from the purrr package or a for loop to apply your function to all years from 1979 to 2025 and to combine the results into a data frame.

    The purrr::list_rbind or dplyr::bind_rows functions will be useful in combining the different years into a large single table.

This should not be a long bit of code when it is all done. My code to do all of these steps totals only 18 lines, generously formatted.

API Usage Required

You must use httr2 and rvest (not httr) to access and process the page directly to download this data.

A primary learning goal of this Mini-Project is to practice use of web scraping for data acquisition. If you download a data file manually, from a different source, use a “wrapper” package, or otherwise avoid scraping the page directly, you will receive a 0 for the Project Skeleton, Code Quality, and Data Preparation portions of your grade.

Data Integration and Exploration

Join together these two tables and perform exploratory data analysis to investigate trends in CES levels and revisions.

Task 3: Data Exploration and Visualization

After joining your two tables, perform both visual (ggplot2-based) and quantitative (dplyr-based) exploratory analysis.

You will need to:

  • Compute at least 6 statistics about CES over the past 45 years
  • Construct at least 4 visualizations of CES estimates and accuracy over the past 45 years.

You can perform any analysis that supports your final write-up (below), but here are some ideas that might be useful:

  1. What and when were the largest revisions (positive and negative) in CES history?
  2. What fraction of CES revisions are positive in each year? In each decade?
  3. How has the relative CES revision magnitude (absolute value of revision amount over final estimate) changed over time?
  4. How has the absolute CES revision as a percentage of overall employment level changed over time?
  5. Are there any months that systematically have larger or smaller CES revisions?
  6. How large is the average CES revision in absolute terms? In terms of percent of that month’s CES level?

Statistical Analysis

While Exploratory Data Analysis (EDA) can inspire questions, it remains useful to perform formal statistical inference to assess whether observed differences are larger than can be explained by pure randomness. The infer package can be used to neatly integrate \(t\)-tests and binomial proportion tests into a tidyverse workflow.

We will use the t_test and prop_test functions from this package to complete our analyses. These can be used as demonstrated below.

  • Example 01: Suppose we want to test whether Gentoo penguins are heavier than Adelie penguins on average. Since we have a numerical response and two different groups, this is a two-sample \(t\) test:

    library(infer)
    library(tidyverse)
    penguins_ok <- penguins |>
        drop_na() |>
        # Things will work better if we ensure species is a character vector 
        # and not a factor vector
        # 
        # You probably don't need to copy this step since your import is unlikely
        # to 'accidentally' make a factor
        mutate(species = as.character(species)) 
    
    penguins_ok |>
        filter(species != "Chinstrap") |>
        t_test(body_mass ~ species, 
               order = c("Adelie", "Gentoo"))
    # A tibble: 1 × 7
      statistic  t_df  p_value alternative estimate lower_ci upper_ci
          <dbl> <dbl>    <dbl> <chr>          <dbl>    <dbl>    <dbl>
    1     -23.3  242. 1.22e-63 two.sided     -1386.   -1504.   -1269.

    From this, we see that Adelie penguins are 1375 grams lighter on average than Gentoos and the \(p\)-value is far less than 0.01, so the difference is unlikely to be solely due to sampling variability.

    Here, we perform the test by specifying the response (quantity of interest) on the left hand side of the ~ and the explanatory variable (that which might meaningfully predict a differerence in groups) on the right hand side of the ~. If we swap the order (or don’t provide it), the sign of the estimated difference may differ, but the actual \(p\)-value won’t change for a two-sided test (as done here).

    We can extend this analysis to perform it separately for each of three years using a bit of nested data trickery. The mechanics of this are more advanced, but you should be able to extend this to your own analysis by just changing variable names:

    penguins_ok |>
    filter(species != "Chinstrap") |>
    group_by(year) |>
    nest() |>
    mutate(p_value_adelie_gentoo = map(data, \(d) t_test(d, 
                                                         body_mass ~ species,
                                                         order=c("Adelie", "Gentoo")))) |>
    unnest(everything())
    # A tibble: 265 × 15
    # Groups:   year [3]
        year species island  bill_len bill_dep flipper_len body_mass sex   statistic
       <int> <chr>   <fct>      <dbl>    <dbl>       <int>     <int> <fct>     <dbl>
     1  2007 Adelie  Torger…     39.1     18.7         181      3750 male      -11.6
     2  2007 Adelie  Torger…     39.5     17.4         186      3800 fema…     -11.6
     3  2007 Adelie  Torger…     40.3     18           195      3250 fema…     -11.6
     4  2007 Adelie  Torger…     36.7     19.3         193      3450 fema…     -11.6
     5  2007 Adelie  Torger…     39.3     20.6         190      3650 male      -11.6
     6  2007 Adelie  Torger…     38.9     17.8         181      3625 fema…     -11.6
     7  2007 Adelie  Torger…     39.2     19.6         195      4675 male      -11.6
     8  2007 Adelie  Torger…     41.1     17.6         182      3200 fema…     -11.6
     9  2007 Adelie  Torger…     38.6     21.2         191      3800 male      -11.6
    10  2007 Adelie  Torger…     34.6     21.1         198      4400 male      -11.6
    # ℹ 255 more rows
    # ℹ 6 more variables: t_df <dbl>, p_value <dbl>, alternative <chr>,
    #   estimate <dbl>, lower_ci <dbl>, upper_ci <dbl>

    Here, we see that our result has columns for the \(t\) statistic, the \(p\)-value, the estimated difference, and many other useful inferential quantities.

  1. Example 02: In other contexts, we may have a categorial response. In this case, we should not perform a \(t\)-test on means, but we instead want to use a binomial proportion test via the prop_test function. For instance, if we want to see whether Adelie penguins are more likely to be female than Gentoos:

    library(infer)
    library(tidyverse)
    penguins_ok |>
       filter(species != "Chinstrap") |>
       prop_test(sex ~ species, 
                 order = c("Adelie", "Gentoo"))
    # A tibble: 1 × 6
      statistic chisq_df p_value alternative lower_ci upper_ci
          <dbl>    <dbl>   <dbl> <chr>          <dbl>    <dbl>
    1   0.00650        1   0.936 two.sided     -0.116    0.141

    As before, we see that there is basically no evidence that the fraction of female penguins differs by species. Note the key difference between the t_test and the prop_test: in t_test the response is a numeric variable and we are testing the mean of that distribution; in a prop_test the response is a Boolean (TRUE/FALSE) value and we are testing the probability of observing a TRUE.5

    We can also use this with a derived quantity. For instance, if we want to see if Gentoos are more likely to be over 4000 grams than non-Gentoos:

    penguins |>
        mutate(is_gentoo = (species == "Gentoo"),
               over_4k = body_mass > 4000) |>
        prop_test(over_4k ~ is_gentoo, 
                  order = c("TRUE", "FALSE"))
    # A tibble: 1 × 6
      statistic chisq_df  p_value alternative lower_ci upper_ci
          <dbl>    <dbl>    <dbl> <chr>          <dbl>    <dbl>
    1      181.        1 3.50e-41 two.sided      0.699    0.828

    Here, we see that there is strong statistical evidence (in the form of a tiny \(p\)-value) that being a Gentoo penguin increases probability of weighing over 4000 grams.

    We can also modify this to be a one-sided test:

    penguins |>
        mutate(is_gentoo = (species == "Gentoo"),
               over_4k = body_mass > 4000) |>
        prop_test(over_4k ~ is_gentoo, 
                  alternative = "greater",
                  order = c("TRUE", "FALSE"))
    # A tibble: 1 × 6
      statistic chisq_df  p_value alternative lower_ci upper_ci
          <dbl>    <dbl>    <dbl> <chr>          <dbl>    <dbl>
    1      181.        1 1.75e-41 greater        0.709        1

    Finally, recall that these values can be pulled out of the test result and used in the body of your text using the pull function from the dplyr package.

Task 4: Statistical Inference

Use the t_test and prop_test functions to perform at least 2 statistical tests about CES revisions.

You can perform any tests that support your final write-up (below), but here are some ideas that might be useful:

  1. Has the fraction of negative revisions increased post-2000?

  2. Has the fraction of revisions of more than 1% increased post-2020?

  3. Is the average revision significantly different from zero?

  4. Has the average revision increased post-2020?

  5. Are revisions larger when the underlying change in CES level is larger?

    You can binarize the CES change as “large” or “not” and use the two sample tests described above or use the cor.test included in base R (not infer).

Fact Check BLS Revisions

Task 5: Fact Checks of Claims about BLS

Go online and find two politicians or commentators talking about CES revisions and the firing of Dr. McEntarfer. Use their claims as the basis of a ‘fact check’ and evaluate them using the Politifact Fact-o-Meter on a scale from “True” to “Pants-on-Fire”.

For each claim, your fact check should include:

  • A hypothesis test of the underlying claim
  • At least 3 numbers (statistics) that you computed from Task 2
  • At least 2 visualizations (plots) from Task 3

At least one of your analyses must use both the absolute levels (Task 1) and the revisions (Task 2). If you cannot find a claim to ‘fact check’ that uses the absolute levels, you can create a fake claim (from a fake politician, clearly marked as such) as the basis of one of your fact checks.

Note that this final write up can be the place where your results from Tasks 3 and 4 are presented.

If the claim you choose to fact check has an explicit partisan basis, the following may be useful:

library(tidyverse)
presidents_party <- tidyr::expand_grid(year=1979:2025, 
                                       month = month.name, 
                                       president = NA, 
                                       party = NA) |> 
    mutate(president = case_when(
        (month == "January")  & (year == 1979) ~ "Carter",
        # BLS jobs reports come out on the first Friday, so February
        # is the first time a new president 'owns' the jobs number 
        (month == "February") & (year == 1981) ~ "Reagan",
        (month == "February") & (year == 1989) ~ "Bush 41",
        (month == "February") & (year == 1993) ~ "Clinton",
        (month == "February") & (year == 2001) ~ "Bush 43",
        (month == "February") & (year == 2009) ~ "Obama",
        (month == "February") & (year == 2017) ~ "Trump I",
        (month == "February") & (year == 2021) ~ "Biden",
        (month == "February") & (year == 2025) ~ "Trump II",
    )) |>
    tidyr::fill(president) |>
    mutate(party = if_else(president %in% c("Carter", "Clinton", "Obama", "Biden"), 
                           "D", 
                           "R")) 

Extra Credit Opportunities

For this mini-project, no more than 4 total points of extra credit may be awarded.

Above, you were required to use the infer package which wraps the traditional (theory-based) Student’s \(t\)-test and binomial proportion test, but the primary aim of the infer package is actually to provide an easy-to-use interface for computationally-intensive statistical inference. For extra credit, you will explore this additional functionality.

In particular, one point of extra credit may be included for each of:

  • Providing a non-technical explanation of computationally-intensive statistical inference. By “non-technical”, I mean at a level suitable for inclusion in a general audience site like Politifact, not a statistics or economics textbook or research paper.
  • Including an schematic visualization of how these computationally intensive methods work. (This is not a ggplot of a sampling distribution) This should be something in a “flowchart” or “how to guide” style, not the results of a specific analysis.
  • Applying computationally intensive techniques in your fact check. (You need to perform a theory-based parametric test, so the infer usage here would be a second statistical test of the same underlying claim.)

To earn any of these extra credit points, you must use computationally-intensive inference, i.e., techniques like the bootstrap or permutation test. It is not enough to simply sample from a parametric null distribution using infer’s hypothesize(type="draw") mode.

Part III of the book Statistical Inference via Data Science will provide useful background on these topics.


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

Footnotes

  1. We will not dwell on the absurdity of reducing the total economic activity of over 300 million people down to a single number here.↩︎

  2. Throughout this section, replace <GITHUB_ID> with your GitHub ID from Mini-Project #00, making sure to remove the angle brackets. Note that the automated course infrastructure will be looking for precise formatting, so follow these instructions closely.↩︎

  3. At the time of writing this assignment, June 2025 is the final month for which all revisions have been published. Given the ongoing lapse in federal government appropriations, it is unclear when revisions to later tables will be released.↩︎

  4. At the time of writing this assignment, June 2025 is the final month for which all revisions have been published. Given the ongoing lapse in federal government appropriations, it is unclear when revisions to later tables will be released.↩︎

  5. Of course, if you haven taken STA 9715, you know that there is only one univariate Boolean distribution (the Bernoulli) and that the probability of observing a success is equal to the mean of the distribution. (\(X \sim \text{Bernoulli} \implies \E[X] = \P(X = 1)\) and all that). This might lead you to ask whether there really is a meaningful difference between a \(t\)-test and a proportion test. These are good questions to ask your STA 9719 professor.↩︎