| Analytic Codebook | ||||
blorg_exp1 — Hofman et al. (2020), Experiment 1 |
||||
| variable | description | type | values | missing |
|---|---|---|---|---|
| worker_id | Anonymized Amazon Mechanical Turk worker identifier. The MTurk worker ID was hashed, so it identifies a participant without revealing the account. | character | 1,743 unique values | None |
| condition.f | Four-level experimental condition crossing visualization format and caption text | factor | 1: CI with viz stats only; 2: CI with extra info; 3: PI with viz stats only; 4: PI with extra info | None |
| interval_CI | Visualization format shown to the participant | numeric | 0 = PI; 1 = CI | None |
| text_extra | Whether the caption supplied information beyond the visualization | numeric | 0 = matching text; 1 = extra information | None |
| wtp_final | Willingness to pay to rent the special boulder, in Ice Dollars | numeric | Observed range: 0–249 Ice Dollars; instrument slider: 0–250 | None |
| superiority | Participant's estimate of the probability that the special boulder out-slides the standard one. Collected on a 0–100 scale and rescaled to a 0–1 proportion. Not used in the M09 lab — included so you can explore it yourself. | numeric | 0 to 1 | None |
Analytic Codebooks
A shared documentation standard for PSY 652 projects
What a codebook does
A codebook is the map of the dataset you actually analyze. It tells another researcher what each variable means, how it is represented in R, what counts as missing, where it came from, and whether you changed it.
For PSY 652, every group project uses the same small analytic-codebook format. The goal is not to document every column in a large raw file. The goal is to make the analytic dataset understandable without forcing a reader to open the code and reverse-engineer it.
A word before the details. Writing a codebook is the least glamorous part of a project and one of the most useful — it is the file that lets a reader, a teammate, or you-in-three-weeks understand what a column actually contains. It is also genuinely fiddly the first time: you will not be sure how much detail to put in values, or how to phrase a derivation that took four lines of code. That uncertainty is normal, and it resolves quickly once you have written a few rows. If you are stuck on how to document something, bring the variable to lab and we will work through it together — it is a much faster conversation in person than in writing.
The PSY 652 convention
Create one file:
documentation/codebook.csv
It documents the variables in your final analytic dataset — the variables that enter a table, figure, descriptive calculation, hypothesis test, or another required part of the analysis.
Use these seven columns, in this order:
| Column | What belongs there |
|---|---|
variable |
Exact variable name in your analytic dataset |
description |
Plain-language meaning of the variable |
type |
How the variable is represented in R |
values |
Categories, coding, units, or observed/theoretical range |
missing |
What NA means and any structural missingness or special missing-data rule |
source |
Raw variable(s) from which this variable came |
derivation |
What you did to turn the source variable(s) into this analytic variable |
These seven fields are enough to answer the questions a future analyst usually has first:
What is this? What values can it take? What does missing mean? Where did it come from? Did you change it?
What belongs in the codebook?
Document a variable if it enters the analysis.
That usually includes:
- participant or case identifiers used to check or organize the data,
- focal outcomes,
- grouping variables,
- variables used in Table 1,
- survey weights if you use them,
- variables used to define exclusions or the analytic sample,
- variables shown in a figure,
- and derived variables created with
mutate()or another transformation.
You do not need to document hundreds of unused columns that happen to exist in the raw file. A focused codebook is easier to write, easier to read, and usually more useful.
Raw codebook versus analytic codebook
The organization that collected the data may already provide a large raw-data codebook. Keep it with the source documentation — it remains the authoritative reference for the original file.
Your PSY 652 codebook serves a different purpose. It documents the small set of variables that survived into your analysis, including the recoding and derivation decisions the original codebook cannot know about.
The seven columns, carefully
variable
Use the exact name that appears in the analytic data frame.
Good:
age_group
mde_pastyear
wtp
condition
Not:
Age group variable
Depression
The outcome
A reader should be able to copy the name from the codebook and find the same column in glimpse(analytic).
description
Write a concise definition in ordinary language.
Good:
Past-year major depressive episode indicator
Willingness to pay for the special boulder, in Ice Dollars
Avoid merely translating the variable name:
MDE past year
For a survey item, summarize what was measured. The full question wording can remain in the original questionnaire unless the wording itself is crucial to interpretation.
type
Describe the analytic representation in R, not merely the raw storage format.
Use a small vocabulary:
numericintegerfactorordered factorlogicalcharacterdate
For example, a survey variable may have arrived from SPSS as <dbl+lbl> but become a factor before analysis. The codebook should say factor, because that is the variable the analysis uses.
values
For categorical variables, list the analytic categories in their meaningful order:
No; Yes
18–29; 30–49; 50–64; 65+
Control; Treatment
For numeric variables, give the units and meaningful range when known:
0–10; higher = greater interference
0–250 Ice Dollars
Proportion from 0 to 1
Survey weight; positive numeric
Do not paste a long frequency table here. Frequencies belong in the analysis, not the codebook.
missing
This column deserves care. NA does not always mean the same thing.
Examples:
None expected
DK/refused recoded to NA
Not asked of respondents who reported no social-media use
Missing if fewer than 3 of 4 items were answered
Original file uses blank/NA for item nonresponse
Distinguish structural missingness from ordinary item nonresponse whenever it matters.
Good:
Structurally missing for non-users because the item was not asked
Less useful:
NA = missing
source
Name the raw variable or variables from which the analytic variable came.
Examples:
F_AGECAT
SNSUSE_W163
wtp_final
severity_chores; severity_work; severity_family; severity_social
If the variable entered the analytic dataset unchanged, the source may simply be the same raw name.
This field is especially important in Project 2: it creates the auditable link between the published paper, the shared data file, and your analysis.
derivation
State briefly what you changed.
Useful phrases include:
Unchanged
Renamed only
Converted labelled values to factor; 99 = Refused recoded to NA
1 = Yes and 2 = No recoded to No/Yes factor
Reverse-coded from 1–4 so higher values indicate greater importance
Mean of items A–C among respondents with all 3 observed
Calculated as number_pills / population
The codebook does not replace the R code. It explains the transformation well enough that the reader knows what code to look for and what it was intended to accomplish.
Three common kinds of variables
1 · Variable used essentially as received
variable,description,type,values,missing,source,derivation
wtp,Willingness to pay for the special boulder,numeric,0–250 Ice Dollars,None expected,wtp_final,Renamed only
2 · Recoded categorical variable
variable,description,type,values,missing,source,derivation
any_social_media,Uses social media sites,factor,No; Yes,DK/refused recoded to NA,SNSUSE_W163,1 = Yes and 2 = No recoded to No/Yes factor
3 · Derived variable
variable,description,type,values,missing,source,derivation
age_group,Respondent age group,factor,18–29; 30–49; 50–64; 65+,Refused recoded to NA,F_AGECAT,Converted Pew value labels to factor levels
A more complex derived variable might look like:
variable,description,type,values,missing,source,derivation
severity_scale,Mean interference across four life domains,numeric,0–10; higher = more interference,Missing when the minimum-items scoring rule is not met,severity_chores; severity_work; severity_family; severity_social,Row mean of the four severity items; see the documented scoring rule
Start from this template
Create documentation/codebook.csv with this header:
variable,description,type,values,missing,source,derivation
Then add one row per analytic variable.
A small project might have only 8–15 rows. That is fine. A concise codebook that accurately documents the analysis is much more useful than a 500-row file nobody reads.
Render the codebook inside your Quarto report
Your CSV is the documentation source. Your .qmd can read the same file and render it as a polished table:
library(tidyverse)
library(here)
library(gt)
codebook <- read_csv(here("documentation", "codebook.csv"), show_col_types = FALSE)
codebook |>
gt() |>
tab_header(title = "Analytic Codebook")Here is that code run against a real codebook — the one published for blorg_exp1 on the Course Datasets page
Look closely and you’ll see the table below is missing source and derivation. That is deliberate, and the reason is worth understanding.
You receive the course datasets already prepared. The raw download, the recoding, and the filtering all happened in scripts you never run. So a course codebook only has to answer what is this variable?
Your project data is different: you are the one who prepares it. You download a raw file and build the analytic file yourself, which means nobody reading your project can reconstruct that step from the data alone. source and derivation are where you record it — and for your project they are the two most important columns in the table, because they are the only ones that document work you personally did.
So use the five columns below as the model for how to write a description, a values entry, and a missing entry. Then add source and derivation on top.
This pattern has two advantages:
- the repository contains a simple machine-readable codebook that can be opened in any spreadsheet or text editor; and
- the report always displays the same documentation file rather than a separately maintained copy.
How the codebook relates to the rest of the project
The codebook answers what the variables are.
Other project documents answer different questions:
| Document | Its job |
|---|---|
README.md |
What is this project, and how do I reproduce it? |
data-provenance.md |
Where did the data come from, and how do I obtain them? |
codebook.csv |
What does each analytic variable mean, and how was it constructed? |
| Project 1 plan | What descriptive question are we answering? |
| Project 2 reproduction plan | Which published result are we reproducing, and what exact analysis does it require? |
.qmd report |
What did we do, what did we find, and what does it mean? |
Avoid making one file do all six jobs.
Project 1 example
Suppose your Pew analysis asks how social-media use varies by age. Part of the codebook might look like:
| variable | description | type | values | missing | source | derivation |
|---|---|---|---|---|---|---|
any_social_media |
Uses social media sites | factor | No; Yes | DK/refused → NA |
SNSUSE_W163 |
Recode 1 = Yes; 2 = No |
age_group |
Respondent age group | factor | 18–29; 30–49; 50–64; 65+ | Refused → NA |
F_AGECAT |
Convert labelled values to factor |
WEIGHT_W163 |
Wave-specific survey weight | numeric | Positive numeric | None expected | WEIGHT_W163 |
Unchanged |
Notice what is not in the codebook: whether age_group appears on the x-axis or whether any_social_media is the grouping variable. Those are analysis decisions explained in the report.
Project 2 example
Suppose a paper reports a two-sample t-test comparing CI and PI visualization conditions.
| variable | description | type | values | missing | source | derivation |
|---|---|---|---|---|---|---|
worker_id |
Anonymized participant identifier | character | Unique ID | None expected | worker_id |
Unchanged |
condition |
Visualization condition used in target contrast | factor | PI; CI | None after target-sample filter | condition.f |
Filtered to target conditions and releveled |
wtp |
Willingness to pay for special boulder | numeric | 0–250 Ice Dollars | Rows with missing WTP excluded as specified by paper | wtp_final |
Renamed only |
The reproduction plan then explains that wtp is the continuous outcome and condition defines two independent groups. Keeping those roles outside the codebook lets the same codebook remain a description of the data rather than of one particular statistical command.
Codebook quality check
Before submission, another teammate should be able to open codebook.csv and answer all of these without reading your R code:
- What does each analytic variable mean?
- Which variables are categorical versus numeric?
- What values or categories are possible?
- What does
NAmean for each variable where missingness matters? - Which raw variable(s) produced each analytic variable?
- Which variables were recoded, renamed, or calculated?
- Could I find the corresponding transformation in the
.qmd?
If any answer is no, improve the codebook.
Let the data tell you its properties
There is a division of labor in this file that is worth naming, because getting it backwards is the most common source of codebooks that are confidently wrong.
Some columns describe facts R already knows. A variable’s type, its observed range or set of categories, and how much of it is missing are all properties of the analytic dataset sitting in front of you. Do not fill these in from memory, and do not copy them from the raw codebook — the raw codebook describes the file before your filters, recodes, and exclusions, so its ranges and categories may no longer be true of yours. Look instead:
| To fill in | Ask the data |
|---|---|
type |
glimpse() — it prints the storage type of every column |
values, for a categorical variable |
count() — the levels that actually occur, and how often |
values, for a numeric variable |
range(), or summary() for the quartiles too |
missing |
sum(is.na(x)), and count() if missingness is coded as a category |
A five-second check beats a confident guess, and it catches the errors that matter most: a factor level you thought you had dropped, a 99 that never got recoded, a numeric column silently read in as character.
The other columns carry things R cannot know. No function will tell you what a variable means, why a value is missing, which raw column it came from, or what decision produced it. That is the part only you can write, and it is the part a reader actually needs.
Compute the properties; curate the meaning.
The standard to remember
A good codebook is not long. It is traceable.
A reader should be able to move:
meaning → analytic variable → raw source → documented transformation
without guessing.