The pipeline is driven by two kinds of reference data: crosswalks (curated lookup tables shipped as package data) and word lists (character vectors shipped as package data used by the regex-based cleaning steps).
Crosswalks
The four crosswalks are package data (title.xwalk, title.patterns, title.taxonomy, status.codes). Their source is the CSV tables in data-raw/crosswalks/ of the source repository: edit a table, then run data-raw/crosswalks/build-crosswalks.R to rebuild the package data. (Until October 2026 the crosswalks were kept in a Google Sheet; it is retired, and an export of every tab is archived in data-raw/crosswalks/archive/.)
Title standardization (get_title_xwalk())
Maps every observed title variant to a canonical title.standard, plus a strata / strata.label for board sub-roles. Used in step 07, standardize_titles().
xwalk <- get_title_xwalk()
dim(xwalk)
#> [1] 9181 4
head(xwalk, 8)
#> title.variant title.standard strata strata.label
#> 1 NO TITLE
#> 2 AAA DIRECTOR DIRECTOR
#> 3 AAC ATHLETE REPRESENTATIVE BOARD MEMBER
#> 4 AAFP DELEGATE BOARD MEMBER
#> 5 AAJ DELEGATE BOARD MEMBER
#> 6 AAJ GOVERNOR BOARD MEMBER
#> 7 AAJ PRESIDENT BOARD MEMBER
#> 8 AAMD LEADERSHIP BOARD MEMBERTitle patterns (get_title_patterns())
Head rules for titles the standardization crosswalk does not list: a title whose longest known prefix or suffix has a rule maps to that rule’s title.standard (title.match is pattern). Each rule records its support (titles it was learned from) and precision. Used in step 07, standardize_titles().
pat <- get_title_patterns()
dim(pat)
#> [1] 121 6
head(pat, 6)
#> position head title.standard rule support precision
#> 1 prefix ACTIVE BOARD MEMBER majority 6 0.833
#> 2 prefix ADVISORY BOARD MEMBER majority 8 1.000
#> 3 prefix AFFILIATE BOARD MEMBER majority 5 1.000
#> 4 prefix ALPHA BOARD MEMBER majority 16 1.000
#> 5 prefix ALT BOARD MEMBER majority 11 1.000
#> 6 prefix ALTERNATE BOARD MEMBER majority 16 0.875Title taxonomy (get_title_taxonomy())
Maps each canonical title.standard to its taxonomy dimensions: functional domain.category / domain.label, the BLS SOC occupation codes, and its role. A title is either an employee level or a board role:
-
emp.level:-
CEO: the top staff job. -
OFFICER: C-suite, vice presidents, deputies. -
MANAGER: directors of departments, managers. -
PROFESSIONAL: non-managerial jobs often reported for their pay, such as physicians, lawyers, professors and coaches. -
STAFF: everything else.
-
-
board.role:CHAIR,VICE CHAIR,SECRETARY,TREASURERorMEMBER.
The legacy flags (ceo, c.level, mgr, spec, board, pres, …) are derived from these two columns. dir.vp is retired. Used in step 08, categorize_titles().
tax <- get_title_taxonomy()
dim(tax)
#> [1] 450 22
head(tax[, c("title.standard", "domain.label", "soc.label",
"emp.level", "board.role")], 8)
#> title.standard domain.label
#> 1 ACCOUNTANT finance
#> 2 ACCOUNTING DIRECTOR finance
#> 3 ACTOR arts and history
#> 4 ACTUARY finance
#> 5 ADMINISTRATION DIRECTOR administration
#> 6 ADMINISTRATION OFFICER administration
#> 7 ADMINISTRATIVE ASSISTANT administration
#> 8 ADMINISTRATOR administration
#> soc.label emp.level board.role
#> 1 Accountants and Auditors PROFESSIONAL
#> 2 Financial Managers MANAGER
#> 3 Actors PROFESSIONAL
#> 4 Actuaries PROFESSIONAL
#> 5 Administrative Services Managers MANAGER
#> 6 STAFF
#> 7 Secretaries and Administrative Assistants STAFF
#> 8 Administrative Services Managers MANAGER
table(tax$emp.level)
#>
#> CEO MANAGER OFFICER PROFESSIONAL STAFF
#> 15 11 129 139 40 116
table(tax$board.role)
#>
#> CHAIR MEMBER SECRETARY TREASURER VICE CHAIR
#> 445 1 1 1 1 1Status codes (get_status_codes())
Maps status-qualifier variants (e.g. ACTING, EMERITUS, INTERIM) to a standardized status.qualifier (e.g. INTERIM, FORMER). Used in step 06, gen_status_codes().
sc <- get_status_codes()
dim(sc)
#> [1] 294 2
head(sc, 8)
#> status.variant status.qualifier
#> 1 AS NEEDED AT LARGE
#> 2 AT LARGE AT LARGE
#> 3 AT-LARGE AT LARGE
#> 4 PROXY AT LARGE
#> 5 AT LG AT LARGE
#> 6 CURRENT CURRENT
#> 7 EX OFFICIO EXOFFICIO
#> 8 EX-OFFICIO EXOFFICIOWord lists (package data)
These character vectors are lazy-loaded package datasets used by the regex cleaning steps. Load any of them with data().
| Dataset | Used in | Purpose |
|---|---|---|
date.words |
remove_dates() (02) |
month/date tokens to detect and strip |
number.words |
gen_status_codes() (06) |
number words removed from titles |
likely.titles |
standardize_conj() (03) |
recognizable titles for split detection |
likely.subjects |
fix_of() (05) |
subjects that follow “of” in a title |
possible.titles |
fix_of() (05) |
candidate title tokens |
former.words |
not used | FORMER variants; superseded by status.codes
|
future.words |
not used | FUTURE variants; superseded by status.codes
|
interim.words |
not used | INTERIM variants; superseded by status.codes
|
regional.words |
not used | REGIONAL variants; superseded by status.codes
|
possible.regional.list |
not used | candidate regional tokens |
data(number.words)
head(number.words, 12)
#> [1] "ONE" "TWO" "THREE" "FOUR" "FIVE" "SIX" "SEVEN" "EIGHT"
#> [9] "NINE" "TEN" "ELEVEN" "TWELVE"
data(likely.titles)
head(likely.titles, 12)
#> [1] "PRESIDENT" "CEO" "DIRECTOR\\b" "CHAIR" "TRUSTEE\\b"
#> [6] "TREASURER" "SECRETARY" "OFFICER" "COUNSEL" "FOUNDER"
#> [11] "PUBLISHER" "EDITOR\\b"Demo data
| Dataset | Description |
|---|---|
tinypartvii |
~81k raw Part VII rows (10,000 orgs) in the modern schema, ready for standardize_df(). |
raw.titles |
A small vector of raw title strings for quick experiments. |
data(tinypartvii)
str(tinypartvii[, 1:8], vec.len = 1)
#> 'data.frame': 81309 obs. of 8 variables:
#> $ EIN2 : chr "EIN-72-1424183" ...
#> $ OBJECTID : chr "OID-202400189349300715" ...
#> $ ORG_EIN : chr "721424183" ...
#> $ ORG_NAME_L1 : chr "MU TAU INC" ...
#> $ ORG_NAME_L2 : chr "" ...
#> $ RETURN_AMENDED_X: chr "FALSE" ...
#> $ RETURN_GROUP_X : chr "FALSE" ...
#> $ RETURN_PARTIAL_X: chr "FALSE" ...