UC Carpentries Workshop Series · Fall 2026

Tidy Data

Tuesday, September 8 · 9:00 am – 12:00 pm PT · Google Sheets

Library Carpentry, Spreadsheets / Tidy Data for Librarians (CC BY 4.0)
instructor script →
Before we start demo

Everyone: make your copy

  1. Open the practice sheet link from the Etherpad
  2. File ▸ Make a copy - this is now your sheet, in your Drive
  3. Rename it tidy-data-yourname
  4. You'll edit your copy all session. I'll drive a copy of my own on screen.

Helpers: anyone without the link or a Google account, jump in via chat now.

the original is left immutable; your copy is a working copy
To start discuss

Two questions

  • What do you use spreadsheets for? What are they good at?
  • What have you accidentally done in a spreadsheet, or been frustrated you couldn't do easily?

On Zoom: drop answers in the chat. I'll read a few out.

spreadsheets are strong for data entry and quick views; weaker for reproducible analysis and version control
Before we start

Habits for data you're creating

  • One rectangular table per sheet - no side-by-side tables, one table per tab
  • A real header row, row 1, one short name per column
  • One value per cell; one column per variable
  • Raw data is read-only - no notes, no colour, no maths in the data cells
  • Be consistent: same spelling, same units, same date format, every row
  • Fill in zeros where you mean zero; use one null value for missing

Today we practise spotting and fixing where these have been broken, on real messy data.

these are the lesson's keypoints; consistent names and codes are a controlled vocabulary, which librarians already keep
Concept 2 demo exercise

Work in a copy: your first edit

  • The source file is read-only. You never edit what you were given.
  • Work in a named copy - 2016_clean, not Copy of Sheet1
  • A duplicated tab is a working copy, not a backup - keep the raw tab too
Never modify the original raw data.

Everyone, now

  1. Right-click the 2016_messy tab ▸ Duplicate
  2. Rename the new tab 2016_clean
  3. Delete the merged title row and the blank spacer rows
raw data as a single source of truth, kept immutable; the lesson's first rule
Concept 1

The one rule

A rectangular table processes the same way on every row:

  • every column is one variable
  • every row is one observation
  • each cell holds one value for that column

Some layouts are built to be read. A table is built to be processed. You can always build a nice view from a table; you cannot reliably process a pretty layout.

column = one variable ↓
sessiondateregisteredattended
RDM intro2016-03-041812
Open access2016-03-112219
Data mgmt2016-04-011511
Metadata2016-04-082017
Licensing2016-04-15149
← row = one observation
one value per cell
tidy data (Wickham). The grid is rows & columns in a database, cases & variables in stats, observations & variables here
Concept 1 discuss

What would a program choke on?

Look at what's left in 2016_messy. 60 seconds.

Drop one thing in the chat that a script could not read as data.

On Zoom: everyone types at once. No wrong answers; we're building the list together.

you're reading a schema - the column structure a tool expects. When it changes between files that's schema drift
Concept 1 · in practice

One value per cell

GQ & DF trainer_1 → GQ trainer_2 → DF 45|0|0 pgr → 45 pdra → 0 other → 0
  • GQ & DF in one cell is two people
  • 45|0|0 in one cell is three counts
  • If you'd sum, filter, or group by it, it needs its own column
atomic values / first normal form (1NF). The Sheets tool is Data ▸ Split text to columns (splitting on a delimiter)
The core exercise demo exercise

Clean the messy training data

Various people recorded training attendance across 2016 and 2017, each their own way. You need to evaluate the programme and start doing statistics.

Working in your copies, make the 2016_messy and 2017_messy data something a computer can read, and put them together in one table.

How we'll run it

  • I demo the RDM table in 2016_clean
  • You clean the Open access table beside it, then the 2017 tab
  • Check against checkpoint_clean / checkpoint_combined
  • Post your row count in the chat

On Zoom: own copies. Green check = done, red x = stuck. Helpers watch the chat and DM you.

the moves: decomposition (split packed columns), a cancelled flag not colour, consistent nulls; combining years then checking counts is basic reconciliation
Concept 3

Formatting is not data

WHAT YOU SEE RDM training, Spring 2016 session date reg att RDM intro 4 Mar 18 12 Open access 11 Mar (cancelled: grey) WHAT A CSV KEEPS session,date,reg,att,cancelled RDM intro,4 Mar,18,12,no Open access,11 Mar,,,yes title row, colour, merge: gone
  • Merged titles, colour, spacing, row shading: not data
  • Grey-for-cancelled had to become a cancelled column
  • Comments and units in cells go too - use another column
  • Metadata (the Notes tab) belongs in a separate file
separation of data from presentation - the same idea as content vs. style on the web. Colour-as-data is a known anti-pattern
Practice 1

Zeros and nulls

  • Fill in zero when you mean a measured zero
  • Pick one null value for genuinely missing and use it everywhere - for us, a blank cell
  • Never 0 for missing. Never -999.
  • Decide what "missing" means here, write it down, check how the next tool reads it
-999 and 0-for-missing are sentinel values / magic numbers. Missing ≠ not-applicable ≠ zero ≠ unknown is null semantics
Concept 4 discuss

A date has three states

These three cells all display 2016-03-04. What might differ underneath? What could be ambiguous?

2016-03-04 2016-03-04 2016-03-04 1 · Real value stored as a number, shown through a format. =ISNUMBER → TRUE 2 · Text characters that happen to look like a date. =ISNUMBER → FALSE 3 · Real, wrong a genuine date value, with the wrong day in it. =ISNUMBER → TRUE
a stored value vs. how it looks is data type vs. lexical representation; Sheets guessing on entry is type inference. Dates are stored as serial numbers
Concept 4

Locale, and the safe move

  • File ▸ Settings ▸ Locale sets the default date format and how Sheets reads ambiguous date text (03/04/2016 as Mar 4 or Apr 3)
  • Once a real date is stored, locale changes how it looks, not which day it is
  • Don't use ISDATE() - ISDATE("July 20 1969") is TRUE
  • Use =ISNUMBER() / =ISTEXT()
  • Store as year/month/day, or a real date shown yyyy-mm-dd
  • Set the locale on purpose and record it
  • Format with the full year before export
  • After any export, open the file and check the dates
date-text ambiguity is a locale / internationalisation (i18n) problem; yyyy-mm-dd is the ISO 8601 standard
Concept 4 demo exercise

Dates as data

Part 1 · pull the pieces

In dates (2015 data), add three columns: =MONTH(date), =DAY(date), =YEAR(date). Format them as number. Which two rows show the wrong year?

Part 2 · through a CSV and back

Download the dates tab as CSV. Open it in a plain-text editor - what happened to the dates? Re-open it in Sheets - now what?

On Zoom: own copies. Put the wrong-year row numbers in the chat; then say in the chat what the CSV did to the dates.

the wrong-year rows are a data-entry error (entry year vs. event year) that passes every format check; the CSV round-trip is lossy and not reversible
Concept 5

QA blocks · QC finds

QA - at entry "tomrrow" ✗ reject the input
Data validation on num_registered: whole number, 1 to 100.
QC - already there len_hours ↓ 2.0 "90 min" 1.5 1.0
Sort and colour-scale to surface odd values already present.
QA = prevention (process), QC = detection (product). "Reject the input" is a constraint / input validation
Concept 5 exercise

Sort, then colour-scale

Sort

In dates: Data ▸ Sort range ▸ Advanced, tick Data has header row. Sort len_hours largest to smallest.

Notice anything strange? Try other columns.

Colour scale

Select num_attended. Format ▸ Conditional formatting ▸ Colour scale. Any strange values stand out?

On Zoom: own copies, ~6 minutes. Put what you find in the chat.

scanning sorted extremes is range checking / basic outlier detection. Sorting a partial selection corrupts a dataset - always select the whole table
Practice 2

Export to CSV

A CSV KEEPS

  • one table of plain text
  • the values, exactly as displayed

A CSV DROPS

  • formulas, formatting, tabs, validation
  • data types - everything becomes text
  • your change log
  • File ▸ Download ▸ CSV = current sheet only. Five tabs, five files.
  • Format dates with the full year first - a CSV keeps only what's shown
  • GQ, DF is written "GQ, DF" so the comma isn't a new column; the real fix is one value per cell
a CSV is a flat file, machine-readable and non-proprietary; the export is lossy and doesn't round-trip. Library of Congress lists it as a preferred format
Practice 3

Write down what you changed

  • Keep every clean-up step in a plain text file beside the data - the lesson's advice
  • The Notes tab in the workbook shows the wrong way: metadata inside the data
  • "Split trainer column 2026-09-08; 3 rows had two names" is enough
"Why is this number different?" - the answer is your change log.
where data came from is provenance; what happened to it is lineage; the goal is reproducible cleaning
Framing idea

Everything downstream reads your structure

tidy table R / tidyverse Python / pandas a colleague a preservation system ChatGPT · Gemini · Claude tidy → all of them work merged cells → all of them break

AI does not fix messy data. It gives a fluent, plausible answer even when its assumptions are wrong. Fluent is not correct.

reshape-then-hand-off is the "T" in ETL (extract, transform, load); the whole chain is a data pipeline. Fluent-but-wrong output is hallucination
You now have the words

What the field calls this

  • one value per cell → atomic values, first normal form
  • months-as-columns → wide vs long; the reshape is pivoting
  • value vs. how it looks → data type, type coercion
  • yyyy-mm-ddISO 8601
  • date-text ambiguity → locale / i18n
  • one code for "missing" → controlled vocabulary; -999 is a sentinel value
  • reject bad input → data validation, constraint
  • QA vs QC → prevention vs detection
  • CSV → flat file, lossy export
  • keep the raw file + a log → provenance, lineage, reproducibility
  • reshape then hand off → the T in ETL
  • check the AI's rows → reconciliation on a key

You don't need these today. You'll meet them again in R, in a database, in a data-management plan - now they won't be new.

Recap

  • one column for one variable
  • one row for one observation
  • one cell for one value
  • never modify your raw data; always copy first
  • keep your clean-up steps in a plain text file
  • a date is a value plus a display, or just text
  • QA blocks bad input; QC finds bad values already there
  • export to CSV for storage and processing
  • downstream tools, including AI, consume your structure; verify by counting
librarycarpentry.github.io/lc-spreadsheets · Wickham, "Tidy Data", J. Stat. Soft. 59(10) · Cornell, Guide to writing README files · feedback link in the Etherpad