*! version 2.0.2 8may2026

Title

pmean -- Panel-data means and exact within-between decomposition for two- and three-dimensional panel data

Syntax

Two-dimensional panel data:

pmean varlist [if] [in],
id(varname) time(varname)
[genprefix(name) replace listwise table save(filename)]

Three-dimensional panel data:

pmean varlist [if] [in],
id(varname) time(varname) dim3(varname)
[genprefix(name) replace listwise table save(filename) full]

Description

pmean computes panel-data means and the exact within-between decomposition for
two-dimensional (id x time) and three-dimensional (id x time x dim3)
panel data. For each input variable, the command generates marginal means
(overall, by id, by time, and optionally by a third dimension), the implied
within and between components, and two- and three-way fixed-effect residuals.
With dim3() and full, the command additionally generates the full
ANOVA-style pairwise interaction components and the three-way residual.

The additive identities (2D, 3D main effects, and full 3-way ANOVA) hold
exactly at every observation in any panel, balanced or unbalanced. The
third dimension can represent a sector, region, product group, industry,
cohort, or any other grouping observed alongside the panel id and time.

The estimation sample is defined by if, in, and observations with
nonmissing values of id(), time(), and, when supplied, dim3().
Missing values of the analysis variables are handled variable by variable
unless the listwise option is specified.

Installation

To install:

. ssc install pmean

To update an existing installation:

. ssc install pmean, replace

Options

id(varname) specifies the panel identifier. Required.

time(varname) specifies the time identifier. Required.

dim3(varname) specifies the third panel dimension. When this
option is omitted, pmean runs in two-dimensional mode. When dim3()
is constant within each panel id (i.e., the third dimension is nested within
the panel), pmean prints an informational note and proceeds; the
id-by-dim3 interaction component is collinear with the between-dim3 component
in that case but the additive identity still holds.

genprefix(name) specifies the prefix used for generated
variables. The default is pm_. Generated variable names are checked
before any variables are created. If a name exceeds 32 characters, use a
shorter prefix or rename the source variable.

replace allows pmean to overwrite previously generated variables
with the same names. If save() is specified, replace also permits
overwriting an existing CSV file.

listwise restricts the estimation sample to observations that are
jointly non-missing on every variable in varlist. By default, missingness
is handled variable by variable.

table displays a compact summary table for each variable. The table
reports N, mean, standard deviation, minimum, maximum, number of panel units,
number of time periods, and, in three-dimensional mode, number of
third-dimension groups.

save(filename) saves the summary table as a CSV file. This
option requires table. If the file already exists, specify replace.

full adds pairwise means, pairwise interaction components, and the full
three-way residual component. This option is available only with dim3().
pairwise is accepted as a synonym for full.

Generated variables

For a variable x, the default two-dimensional generated variables
are:

pm_overall_x -- Grand mean over the estimation sample

pm_idmean_x -- Unit mean (time-averaged within each id)

pm_timemean_x -- Period mean (averaged across units within each time)

pm_within_id_x -- One-way within deviation: x minus its id mean

pm_between_id_x -- Between-id component: id mean minus grand mean

pm_between_time_x -- Between-time component: period mean minus grand mean

pm_twfe_x -- Two-way demeaned variable (residual after id and time means)

With dim3(), the command additionally generates:

pm_dim3mean_x -- Group mean within each dim3 category

pm_between_dim3_x -- Between-dim3 component: dim3 mean minus grand mean

pm_threefe_x -- Three-way main-effect demeaned variable

With full, the command further generates:

pm_idtime_mean_x -- Cell mean within each (id, time) pair

pm_iddim3_mean_x -- Cell mean within each (id, dim3) pair

pm_timedim3_mean_x -- Cell mean within each (time, dim3) pair

pm_idtime_comp_x -- Id-by-time interaction component

pm_iddim3_comp_x -- Id-by-dim3 interaction component

pm_timedim3_comp_x -- Time-by-dim3 interaction component

pm_threeway_x -- Full three-way ANOVA residual (saturated decomposition)

All generated variables are stored in double precision and are labeled.

Formulas

Let x_it denote a two-dimensional observation for unit i and time
t. The two-way demeaned variable is computed as:

x_it - mean_i(x) - mean_t(x) + mean(x).

Let x_itg denote a three-dimensional observation for unit i, time
t, and third dimension g. The three-way main-effect demeaned
variable is computed as:

x_itg - mean_i(x) - mean_t(x) - mean_g(x) + 2*mean(x).

With full, the full three-way residual component is computed as:

x_itg - mean_it(x) - mean_ig(x) - mean_tg(x) +
mean_i(x) + mean_t(x) + mean_g(x) - mean(x).

The three additive identities (2D, 3D main effects, and full 3-way ANOVA)
hold exactly at every observation in any panel, balanced or unbalanced.
What balance buys is (i) mutual orthogonality of the components, (ii) an
additive decomposition of Var(x) into between- and within-components, and
(iii) numerical equivalence between pm_twfe_x and the OLS residual
from reghdfe x, absorb(id time) (Correia 2016).
In unbalanced panels these three properties fail, although the additive
identity itself remains exact at the observation level. See Wansbeek and
Kapteyn (1989) for a formal treatment of the unbalanced case.

Edge cases

Single observation per unit. If a panel id has only one observation in
the estimation sample, the within-id deviation is identically zero for that
observation.

Single time period. If only one time period is observed in the sample,
the between-time component is identically zero.

Nested third dimension. When dim3() is constant within each panel
id (for example, region nesting state), the id-by-dim3 cell mean equals the
id mean and the id-by-dim3 interaction component is collinear with the
between-dim3 main effect. pmean detects this and prints an
informational note. The additive identity still holds.

Missingness. By default, missingness on the analysis variables is
handled per-variable inside each egen call, so different generated
variables can be defined on slightly different observation sets. Use the
listwise option to require joint non-missingness across all variables
in varlist.

Examples

Two-dimensional use with the Grunfeld investment panel:

. webuse grunfeld, clear

. xtset company year

. pmean invest mvalue, id(company) time(year) replace

Three-dimensional use with the Munnell public-capital panel (note: gsp
is already log-transformed in this dataset):

. webuse productivity, clear

. xtset state year

. pmean gsp, id(state) time(year) dim3(region) replace

Three-dimensional summary table and CSV export:

. pmean gsp, id(state) time(year) dim3(region) table save(pmean_summary.csv) replace

Full pairwise three-dimensional decomposition:

. pmean gsp, id(state) time(year) dim3(region) full genprefix(p2_) replace

Listwise sample across multiple outcomes:

. pmean invest mvalue kstock, id(company) time(year) listwise replace

Stored results:

. return list

. display r(overall_gsp)

Stored results

pmean stores the following in r():

Scalars:

r(N) -- number of observations in the estimation sample

r(dimensions) -- number of panel dimensions (2 or 3)

r(overall_x) -- overall mean of variable x, for each x in varlist

Macros:

r(cmd) -- pmean

r(cmdline) -- command as typed

r(varlist) -- variables decomposed

r(id) -- panel identifier

r(time) -- time variable

r(dim3) -- third-dimension variable, if specified

r(prefix) -- prefix used for generated variables

r(generated) -- list of generated variables

r(mode) -- 2D or 3D

References

Correia, S. 2016. A feasible estimator for linear models with multi-way
fixed effects. Preprint.
http://scorreia.com/research/hdfe.pdf.

Mundlak, Y. 1978. On the pooling of time series and cross section data.
Econometrica 46: 69-85.

Wansbeek, T., and A. Kapteyn. 1989. Estimation of the error-components model
with incomplete panels. Journal of Econometrics 41: 341-361.

Authors

Ahmad Nawaz

School of Economics, Department of Industrial Economics,
Nanjing University, Nanjing 210093, China

Department of Economics, University of Sahiwal, Sahiwal 57000, Pakistan

Email: ahmadnawaz@uosahiwal.edu.pk

Jianghuai Zheng

School of Economics, Department of Industrial Economics,
Nanjing University, Nanjing 210093, China

Email: zhengjh@nju.edu.cn

Repository: github.com/ahmadNJU/stata-pmean

Citation:

Nawaz, A., and J. Zheng. 2026. pmean: Stata module for panel-data means
and exact within-between decomposition. Statistical Software Components
SXXXXXX, Boston College Department of Economics.

Version-pinned DOI: 10.5281/zenodo.20079459

Comparison with related commands

pmean is descriptive: it generates panel-data transformations
(overall mean, unit and time means, within and between components, two-way
and three-way fixed-effect residuals) and stores them as new variables. It
does not perform statistical inference on differences in means.

For inferential pairwise comparisons of group means in cross-sectional
data, see [R] pwmean, which computes all pairwise differences
between group means under an equal-variance assumption and supports
multiple-comparison adjustments such as Tukey's HSD, Bonferroni, and
Dunnett.

For two-way and high-dimensional fixed-effects regression with proper inference, see reghdfe (Correia 2016).

Also see

Help: [XT] xtreg, [XT] xtsum, [XT] xtdescribe, [D] egen, [R] pwmean; reghdfe (if installed)