Skip to content

canpumf

0.6.0Package record

Parse StatCan PUMF Files

0packages depend
1.4Kdownloads / year
69.5%test coverage
13/13flavors OK

Overview

About

Facilitate working with Statistics Canada (StatCan) Public Use Microdata Files (PUMF). Enables downloading of available PUMF data, parsing of metadata from command files or other sources to infer the layout structure, variable labels and value labels as well as missing data values, and returns a connection to a 'DuckDB' database with the labelled data. Data and documentation come from Statistics Canada's Public Use Microdata Files https://www.statcan.gc.ca/en/microdata/pumf, distributed under the Statistics Canada Open Licence https://www.statcan.gc.ca/en/terms-conditions/open-licence.

Changes in 0.6.0

Historical Labour Force Survey and a 1976-onward LFS timeline

The LFS microdata now span 50 years. The monthly public-use files for 1976–2005, which Statistics Canada does not post for download, are loaded from Borealis and can be stacked with the current LFS in one harmonised table.

  • New series "LFS_HIST" loads the monthly LFS PUMFs for January 1976 to December 2005 from Borealis (ODESI), in the legacy pre-2017 layout: get_pumf("LFS_HIST", "1995-06") loads one month, and get_pumf("LFS_HIST", "1995") loads all twelve months of a year. Like "LFS", every loaded month is appended to one shared database (LFS_HIST/LFS_HIST.duckdb), so the whole period can be queried as one table. refresh = "auto" loads every month not yet present. French labels come from the French ODESI deposits.
  • ODESI labelled the same codes differently from era to era ("Unemployed, temporary layoff" / "Unemploy,temp layoff"). Loaded month by month, that would give one factor level per spelling. LFS_HIST therefore ships one harmonised bilingual dictionary, built from the SAS setup files of all 718 monthly deposits (tools/build_lfs_hist_reference.R). Each code gets its most recent wording, and codes whose meaning changed are curated by hand. Each month is still checked against its own setup file when it is loaded.
  • New get_lfs_timeline() returns one lazy table spanning "LFS_HIST" and "LFS", 1976 onward, with a curated common schema. Variables with identical codes carry the current labels. LFSSTAT, MARSTAT, CMA, SCHOOLN, AGYOWNK, the industry groups (NAICS_18), education (1990 onward) and sex/gender are recoded to common categories. Hours and wages are in plain units, and the weight is FINALWT. The two databases stay separate and are attached read-only, so the timeline never takes or waits for a write lock. The mappings ship in inst/extdata/lfs_timeline/ (tools/build_lfs_timeline_reference.R). refresh = "auto" first brings both series up to date, so an analysis script that calls get_lfs_timeline(refresh = "auto") always picks up newly released LFS months.
  • The LFS vignette has a new section on the long timeline: loading "LFS_HIST", 50 years of unemployment and participation rates by gender, wages by CMA, and caveats for working across eras.
  • The LFS database engine is now a general framework for *longitudinal* series (time slices sharing nearly the same variables, appended to one database per series). LFS and LFS_HIST are its two instances. label_pumf_columns(), pumf_metadata(), list_pumf_cache(), remove_pumf_cache() and open_pumf_documentation() handle both series. LFS behaviour is unchanged.
  • The import was validated against Statistics Canada table 14-10-0287. For all 360 months the weighted population matches the published unadjusted estimates exactly, by province, gender and age group. Employment and unemployment match to rounding, except for January 1985 to November 1986: there the published series appears to carry a revision the public-use files lack, and microdata unemployment runs about 1.2% above the published figure (#23). The same issue documents the problems found in the Borealis/ODESI metadata and how LFS_HIST works around them.

New features

  • **PUMF data can now be loaded from the Borealis Dataverse**, which hosts the ODESI collection of Statistics Canada PUMFs. Statistics Canada stays the primary source. The 1971, 1976, 1981 and 1986 Census PUMFs, which StatCan distributes only by EFT, are now downloaded from Borealis automatically — get_pumf("Census", "1971") works out of the box. A deposited EFT bundle is still preferred when present; add "eft" or "borealis" to the version to choose explicitly. The Borealis copies carry English labels only. For 1971 they are also more accurate than the EFT text files, whose negative household incomes use a sign overpunch the fixed-width reader does not decode.
  • Any other Borealis PUMF dataset can be loaded with get_pumf(series, version, borealis = "doi:..."). New list_borealis_pumf_catalogue() browses the collection (cached, and persisted to the cache directory) and list_borealis_pumf_files() lists a dataset's files. The catalogue's statcan column marks datasets that Statistics Canada also posts for direct download, together with the matching StatCan title. Prefer StatCan's copy for these, since the Borealis re-deposits can carry transcription errors. get_pumf(borealis =) warns when asked for such a dataset. Setting BOREALIS_DATAVERSE_KEY gives access to restricted files.
  • Registry entries accept a borealis field (list(doi =, files =)), also via pumf_registry_entry().
Show all changes in 0.6.0Hide the rest of the changes in 0.6.0
  • **Truncated labels are now repaired from the survey's user guide.** Statistics Canada's shipped command files routinely carry damaged value and variable labels — hard cuts at 60 characters, dropped leading text, dropped interior text. The damage is upstream of the flavour-specific renderers (the SAS, SPSS and Stata copies of a file agree byte for byte), and it is quiet: codes and frequencies are correct, only the human-readable label is wrong. A ninth metadata parser, parse_pdf_freq_codebook(), reads the data-dictionary appendix of a PUMF user guide (GSS cycles, SGVP, PALS, SFS, Time Use), which carries the full text.
  • Trusting a PDF scrape over a machine-readable command file would normally be a bad trade. What makes it a good one here is that this appendix prints the **frequency of every code**, so the parse is reconciled against the actual data file before any of it is believed, and a label is replaced only where the guide's text *demonstrably extends* the command file's — a strict superstring, or a subsequence sharing a long anchor ("Single-ded house" → "Single-detached house"). For GSS Cycle 16 this repairs 2,865 labels across the four modules with no variable contradicting the data.
  • A repair additionally requires evidence that the label it replaces was *damaged*. Some guides print the full question wording where the command file carries a hand-written short label ("How many hours do you work per week" against "How many hours do you (does ....) usually work per week?"); these are different fields, not a truncation, and the abbreviation is often a subsequence of the question, so the text-shape test alone would rewrite good labels into questions. A hard cut leaves a spike of labels at a fixed ceiling — GSS Cycle 16 has 1,665 of 1,860 variable labels at 59–60 characters against 42 in the six lengths below — while a hand-abbreviated set thins out towards its longest entry. Labels are only repaired where that ceiling exists and the label sits at it; everything else is flagged.
  • Dropped *leading* text leaves a short label rather than one at a ceiling, so it carries its own signature: what survives is a strict suffix of the guide's text ("relative in a family farm or business?", "les réserves indiennes)"). Two things that are not damage produce the same shape — a guide that prefixes an editorial note onto a label the command file has in full (SGVP 2007's "Grouped variable: Age group"), and a guide leaking its own field header into the text ("Longueur : 2 Age du répondant …"). Both are rejected by looking at the *dropped* text rather than at what survived: StatCan writes these as "Key: value", while text lost to truncation is running prose. That distinction is what lets the mid-list case be repaired — GSS Cycle 16's value label "Co-worker of respondent and Other relatives)", which is really the tail of "Other (Do not include organizations here) (Includes …)" and reads as a category about co-workers, starts with a capital exactly as an intact label would. Together these take SGVP from 35 repairs to 1 and PALS 2006 from 245 to 100, while GSS Cycle 16 keeps 2,860 of 2,865.
  • The guide is also checked as a *document* before any of it is used, against two independent channels: whether its printed counts reproduce a tabulation of the data, and whether its printed field positions reproduce the command file's layout. A guide failing both is the wrong document and is discarded whole. A release shipping both its original and revised user guide (PALS 2006) is disambiguated the same way — the two describe different field positions, and only the layout tells them apart. Where the positions agree but the counts do not, the guide's frequencies were simply tabulated on another base (PALS 2006 computes its over the disability sub-population) and are treated as absent rather than as contradiction.
  • Nothing is repaired silently. New pumf_label_repairs(tbl) returns every divergence found — repaired, filled, or merely flagged — with both texts, the reason, and the variable's validation status; new pumf_freq_validation(tbl) reports per variable whether the guide's frequencies reconciled. Substantive disagreements (where the guide and the command file say different things rather than one being a truncation of the other) are always flagged rather than applied. Set options(canpumf.pdf_crosscheck = FALSE) to skip the step.
  • The guide's frequency tables are read off the number column nearest the FREQ header word rather than by walking right from it. The columns are right-aligned but pdftools reconstructs them with a few characters of drift, so walking out stopped at a thousands comma (reading 9,520 as 9) and never reached a value printed further right than its neighbours (reading a bare 0 as absent). A code row's label is also now optional, so a 0–10 scale that labels only its endpoints keeps the counts for the nine bare codes in between. Together these take the GSS Cycle 26 guide from 4 contradicted variables to none across all 610.
  • Codes the guide documents but the command file never declared are reported, never injected — that stays a registry codes_supplement decision. The report covers only variables the command file treats as categorical: where it declares no codes the variable is continuous, and the guide's zero-value rows ("No hours", "None", "Aucun don") label a valid numeric zero rather than a code the command file forgot.
  • The **Canadian Health Survey on Seniors** (CHSS, 2019-2020) is now supported and directly downloadable: get_pumf("CHSS", "2019-2020"). The survey ships 1000 bootstrap replicate weights, joined onto the main table like the other BSW surveys.
  • The **Participation and Activity Limitation Survey** (PALS, 2001 and 2006) is now supported and directly downloadable: get_pumf("PALS", "2001"). Both editions ship one archive holding a complete English and French copy of the release; the French command file is paired automatically and supplies the French labels.
  • PALS 2001 ships no flat data file — only the SAS dataset the flat file would have been built from — so Stage 3 now reads .sas7bdat data with haven when that is the file the registry selects. Its coded numeric columns are rendered back to their code strings so the usual label mapping applies unchanged.
  • The SAS command-file parser now understands quoted character codes in PROC FORMAT ("01" = "...", as SAS datasets with character columns require) and the French phrasing of StatCan's variable/format association comment (/* $FMT s'applique à: VAR1 VAR2 */).
  • New data_fixups field rename_regex rewrites many column names at once (c("^A" = "")), for releases whose data file decorates the documented variable names wholesale — the PALS 2001 SAS dataset ships StatCan's *collection* names, which prefix 632 of its 758 columns with an "A". A rewrite is applied only where it lands on a name the metadata declares and the current name is not itself declared, so it cannot collide with a correctly-named column.
  • New data_fixups field missing_codes blanks a discrete set of per-variable missing codes, for variables whose sentinels do not form one contiguous range and which a single missing_low/missing_high pair therefore cannot express. PALS 2006 AUDE_Q02 (hours usually worked) declares −5/−6/−7 below and 998/999 above the valid 1–97 hours, so the derived range would have blanked the whole column.
  • New registry field download_format pins which format bundle to fetch when Statistics Canada offers the same edition as several downloads (CSV / SAS / TXT). It is needed when only one bundle carries the command files the metadata parsers depend on — the CHSS CSV zip ships the data alone, while the TXT zip additionally carries the SPSS layout cards. The field is also accepted by pumf_registry_entry() for user-supplied entries.
  • The SAS @position INPUT-card parser now understands the indexed-array shorthand StatCan uses for bootstrap-weight cards (@28 (BSW1-BSW1000) (1000* 7.2)), expanding it into one layout row per weight. Bootstrap-weight command files are also now found when they sit outside the survey's SPSS card directory and are not named layout* (CHSS ships Layout_Cards/bsw_i.sas); SAS cards are preferred over their companion .sps, whose column specs are sometimes left implicit.
  • Fixed-width bootstrap-weight files are now read with the decimal point implied by the card's w.d informat, matching SAS/SPSS semantics — without this, CHSS replicate weights would have been 100 times too large. The correction is applied before the missing-value range (which documentation states in display units) and only where the raw field carries no explicit ..

Dependencies

  • duckplyr is no longer a dependency. curl and jsonlite are new in Imports, for the Borealis API.

Bug fixes

  • Labelled non-response codes of numeric variables are now set to NA even when the command file declares no MISSING VALUES for them. Before, only a declared range, or the range derived for force_numeric variables, removed them, so values such as GSS Cycle 21 AGE_DIV_MA1 999.7 ("Not asked"), Cycle 25 CHDCARE_*_COST 9999.97–9999.99 and the Cycle 21 and 26 health utility index HLTH_UTIL_INDEX 7/9 ("Not asked", "Don't know"; valid range −0.31 to 1) stayed in as real numbers. Stage 3 now takes every code whose English or French label is a true-missing label and blanks it as a discrete code, so valid values that fall between sentinels are kept. Labels with a qualifier also count ("NOT APPLICABLE(DOES NOT DRIVE)", GSS Cycle 8 D11; "Non demandé - aucun enfant dans le ménage", Cycle 24 AGECHRYC). Zero labels ("None") and composite labels ("zero income, not applicable") are left as values. Rebuild with refresh = TRUE: GSS Cycles 8, 17, 21, 24, 25 and 26.
  • GSS Cycle 17 (2003) no longer forces 236 categorical variables to numeric. Its force_numeric list covered almost every labelled variable, so SEX, PRV, YRARRI, EDU5, the Likert items and the rest arrived as bare numbers instead of labelled factors. Only the six count/age variables with a top-code label (AGECHRYC, OMA_Q110, MAR_Q161, WKWEHR, WKWEHOHR, MAR_Q315) are still forced.
  • force_numeric can no longer turn a fully labelled variable into numbers. Labels are strong evidence of a category, so the only legitimate use of the override is a count, age or amount variable whose data is mostly unlabelled, with labels only on a top code or on sentinels. Stage 3 now ignores the override for any variable whose every data value is labelled. Besides Cycle 17, this restores GSS Cycle 12 DDAY (Sunday–Saturday), GSS Cycle 24 TIMECR/TIMENS ("Zero Yes codes"…) and 1971 Census SUBSAMPL in the individual and family files (ONE–FIVE) as factors. The dead Cycle 12 and 24 entries were removed from the registry. Rebuild with refresh = TRUE: GSS Cycles 12 and 24, and the 1971 Census individual and family files.
  • Fixed-width main data files are now also read with the decimals their command file implies — a DATA LIST ( 4 ) or SAS w.d informat — where the raw field carries no explicit .. The older cards pad the parentheses (WGHTFNL 6 - 14 ( 4 )), which the parser did not recognise, so the weights of GSS Cycle 8 (1993) and Cycle 9 (1994) were 10,000 times too large and the 1981 Census households FAMWGT (EFT copy) 100 times too large. Display FORMATS decimals do not change the stored value and are not applied. Layout decimals are recorded in a new optional decimals column of layout.csv; caches written before it read as having none.

The NEWS section is longer than shown here.

From NEWS.md in the release

Install

Health

CRAN checks
13OK
Slowest check: 2.9 min · r-oldrel-windows-x86_64
Status changes
  • OK13 OK2026-09-30
  • ERROR12 OK, 1 ERROR2026-09-04
  • OK13 OK2026-08-05
  • NOTE12 OK, 1 NOTE2026-08-01
  • OK7 OK2026-07-04
Advisories

none known

Documentation

In release 0.6.0
READMEYes · 2,025 wordsVignettesYes · 7 · evaluation depends on the environmentNEWSYes · 100% structured · mentions 0.6.0Citation fileNoWebsiteYes · pkgdown
Help pages
59 (33 internal)
Examples that run
12%3 run in a plain check (1 of them under a condition) · 22 only when donttest examples are enabled (R CMD check --as-cran) · 1 never run
Exported functions with examples
100%
Documented parameters
90%
Return-value docs
100%
Help pages citing references
0%

Downloads

1.4K
CRAN downloads in the past year
Rank #7,910 · ~4/day · ~119/mo
Daily download trend is not available in this view yet.
54930 days
1.1K90 days
1.4K1 year
Compare downloads with other packages →
Also on32 r2u15 autocran

Repository

8Stars
3Forks
11Open issues
1Open PRs
4Releases
292Commits
2Commit identities
292 commits · Last activity 2026-09-25 · 0% stars, 30d
Responsiveness
How these are sampled
PRs merged (all time)
83%
Median days to close, 50 most recently updated closed issues
8
Median days to close, 50 most recently updated closed PRs
27

Stars over time

2025-04-11 · 72026-07-07 · 8
PracticesBeta

5 development-tooling and community-health practices detected across 3 families in the upstream repository

Checks run against github.com/mountainmath/canpumf on 2026-10-21.

Continuous integration (2)
GitHub ActionsR CMD check workflow

The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel

Docs source (2)
pkgdown

GitHub Pages site last deployed 2026-09-25

pkgdown site last built 2026-09-25

CRAN release process (1)
cran-comments.md
How this is detected·Detection ruleset v4 (2026-10-20)
AI coding toolsBeta

This repository shows signs of AI coding tools.

  • Claude Codefirst seen 2026-05-24
    Seen in the repository: .claude
    Named in .Rbuildignore: .claude
    Pull request it wrote: opened by a project member
    Commits: at least 174 crediting it in the message
Models named in its commits
  • Claude Sonnet 4.6100 commits · Jun 2026
  • Claude Opus 5.512 commits · Sep 2026
  • Claude Fable 52 commits · Aug 2026
  • Claude Opus 4.82 commits · Jun 2026

Some of these counts are a minimum, because the search stopped before the oldest commits.

Counts are commits, not lines of code. Commits by a tool's accounts count once across all of its accounts. Commits crediting it are the largest count among its credit lines, a minimum.How this is detected·Detection ruleset v4 (updated 2026-09-27)

Dependencies

Declared dependencies
27 external dependencies (excludes base and recommended)

Installing canpumf adds 47 packages (27 with compiled code, 33 MB of source tarballs). Heaviest: stringi 11 MB, duckdb 7.9 MB, openssl 1.1 MB.

Depends (1)
R >= 4.2
LinkingTo (0)
none
Enhances (0)
none
Reverse dependencies
0direct
0indirect

Nothing depends on this yet.

Datasets

People & History

People (1)
Author, Maintainer since 0.5.2 (2026)
Releases (2)

Pick two releases to compare their code metrics.

  • 0.6.0Latest
    record
    2026-09-25 · current release · diff ↗ ·
    added 5 exports
    get_lfs_timeline, list_borealis_pumf_catalogue, list_borealis_pumf_files, pumf_freq_validation, pumf_label_repairs
  • 0.5.2
    record
    2026-07-03
  • R
    R 4.6.0 released · 2026-04-24

Package metadata

First published
2026-07-03
Total releases
2 / 1 yrs
License
MIT + file LICENSE OSI
Minimum R
≥ 4.2
Download size
1.2 MB

Cite

Cite this package

Run in R for the authors' preferred citation:

citation("canpumf")
von Bergmann, J. (2026). canpumf: Parse StatCan PUMF Files (Version 0.6.0) [Computer software]. https://doi.org/10.32614/CRAN.package.canpumf

This package has no citation file, so citation() returns this entry built from DESCRIPTION.

Cite the R Observatory

For a number measured here: a download total, a coverage figure, an archival date.

APA

Balamuta, J. J. (2026). R Observatory: Metrics for canpumf version 0.6.0 [Data set]. HJJB, LLC. Data release v2026-10-23. https://doi.org/10.5281/zenodo.21843040

From data release v2026-10-23, which the citation names so these numbers can be found later. More on citing and the projects behind them.

Report a problem with this page →

Privacy choices

These apply to this browser and are stored on this device only. Nothing about your choice is sent to us.

Read the privacy policy