--- title: "Getting started with rmoriedata" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with rmoriedata} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(rmoriedata) ``` `rmoriedata` bundles the open-data fixtures used across the `rmorie` ecosystem and ships a small set of analyst-facing helpers for releasing aggregate statistics without re-identification risk. Everything shown here runs **offline** against data that installs with the package -- no network required. The package has four surfaces: 1. **A bundled dataset store** you browse and load by slug. 2. **Named loaders** for the Chicago crime samples, the Ontario SIU director's-report corpus, and the CIHI data-table catalogue. 3. **Differential-privacy mechanisms** (`morie_dp_*`). 4. **Re-identification-risk verifiers** (`morie_k_anonymity_verify`, `morie_l_diversity_verify`, `morie_cell_suppress`). ## 1. Browsing the bundled store Every bundled table lives in a Parquet store. `morie_data_catalog()` lists what's there, with row/column counts and the original source path. ```{r catalog} cat <- morie_data_catalog() table(cat$kind) head(cat[cat$kind == "table", c("slug", "n_rows", "n_cols")]) ``` Load any table by its `slug`: ```{r load} iucr <- morie_data_load("chicago_iucr_codes") head(iucr) ``` Unknown slugs error with guidance rather than failing silently: ```{r load-bad, error = TRUE} morie_data_load("no_such_dataset") ``` Some tables ship a data dictionary (JSON). Find them via the catalogue's `kind` column: ```{r dict} dict_slugs <- cat$slug[cat$kind == "dictionary"] head(dict_slugs) ``` ## 2. The named loaders ### Chicago crime samples Two CRAN-safe slices of the City of Chicago open data ship as lazy-loaded data objects, and `load_chicago_data()` wraps them (with an optional `full = TRUE` network fetch of the complete dataset). ```{r chicago} comp <- load_chicago_data("complaints") dim(comp) head(sort(table(comp$primary_type), decreasing = TRUE), 5) arr <- load_chicago_data("arrests") sort(table(arr$charge_type), decreasing = TRUE) ``` ### Ontario SIU director's reports The first open, machine-readable parse of the Ontario Special Investigations Unit director's-report corpus -- one row per report, 64 structured columns. ```{r siu} en <- load_siu_reports(lang = "en") nrow(en) head(sort(table(en$police_service), decreasing = TRUE), 5) ``` ### CIHI data-table catalogue A catalogue of the public CIHI data-table workbooks, each with a live URL and an Internet Archive fallback so the table stays retrievable if CIHI rotates the file. (`fetch_cihi_table()` does the actual download and is a network call, so it isn't run here.) ```{r cihi} tables <- load_cihi_data_tables() nrow(tables) head(tables$title, 3) ``` ## 3. Data integrity Verify you're using the exact data slice the package shipped: ```{r integrity} ck <- morie_data_checksums() head(ck[order(-ck$bytes), c("file", "bytes")], 3) # The same compiled SHA256 kernel the whole ecosystem uses: morie_core_sha256("abc") ``` ## 4. Differential privacy Release counts, means, and histograms with calibrated noise. Smaller `epsilon` means stronger privacy and more noise. ```{r dp} set.seed(1) # A private count of records matching a predicate. morie_dp_laplace_count(true_count = 42, epsilon = 1.0) # The mechanism is unbiased -- averaging many releases recovers the truth. mean(replicate(2000, morie_dp_laplace_count(42, epsilon = 1.0))) # A private mean of bounded data. x <- runif(1000, 0, 1) morie_dp_gaussian_mean(x, lower = 0, upper = 1, epsilon = 1.0) # A private histogram straight from tabulated data. counts <- as.integer(table(comp$year)) round(pmax(0, morie_dp_laplace_histogram(counts, epsilon = 1.0))) ``` ## 5. Re-identification risk Check a release against the standard disclosure-control thresholds before publishing it. ```{r kanon} df <- data.frame( age = c(25, 25, 25, 32, 32, 40), sex = c("F", "F", "F", "M", "M", "M") ) # k-anonymity: every quasi-identifier combo must appear >= k times. morie_k_anonymity_verify(df, c("age", "sex"), k = 2)$summary # l-diversity: each class must hold >= l distinct sensitive values. df2 <- data.frame( age = c(25, 25, 25, 25, 32, 32, 32), sex = c("F", "F", "F", "F", "M", "M", "M"), dx = c("A", "B", "C", "A", "X", "Y", "Z") ) morie_l_diversity_verify(df2, c("age", "sex"), "dx", l = 3)$summary ``` Cell suppression hides small counts and (by default) applies complementary suppression so the hidden values can't be recovered from the marginals: ```{r suppress} tbl <- matrix(c(120, 3, 47, 88, 2, 99, 14, 51, 60), nrow = 3, dimnames = list(c("A", "B", "C"), c("X", "Y", "Z"))) res <- morie_cell_suppress(tbl, threshold = 5) res$suppressed ``` ## Bridging to Python `load_chicago_data(..., as = "parquet_path")` writes a Parquet file and returns its path -- the recommended hand-off to `pandas.read_parquet()`. Because the store is Parquet throughout, the same tables load natively in R, Python, DuckDB, and Arrow.