*! version 1.0.0 2026-07-18

Title

applyvarlabels -- Label the variables in memory from a two-column (Variable, Label) crosswalk in Excel or CSV

Syntax

applyvarlabels using crosswalkfile [, options]

crosswalkfile is a .xlsx/.xls workbook or a .csv/.tsv/.txt
file with one row per variable: a column of variable names and a column of the
labels to apply. The dataset to label must already be in memory.

Crosswalk layout
variable(name) column holding the variable names; default variable(Variable)

label(name) column holding the labels; default label(Label)

sheet(name) worksheet holding the crosswalk (Excel only); default is the first sheet

nocase match crosswalk names to variables ignoring case

Output and control
dofile(filename) write the generated relabel do-file here and keep it; default is a temp-dir file

norun write the relabel do-file but do not apply the labels

smcl(filename) write the inventory to this .smcl file; default is a temp-dir file

replace overwrite an existing dofile() or smcl() file

Description

applyvarlabels solves a recurring Statalist problem
(thread 1768839):
you are handed a dataset of many variables, none of them labeled, together
with a spreadsheet that lists each variable name beside the label it should
carry. The intuitive loop - levelsof the labels, tokenize
the variables, and march down both at once - puts the wrong label on the
wrong variable, because levelsof returns the distinct labels sorted
alphabetically, so pairing them positionally with the variables lines them
up in the wrong order.

applyvarlabels reads the crosswalk in row order and matches every
label to its variable by name, never by position. It then:

1. Writes a capture-guarded relabel do-file: one
capture label variable line per crosswalk row. capture means a
variable named in the crosswalk but absent from the data is skipped, not an
error - so the file is safe to rerun on any dataset that shares the
names.

2. Runs it to apply the labels to the data in memory (unless you
say norun).

3. Prints an inventory of everything that did not line up:
crosswalk rows with no such variable, and variables in memory the crosswalk
never mentions - on screen and to a viewable .smcl file.

The data in memory are never sorted, dropped, or reordered. The crosswalk is
read in its own frame, so nothing changes but the variable
labels themselves.

What you get back

1. Labels on your variables. Exact-name matches are applied in
place; describe shows the result.

2. A reusable relabel do-file. Every match is written as a
capture label variable line, wrapped in a set varabbrev off/restore
pair so an abbreviated name can never resolve to the wrong variable. Name it
with dofile() to keep it beside your cleaning code; its path is in
r(dofile), offered as a click-to-view link.

3. An inventory of what did not match. Two lists - crosswalk
rows with no such variable (r(nomatch)), and variables with no crosswalk
row (r(nolabel)) - plus notes on duplicate rows, empty-label rows,
and labels past Stata's 80-character limit. The full inventory is also written
to r(smcl).

Options

variable(name) and label(name) name the
two crosswalk columns. The defaults, Variable and Label, are
matched case-insensitively, so a header of variable or VARIABLE
also works.

sheet(name) selects the worksheet that holds the
crosswalk, for an Excel workbook whose crosswalk is not on the first sheet
(for example, a workbook whose first sheet is the data and whose second is the
labels). Ignored, with a note, for a delimited file.

nocase matches a crosswalk name to a variable ignoring case, so
AgeYears in the spreadsheet finds ageyears in the data. The
generated do-file uses the variable's actual spelling, so capture
never misfires. Without it, matching is exact.

dofile(filename) writes the relabel do-file to a path
you choose and keeps it; a .do suffix is added if you omit it. Without
this option the file goes to a temporary directory (viewable during the
session, overwritten on the next run). Use replace to overwrite an
existing named file.

norun writes the relabel do-file but does not apply the labels -
a dry run. Inspect or edit the file, then do it yourself. The inventory
still reports what would and would not have matched.

smcl(filename) writes the inventory to a .smcl
file you name (a .smcl suffix is added if omitted); replace
overwrites it. The default writes to a temporary-directory file offered as a
click-to-view link.

replace permits applyvarlabels to overwrite an existing
dofile() or smcl() target.

Examples

The headline case - data in memory, crosswalk on its own sheet:

. import excel using "survey.xlsx", sheet("data") firstrow clear

. applyvarlabels using "survey.xlsx", sheet("var_labels")

Crosswalk columns named something other than Variable/Label:

. applyvarlabels using "labels.xlsx", variable(varname) label(description)

A CSV crosswalk (importer chosen from the extension):

. applyvarlabels using "labels.csv"

Names that differ only in case:

. applyvarlabels using "labels.xlsx", nocase

Keep the relabel do-file as a reusable, auditable artifact:

. applyvarlabels using "labels.xlsx", dofile("relabel_survey.do") replace

Dry run - write the relabel do-file, apply nothing, inspect it first:

. applyvarlabels using "labels.xlsx", norun dofile("relabel_preview.do") replace

. do "relabel_preview.do"

The bundled example_applyvarlabels.do walks the whole workflow on
the shipped example_varlabels.xlsx, including the two crosswalk rows with
no matching variable and the one variable with no crosswalk row.

Stored results

applyvarlabels stores the following in r():

Scalars

r(N_variables) variables in memory

r(N_applied) variables that received a label

r(N_nomatch) crosswalk rows with no matching variable

r(N_nolabel) variables in memory with no crosswalk row

r(N_normalized) labels altered for Stata (straight quotes, backticks)

r(N_long) labels over 80 characters (truncated by Stata)

Macros

r(applied) variables that received a label

r(nomatch) crosswalk names not found in memory

r(nolabel) variables in memory with no crosswalk row

r(dups) variables named more than once in the crosswalk (last label wins)

r(blanks) variables whose crosswalk label cell was empty (skipped)

r(normalized) variables whose label was altered for Stata (curly quotes, apostrophes)

r(dofile) path of the generated relabel do-file

r(smcl) path of the inventory .smcl file

Under norun, r(N_applied) counts the variables that would be
labeled (the do-file is written and left for you to run), and the labels are not
yet on the data.

Remarks

Why a do-file, and why capture. Writing the relabel commands to a
do-file makes the labeling an inspectable, version-controllable, rerunnable
step rather than a one-shot side effect - the same descsave-style logic
behind a codebook you can regenerate. capture guards each line so a
crosswalk that is broader than the data at hand (extra rows, a variable dropped
upstream) applies cleanly to whatever is present and reports the rest.

Matching is exact by default. A crosswalk name must equal a variable
name (Stata is case-sensitive). Variable-name abbreviation is turned off while
matching and inside the generated do-file, so a crosswalk row inc never
silently lands on a variable named income. Use nocase for
case-insensitive matching. Trailing and leading spaces in the crosswalk cells
are trimmed.

Labels are capped at 80 characters. Stata truncates a variable
label longer than 80 characters; applyvarlabels counts such labels in
r(N_long) and cautions you rather than failing.

Special characters. Apostrophes, ampersands, and dollar signs are
preserved exactly - a $name in a label is escaped in the
generated do-file so it is not macro-expanded when that file runs. Two
characters a Stata variable label cannot carry are normalized instead, and the
affected variables are listed in r(normalized) with a note: a
straight double quote ("), which label variable
cannot parse, becomes a typographic (curly) quote; and a backtick
(`), which would open a macro reference when the relabel do-file
runs, becomes an apostrophe.

Nothing else changes. The crosswalk is read in a separate frame;
the data in memory keep their sort order, their observations, and their
variable order. Only variable labels are touched, and only for matched
variables. A variable that already had a label and appears in the crosswalk is
relabeled; one that is not in the crosswalk is left exactly as it was and
listed in r(nolabel).

Author

Eric A. Booth

Sr Researcher, Texas 2036

eric.a.booth@gmail.com

MIT License. Report issues at the GitHub repository.

Also see

Help: label, label language, import excel, frames

Related: labelbook, ds, describe