Appendix A — Datasets
A.1 What This Appendix Covers
This appendix is the reference you come back to whenever you need to remember how a dataset is structured or what its known quirks are. For every dataset used in the book, the entry below lists:
- Source (publishing agency) and URL
- Filename in the course repository
- Chapters where the dataset is used
- Structure — what each row represents and the full column list with types
- Known quirks — the gotchas you need to handle before analysis
The “Known quirks” block for each dataset is your per-dataset troubleshooting guide. Read it before loading the file for the first time; return to it whenever a new error surprises you.
All datasets are available in the accompanying GitHub repository.
A.2 Colorado Cannabis Sales by County
Source: Colorado Department of Revenue, Marijuana Enforcement Division
URL: https://cdor.colorado.gov/data-and-reports/marijuana-data/marijuana-sales-reports
File: colorado_cannabis_sales_by_county.csv
Used in: Chapter 5, Chapter 9
This file contains monthly medical and retail cannabis sales totals for each Colorado county from 2014 to 2024. The original file is an Excel export with a two-row title block at the top and an eight-row footnote section at the bottom.
Structure: Each row represents one county’s sales for one month.
| Column | Type | Description |
|---|---|---|
| Month | integer | Calendar month (1–12) |
| Year | integer | Calendar year (2014–2024) |
| County | text | Colorado county name |
| Medical Sales | currency string | Medical cannabis sales in dollars |
| Retail Sales | currency string | Retail cannabis sales in dollars |
Known quirks:
- Header row is on row 2 (zero-indexed), not row 0. Use
header=2inread_csv. - Eight footer rows contain footnotes and source information. Use
skipfooter=8. - Sales columns are formatted as currency strings (
$1,234,567) and must be stripped of$and,before numeric conversion. NR(Not Reported) appears in sales columns for counties with fewer than three licensees. Treat as missing withna_values=['NR'].- Rows with
County == 'Total'are monthly statewide aggregates and should be removed before county-level analysis. - County names may contain leading or trailing whitespace.
A.3 Boulder County Voter Registration Data
Source: Boulder County Clerk and Recorder
URL: https://bouldercounty.gov/elections/maps-and-data/data-access/
File: boco_voter_data.txt
Used in: Chapter 6
A pipe-delimited text file containing voter registration records for Boulder County. Each row represents one registered voter.
| Column | Type | Description |
|---|---|---|
| VOTER_ID | text | Unique voter identifier (has leading zeros) |
| VOTER_NAME | text | Full name |
| RES_ADDRESS | text | Residential address |
| RES_CITY | text | City of residence |
| RES_ZIP_CODE | text | 5-digit ZIP code (has leading zeros) |
| PARTY | text | Party affiliation code |
| YOB | integer | Year of birth |
| PRECINCT | text | Precinct number |
Known quirks:
- Delimiter is
|(pipe), not comma. Usesep='|'inread_csv. VOTER_ID,RES_ZIP_CODE,BALLOT_ZIP, andPRECINCTcontain leading zeros and should be loaded as strings using thedtypeparameter.- Party affiliation codes are inconsistent — multiple abbreviations for the same party (e.g.,
DEM,Dem,D,Democrat). - Some text fields contain extra whitespace, non-breaking spaces, or inconsistent capitalization.
A.4 Lahman Baseball Database
Source: Sean Lahman’s Baseball Archive
URL: https://www.seanlahman.com/baseball-archive/statistics/
Files: Batting.csv, Salaries.csv, People.csv, Teams.csv
Used in: Chapter 7, Chapter 8
A comprehensive historical database of Major League Baseball statistics. The book uses four tables from this database.
A.4.1 Batting.csv
Each row represents one player’s statistics for one team in one season. Players traded mid-season have multiple rows (one per “stint”).
| Column | Type | Description |
|---|---|---|
| playerID | text | Unique player identifier |
| yearID | integer | Season year |
| teamID | text | Team abbreviation |
| stint | integer | Order of appearance with team that season |
| AB | integer | At bats |
| H | integer | Hits |
| 2B | integer | Doubles |
| 3B | integer | Triples |
| HR | integer | Home runs |
| BB | integer | Bases on balls (walks) |
| HBP | integer | Hit by pitch (NULL before this stat was tracked) |
| SF | integer | Sacrifice flies (NULL before this stat was tracked) |
Known quirks:
HBPandSFare NULL for early seasons when these statistics were not recorded. Filling with 0 is a common choice but should be documented.- Players traded mid-season appear as multiple rows. Aggregate to one row per (playerID, yearID) before computing season-level metrics or merging with other tables.
A.4.2 Salaries.csv
One row per player per season. Salary data begins in 1985.
| Column | Type | Description |
|---|---|---|
| playerID | text | Unique player identifier |
| yearID | integer | Season year |
| teamID | text | Team abbreviation |
| salary | integer | Annual salary in dollars |
A.4.3 People.csv
One row per player. Biographical information.
| Column | Type | Description |
|---|---|---|
| playerID | text | Unique player identifier |
| nameFirst | text | First name |
| nameLast | text | Last name |
| birthYear | integer | Year of birth |
| birthState | text | State/province of birth |
| birthCountry | text | Country of birth |
A.4.4 Teams.csv
One row per team per season. Franchise-level information.
| Column | Type | Description |
|---|---|---|
| teamID | text | Team abbreviation |
| yearID | integer | Season year |
| franchID | text | Franchise identifier |
| name | text | Full team name |
| W | integer | Wins |
| L | integer | Losses |
| attendance | integer | Season attendance |
A.5 Colorado State Demography Office — Single Year of Age Estimates
Source: Colorado Department of Local Affairs (DOLA), State Demography Office
URL: https://demography.dola.colorado.gov/assets/html/sdodata.html
File: sya-county.csv
Used in: Chapter 7, Chapter 8, Chapter 10, Chapter 12
Population estimates by county, year, and single year of age (0 through 100). Includes both historical estimates and future forecasts.
| Column | Type | Description |
|---|---|---|
| countyfips | text | FIPS county code (with leading zeros) |
| county | text | County name |
| year | integer | Calendar year |
| age | integer | Single year of age (0–100) |
| malepopulation | integer | Male population count |
| femalepopulation | integer | Female population count |
| totalpopulation | integer | Total population count |
| datatype | text | Estimate (historical) or Forecast (projected) |
Known quirks:
- The first row of the CSV is a metadata header. Use
skiprows=1inread_csv. countyfipshas leading zeros and should be loaded as a string.- The
datatypecolumn distinguishes historical estimates from projections. Filter toEstimaterows for historical analysis. - County names use bare names (e.g.,
Adams, notAdams County). This format differs from the CDC and CBI datasets and must be standardized before joining. The standardization process and its consequences are demonstrated in Chapter 10 and Chapter 12. - Contains a
DtypeWarningon some columns due to mixed types.
A.6 CDC WONDER — Underlying Cause of Death
Source: Centers for Disease Control and Prevention, WONDER database
URL: https://wonder.cdc.gov/ucd-icd10.html
File: cdc_deaths.csv
Used in: Chapter 10, Chapter 12
Colorado mortality counts by county, year, age group, and ICD-10 chapter (broad cause of death category).
| Column | Type | Description |
|---|---|---|
| County | text | County name (format: Adams County, CO) |
| Year | integer | Calendar year |
| Age Group | text | Age band |
| ICD Chapter | text | Broad cause of death category |
| Deaths | integer | Number of deaths |
Known quirks:
- County names are in the format
'Adams County, CO'. This must be standardized to match other datasets; see Chapter 10 for the cleaning workflow. - Death counts below 10 may be suppressed for privacy. The value appears as
Suppressedrather than a number. Unreliableflags appear for counts based on small numbers.
A.7 Colorado Bureau of Investigation — Crime Statistics
Source: Colorado Bureau of Investigation
URL: https://coloradocrimestats.state.co.us/
File: cbi_crime.csv
Used in: Chapter 10, Chapter 12
Reported criminal offenses by jurisdiction, date, and offense type.
| Column | Type | Description |
|---|---|---|
| jurisdiction | text | Reporting agency (format: Adams County) |
| offense_date | text | Date of offense |
| offense_type | text | Type of offense |
| county | text | County (may differ from jurisdiction) |
Known quirks:
- County names use the format
'Adams County'(with ” County” suffix but without state abbreviation). Must be standardized before joining with other sources; see Chapter 10 and Chapter 12. - Jurisdiction names do not always map cleanly to county names — some jurisdictions are municipal police departments rather than county sheriff offices.
- Multiple NULL patterns across columns; different columns use different conventions for missing data.
A.8 Boulder County Assessor
A.8.1 Buildings
Source: Boulder County Assessor’s Office
URL: https://bouldercounty.gov/property-and-land/assessor/data-download/
File: buildings.csv
Used in: Chapter 11
One row per improvement section recorded for each parcel. Contains detailed building characteristics.
| Column | Type | Description |
|---|---|---|
| strap | text | Parcel account number |
| bld_num | integer | Building number on parcel |
| section_num | integer | Section within building |
| bldg_class | text | Building class (R = residential, C = commercial) |
| quality_grade | text | Construction quality rating |
| year_built | integer | Year of construction |
| above_ground_sqft | integer | Above-ground square footage |
| heating_type | text | Heating system type |
| roof_type | text | Roof material |
Known quirks:
- Some text columns have trailing whitespace.
- Placeholder zeros in categorical columns should be treated as missing.
- Multiple rows per parcel account number (one per building section).
A.8.2 Residential Sales
Source: Boulder County Assessor’s Office
URL: https://bouldercounty.gov/property-and-land/assessor/sales/
File: ar-rec-2025-residential.xlsx
Used in: Chapter 6
Residential property sales records.
| Column | Type | Description |
|---|---|---|
| ACCOUNTNO | text | Property account number (has trailing whitespace) |
| PROPERTY_ADDRESS | text | Street address |
| LOCCITY | text | City |
| SALE_DATE | datetime | Date of sale |
| SALE_PRICE | mixed | Sale price (contains $, commas, and text like PRIVATE SALE) |
Known quirks:
ACCOUNTNOhas trailing whitespace that must be stripped.SALE_PRICEcontains currency formatting and non-numeric values likePRIVATE SALE.- Multiple rows per
ACCOUNTNO(representing different sale transactions over time).
A.9 Non-Tabular Data Sources
The five chapters in Part IV use specialized datasets — shapefiles, edge lists, text corpora, time series, and API responses. Each chapter’s examples assume one or more of the sources listed below.
A.9.1 Census TIGER/Line Shapefiles (Chapter 13)
Source: US Census Bureau URL: https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html Files: tl_2023_08_county.shp (Colorado counties) and companion .shx, .dbf, .prj files Used in: Chapter 13
County and state boundary polygons for the entire United States, republished annually. The Colorado-specific file (08 = state FIPS) is a good default for the book’s spatial examples.
Known quirks:
- A shapefile is actually several files (
.shp,.shx,.dbf,.prj). Keep them together in the same folder. - Default CRS is
EPSG:4269(NAD83 latitude/longitude). Reproject toEPSG:3857for overlays on web basemaps. - Each county has a
GEOID/COUNTYFPthat matches thecountyfipscolumn in the State Demography Office data.
A.9.2 ICON / KONECT / Network Repository Edge Lists (Chapter 14)
Sources: ICON (CU Boulder), KONECT (Koblenz), Network Repository Example files: soc-karate.edges (Zachary’s karate club), soc-dolphins.edges (dolphin social network) Used in: Chapter 14
Small, curated network datasets suitable for teaching. Zachary’s karate club (34 nodes, 78 edges) is the single most common beginner example.
Known quirks:
- Edge-list files often start with comment lines prefixed by
%(KONECT) or#. Usecomment='%'inpd.read_csvto skip them. - Many datasets ship as whitespace-delimited
.edgesfiles, not.csv. Passsep=r'\s+'orsep=' 'topd.read_csv. - Node IDs are typically integers. Cast consistently before building a graph to avoid “node not in graph” errors.
A.9.3 Project Gutenberg and NLTK Corpora (Chapter 15)
Sources: Project Gutenberg, NLTK built-in corpora Example files: 2021-biden.txt (Project Gutenberg), inaugural corpus (NLTK built-in) Used in: Chapter 15
The NLTK inaugural corpus contains every US presidential inaugural address (1789–present) as plain text, accessible via nltk.corpus.inaugural. Project Gutenberg distributes public-domain literature in UTF-8 text.
Known quirks:
- Project Gutenberg files include a boilerplate header and footer that must be stripped before analysis.
- NLTK corpora require a one-time
nltk.download('inaugural')(and similar for other corpora and resources likepunkt,stopwords,wordnet,vader_lexicon). - Encoding is UTF-8 for recent files; older Gutenberg texts may arrive as Latin-1. Pass
encoding=explicitly.
A.9.4 FRED / World Bank / IMF Time Series (Chapter 16)
Sources: FRED, World Bank Open Data, IMF Data Example files: UNRATE.csv (US unemployment rate, monthly), CPIAUCSL.csv (CPI, monthly), HOUST.csv (housing starts, monthly) Used in: Chapter 16
FRED publishes thousands of US macroeconomic series as downloadable CSVs with two columns: DATE and the series value. World Bank data arrives in wide format (one column per year) and requires melt to reshape into long.
Known quirks:
- FRED files use
DATEas an ISO date column. Parse withpd.to_datetime(df['DATE'])and set as the index. - Some series have “.” or blank rows for missing observations (e.g., during data-collection gaps). Treat these as
NaNviana_values=['.', '']. - World Bank CSVs include 4 metadata rows at the top. Use
skiprows=4. - IMF files sometimes require joining a separate country-code reference file before they are usable.
A.9.5 Public APIs for Structured Data (Chapter 17)
Sources: FRED API, Census Bureau API, OpenAlex API, Wikipedia/MediaWiki API, Open Library API Example file: example_openalex_response.json (cached API response), any static Wikipedia page for HTML scraping Used in: Chapter 17
All five APIs above are free; most require only a User-Agent header (or, for the OpenAlex “polite pool,” a mailto query parameter). The chapter includes worked examples against OpenAlex.
Known quirks:
- FRED, Census, and Open Library require registration for an API key. OpenAlex and Wikipedia are unauthenticated.
- Every API paginates differently — some use
page=N, some use a cursor token, some useLink:headers. Read the docs before looping. - Rate limits are real. Respect them with
time.sleep()between requests, and cache responses to disk during development. - API responses are JSON; flatten with
pd.json_normalize()to get a clean DataFrame.
The datasets described in this appendix represent what is publicly available — what agencies have chosen to publish, in the formats they chose to publish it. That is a narrower set than what exists or what would be useful for public accountability.
Noticeably absent from what is publicly available at a useful granularity:
- Housing displacement records at the parcel level — public records exist, but parcel-level linkage to eviction or code enforcement actions is rarely published.
- Policing data at the incident level — Colorado requires some reporting, but stop-and-frisk data, use-of-force details, and officer-level records are inconsistently available across jurisdictions.
- Detention and incarceration populations — county jail populations are not systematically published in machine-readable form.
- Environmental health data — air quality monitoring stations cover urban centers but are sparse in rural counties and on Tribal lands.
Exemption — data that does not exist publicly, or is not released — is itself a data quality problem. The questions you cannot answer because the data is missing are often the most important ones to ask.
When you finish an analysis, it is worth asking: what would you study if you had access to data that is not currently available? That question is as analytically important as what you did study. See Chapter 4 for the broader framework.
A.10 Further Reading
- Colorado Department of Revenue — Marijuana Sales Reports — cdor.colorado.gov
- Boulder County Clerk and Recorder — bouldercounty.gov/elections
- Sean Lahman’s Baseball Archive — sabr.org/lahman-database and Chadwick Bureau’s maintained copy on GitHub
- Colorado State Demography Office — demography.dola.colorado.gov
- CDC WONDER — wonder.cdc.gov and WONDER help
- Colorado Bureau of Investigation Crime Statistics — coloradocrimestats.state.co.us
- Boulder County Assessor — bouldercounty.gov/property-and-land/assessor
Finding new datasets: Data.gov aggregates federal sources, CO Information Marketplace publishes Colorado state data, and your local city/county usually has an open-data portal. When evaluating a new source, always check what is published, when it was last updated, and what machine-readable formats are available.