Skip to main content
v2026.11,772 entries · CC-BY 4.0

Creating Dummy Variables in Stata: i. Factor Notation vs. tabulate, generate()

Two ways to create dummy/indicator variables in Stata — the i. factor-variable operator vs. tabulate, generate() — and when each one is the right tool.

Written and maintained by CASRAI Editorial Board

Last updated

Stata gives you two genuinely different ways to turn a categorical variable into 0/1 indicators, and they are not interchangeable: the i. factor-variable operator builds indicators on the fly, inside a single command, without ever writing a new variable to your dataset, while tabulate varname, generate(stub) physically creates one stored dummy variable per category. Most modern Stata workflows should default to i. notation — it is what margins, lincom, and every postestimation command expect — but there are real, specific situations where you need the stored variables tabulate‘s generate() option produces instead. This guide covers the mechanics of both, how each handles the reference/base category, the collinearity trap that catches people using generate(), and when to reach for which.

The i. Factor-Variable Operator

Prefixing a categorical variable with i. inside an estimation command tells Stata to treat it as a set of indicators rather than a single continuous predictor:

regress wage i.region

If region takes values 1 through 4, this is equivalent in effect to including three dummy variables (2.region, 3.region, 4.region) and omitting one as the reference — except no such variables are ever created or stored. Stata builds them internally for the duration of the command and discards them afterward. This is the operator’s central advantage: it “saves lots of space,” in Stata’s own phrasing, and it integrates with every command that understands factor-variable syntax — not just estimation commands, but margins, lincom, test, and predict afterward, all of which read the same 1.region/2.region-style labeling automatically.

i. also composes directly with interaction operators, which is the syntax’s other major reason to prefer it over hand-built dummies:

regress cholesterol i.smoker##i.agegrp bmi i.smoker#c.bmi

# requests the interaction term alone; ## requests the full factorial (both main effects and the interaction); c. marks a variable as continuous when it appears in an interaction, so i.smoker#c.bmi produces a single smoker × bmi product term rather than treating bmi as categorical. Building this by hand with stored dummy variables means generating every interaction product column yourself and keeping the naming consistent — error-prone at exactly the point where a typo is hardest to notice.

Choosing the Base (Reference) Category with i.

By default, i. uses the lowest observed value of the variable as the omitted base category. That default is frequently not the category you want as the reference — a control group coded 0, a “none” category, or whichever level makes the coefficients easiest to interpret. Override it with the b operator combined into the factor-variable prefix:

regress outcome ib3.agegrp

ib3.agegrp sets category 3 as the base instead of whatever the lowest coded value happens to be. ib(freq).varname is also available, and picks the most frequent category as the base automatically — useful when the substantively natural reference group also happens to be the modal one and you don’t want to hardcode its numeric code into the command.

tabulate, generate(): Physically Stored Dummy Variables

The other approach creates real variables you can see with describe and reuse in later commands, including ones that don’t understand factor-variable syntax:

tabulate region, generate(reg)

This creates one new variable per distinct value of regionreg1, reg2, reg3, reg4 — numbered by the sorted order of the underlying values, each coded 1 where the observation belongs to that category and 0 otherwise. Unlike i., tabulate‘s generate() option does not pick a base category for you and does not omit one from the set it creates — it generates a complete, non-redundant-looking set that is in fact perfectly collinear if you include all of them in the same regression alongside a constant term. That is the single most common mistake this command produces: entering reg1 reg2 reg3 reg4 together in a regress command that also has its default intercept triggers Stata’s “collinear” note and one variable is silently dropped — not necessarily the one you would have chosen as the reference. The fix is the same dummy-variable-trap fix as in any statistical package: deliberately drop one generated dummy from the model yourself, choosing which one, rather than letting regress drop one for you.

Missing values in the source variable do not get their own generated dummy by default — observations with a missing region come through as 0 on every reg# variable, which silently misrepresents them as belonging to no category rather than flagging them as unknown. Check misstable summarize region before generating dummies from a variable with any missingness, and consider recoding missing to an explicit category first if that observation-level distinction matters to the analysis (see Recoding Variables in Stata for the recode mechanics).

When tabulate, generate() Is Actually the Right Tool

Given that i. is more capable inside Stata’s own estimation framework, generate() earns its place in a narrower set of real situations:

  • Exporting or merging. A stored dummy variable survives export delimited, merge, and round-trips to R, Python, or Excel intact. A factor-variable expression like i.region exists only inside the command that used it — there is nothing to export.
  • Commands that don’t parse factor-variable syntax. Some user-written and older built-in commands accept only literal variable names, not i. expressions. When one of these is genuinely the right tool for the analysis, stored dummies are the only way to feed it categorical predictors.
  • Graphing by category. Several graphing workflows condition on or overlay by a stored 0/1 variable more directly than they do a factor-variable expression evaluated inline.
  • Manually building a specific reduced set of comparisons — e.g., you only want three of six categories represented as separate predictors and the rest pooled into a reference group, which is easier to construct explicitly with generate() plus some recoding than to express through ib#. alone.

Outside of these, prefer i.. It is less code, it cannot silently produce the dummy-variable trap the way an unfiltered set of generate() outputs can, and every postestimation command after regress, logit, or xtreg is written to expect it.

A Third Option, Mostly Historical: xi:

Older Stata code and older tutorials sometimes prefix a whole command with xi: and mark categorical variables with i. inside it — xi: regress y i.region — which physically expands the indicators into new stored variables named _Iregion_2, _Iregion_3, and so on, then runs the command. This was necessary before factor-variable notation existed as a native feature; since Stata 11 introduced the modern i./c./#/## system, xi: is no longer needed for anything the native operators can already do, and mixing the two styles in the same do-file is a common source of confusion when reading someone else’s older code. If you inherit a do-file that still uses xi:, it is safe to rewrite it with native factor-variable syntax rather than preserve the legacy prefix.

i. vs. tabulate, generate() at a Glance

  • Where it lives: i. exists only inside the command using it; generate() writes permanent variables into the dataset.
  • Reference category: i. picks one automatically (override with ib#. or ib(freq).); generate() creates a dummy for every category and leaves it to you to drop one.
  • Interactions: i. composes with #/##/c. directly; interactions between generate() dummies must be built as separate product variables.
  • Postestimation: margins, lincom, and test read i. labeling natively; they can still work with generate() dummies, but you lose the automatic category labeling in the output.
  • Portability: generate() variables export and merge like any other variable; i. expressions do not exist outside the command that used them.

Frequently Asked Questions

What does the i. prefix actually do in Stata?

It tells Stata to treat the variable that follows as categorical rather than continuous within that command, expanding it into one indicator per category (minus a reference category) for the duration of that command only — nothing is written back to the dataset.

How do I change which category i. treats as the reference?

Combine the base operator with the indicator prefix: ib3.varname sets category 3 as the base, and ib(freq).varname sets whichever category has the most observations as the base.

Can I just run tabulate, generate() and drop into a regression?

You can, but include only k-1 of the generated dummies alongside the regression’s constant term, or Stata will flag (and silently resolve) a collinearity error by dropping one for you — deliberately choose which one to drop instead.

Why does my model report a variable as collinear after I created dummies?

This is almost always the dummy-variable trap: including every category’s dummy plus an intercept term is mathematically redundant, because the dummies already sum to 1 for every observation. Drop one category’s dummy (or omit the constant, which is rarely the better fix) to resolve it.

Does margins work with tabulate-generated dummy variables?

margins will run against a model built from stored dummies, but it treats each one as an ordinary continuous 0/1 variable rather than as a labeled factor level, so the output won’t group or label results by the original category the way it does automatically for a model built with i..

Related Stata Guides

Once your categorical predictors are coded, see Regression in Stata and Logistic Regression in Stata for how i.-coded predictors carry through to estimation and postestimation output, and Chi-Square Test in Stata for more on what tabulate does beyond the generate() option covered here. If the categorical variable you’re dummy-coding also needs relabeling first, Recoding Variables in Stata and Labeling Variables and Values in Stata cover recode and value labels respectively. If the variable has missing values you’re filling in before modeling rather than coding around, Multiple Imputation in Stata: mi impute and mi estimate covers how Stata’s mi suite imputes categorical predictors directly (via mi impute chained‘s logit/ologit/mlogit sub-models) without requiring you to pre-build dummy variables at all. For keeping either approach reproducible across a project, see Stata Do-Files: Structure for a Reproducible Workflow.

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · included with Regulatory Radar

Ask about Creating Dummy Variables in Stata: i. Factor Notation vs. tabulate, generate()

Ask CASRAI answers research-administration questions and cites the passages behind every claim — and says so when the corpus does not cover something, instead of guessing. It comes with a Regulatory Radar subscription at $29 a month, alongside the daily digest of regulatory changes and the dashboard of what changed.

150 questions a day, on this site, over the API, or inside your own tools through the CASRAI MCP server.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Regulatory Radar

Stop finding out after the fact

$29/month, cancel anytime. Daily digest updates from our analysis, a dashboard holding the same items, and a cited assistant for everything they raise.

  • Federal Register, Federal Register+, Grants.gov, Regulations.gov, NSF News, UKRI, plus CASRAI’s own published content.
  • 72,264 indexed passages, and every answer cites the ones it drew on.