plm Skill

SkillAI & models

R panel data models with plm: within (FE), random (RE), between, first difference, Fama-MacBeth. Hausman test, panel unit root tests. Includes estimatr for robust estimation and lme4 for mixed effects. Use when execution language is R. Python equivalent: linearmodels. For high- dimensional FE use fixest; for cross-sectional OLS/GLM use r-stats.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the plm Skill skill

What this skill tells your AI

The instructions your AI receives, as published by daaf-contribution-community/daaf in .claude/skills/plm/SKILL.md and read by ahel’s review.

R's canonical panel data modeling package. Covers within (FE), random effects (RE), between, first difference, and pooled OLS estimators via plm(), plus Fama-MacBeth via pmg() (requires a reversed, time-first index — see models.md). Provides the Hausman test (phtest()) for FE vs RE selection, LM tests for unobserved effects (plmtest()), panel serial correlation tests (pbgtest(), pwartest(), pbsytest()), cross-sectional dependence tests (pcdtest()), and panel unit root tests (purtest(), cipstest()). Includes estimatr for robust/cluster-robust estimation (lm_robust(), iv_robust()) and lme4 for mixed-effects models (lmer(), glmer()). Use when execution language is R and the analysis involves panel data requiring RE, between, first-difference, or Hausman testing. Python equivalent: linearmodels. For high-dimensional fixed effects, IV with FE, or DiD, use fixest. For cross-sectional OLS/GLM without panel structure, use r-stats.

What is plm?

plm (Croissant & Millo, 2008) is the standard R package for linear panel data models. It provides a unified formula interface that mirrors base R's lm() but adds panel-aware estimation:

  • Panel-aware data: pdata.frame() declares entity and time identifiers
  • Five estimators: within (FE), random (RE), between, first difference (fd), pooling -- selected via the model= argument to plm()
  • Fama-MacBeth: pmg(model = "mg") with a reversed (time-first) indexindex = c("time", "entity") — so the per-group regressions are cross-sectional per period, not per-entity time series (see models.md)
  • Hausman test: phtest() for FE vs RE model selection
  • Dynamic panels: pgmm() for Arellano-Bond and Blundell-Bond GMM
  • Panel IV: plm() with instruments argument for 2SLS within panels
  • Rich diagnostics: serial correlation, cross-sectional dependence, unit root tests, all panel-specific

This skill also covers two companion packages:

PackageVersionRole
estimatr1.0.6lm_robust() and iv_robust() with HC/CR standard errors
lme42.0-1lmer() for random intercepts/slopes (mixed-effects models)

Version Notes

This skill targets plm 2.6-7 (R 4.5.3). Key features:

  • pdata.frame() for explicit panel structure declaration
  • plm() formula interface: y ~ x1 + x2 | instruments
  • Default vcov is classical (homoskedastic) -- always specify robust/clustered vcov explicitly
  • pgmm() supports both Arellano-Bond ("ab") and Blundell-Bond ("bb") transformations

How to Use This Skill

Reference File Structure

FilePurposeWhen to Read
quickstart.mdpdata.frame, plm() basics, model= argument, summary, coeftestStarting with plm or panel data in R
models.mdwithin, random, between, fd, Fama-MacBeth, comparisonChoosing or switching between panel estimators
diagnostics.mdphtest() Hausman, plmtest(), pcdtest(), panel unit rootTesting assumptions, model selection
iv.mdPanel IV via plm() instruments, Sargan/Hansen, pgmm()IV estimation within panel structure
robust.mdestimatr lm_robust/iv_robust, HC/CR SEs, plm vcov optionsRobust or clustered standard errors
mixed-effects.mdlme4 lmer/glmer, random intercepts/slopes, ICCMixed-effects / multilevel models
gotchas.mdpdata.frame requirements, FE vs RE, fixest vs plm routingDebugging or package selection

Reading Order

  1. New to plm? Start with quickstart.md then models.md
  2. FE vs RE decision? Read quickstart.md then diagnostics.md
  3. Need robust SEs? Read robust.md
  4. Panel IV or GMM? Read iv.md
  5. Mixed-effects models? Read mixed-effects.md
  6. Coming from linearmodels (Python)? Read quickstart.md then gotchas.md

The reference-file routing in this skill applies to advisory and brainstorming turns as much as implementation. Recommending an estimator, reviewing a panel analysis plan, or answering a question that touches a routed topic calls for reading the routed reference file just as much as writing code does — the reference files carry curated caveats and environment-specific constraints (e.g., the Fama-MacBeth index reversal) that this overview and general knowledge lack.

Related Skills

SkillRelationship
linearmodelsPython equivalent for panel data. plm covers the same estimators (FE, RE, between, FD, Fama-MacBeth) with R-native formula syntax. Key API difference: plm uses pdata.frame() for panel declaration; linearmodels uses pandas MultiIndex
fixestPreferred for high-dimensional FE, FE + IV, DiD, fast FE demeaning, publication tables. Use plm when fixest cannot do what you need (RE, between, Hausman test, Fama-MacBeth, panel diagnostics, dynamic GMM)
r-statsBase R regression without panel structure. Use r-stats for cross-sectional OLS, GLM, classical tests. plm extends the lm() formula interface for panel data
data-scientistMethodology guidance -- load for "why and when" behind model choices
tidyverseData preparation before estimation; plm accepts data.frames directly from dplyr pipelines
gtPublication-quality tables -- plm model output feeds into modelsummary/gt for formatted regression tables

Quick Decision Trees

"I need a panel model in R"

What panel estimation method?
+-- Fixed effects (within estimator)
|   +-- 1-2 way FE, no IV --> plm (model = "within") or fixest feols
|   +-- 3+ way FE --> fixest (plm max 2-way via twoways)
|   +-- FE + IV combined --> plm with instruments or fixest 3-part formula
|   +-- FE + DiD --> fixest (plm has no DiD)
+-- Random effects (GLS) --> plm (model = "random")
|   --> ./references/models.md
+-- FE vs RE comparison --> plm phtest() (Hausman test)
|   --> ./references/diagnostics.md
+-- Between estimator --> plm (model = "between")
|   --> ./references/models.md
+-- First difference --> plm (model = "fd")
|   --> ./references/models.md
+-- Pooled OLS (panel-aware) --> plm (model = "pooling")
|   --> ./references/models.md
+-- Fama-MacBeth --> pmg(model = "mg") with REVERSED index c("time","entity")
|   --> ./references/models.md
+-- Dynamic panel (Arellano-Bond/Blundell-Bond) --> plm pgmm()
|   --> ./references/iv.md

"I need robust standard errors"

What inference?
+-- Heteroskedasticity-robust (HC) --> ./references/robust.md
|   +-- For plm models: vcovHC() from plm
|   +-- For lm models: estimatr::lm_robust()
+-- Clustered SEs --> ./references/robust.md
|   +-- For plm models: vcovHC(type = "HC1", cluster = "group")
|   +-- For lm models: estimatr::lm_robust(clusters = group)
+-- Newey-West (panel HAC) --> ./references/robust.md
|   +-- vcovNW() from plm
+-- Driscoll-Kraay --> ./references/robust.md
|   +-- vcovSCC() from plm
+-- Bootstrap --> sandwich::vcovBS

"I need panel diagnostics"

What diagnostic?
+-- FE vs RE decision --> ./references/diagnostics.md
|   +-- Hausman test: phtest()
+-- Serial correlation --> ./references/diagnostics.md
|   +-- Breusch-Godfrey: pbgtest()
|   +-- Wooldridge AR(1) FE test: pwartest() / first-difference: pwfdtest()
+-- Unobserved individual/time effects (LM) --> ./references/diagnostics.md
|   +-- plmtest() (Breusch-Pagan, Honda, GHM -- NOT a serial correlation test)
+-- Cross-sectional dependence --> ./references/diagnostics.md
|   +-- Pesaran CD: pcdtest()
+-- Unit root (stationarity) --> ./references/diagnostics.md
|   +-- purtest() (Levin-Lin-Chu, Im-Pesaran-Shin, etc.)
|   +-- cipstest() (Pesaran CIPS)
+-- Poolability (F-test for FE) --> ./references/diagnostics.md
|   +-- pooltest()

"Something isn't working"

Having issues?
+-- Error about pdata.frame or index --> ./references/gotchas.md
+-- Hausman test gives warnings --> ./references/gotchas.md
+-- Results differ from fixest --> ./references/gotchas.md
+-- Unbalanced panel handling --> ./references/gotchas.md
+-- Want to compare with linearmodels (Python) --> ./references/gotchas.md
+-- plm vs fixest: which to use? --> ./references/gotchas.md

File-First Execution in Research Workflows

Important: In DAAF research pipelines, plm regressions are executed through script files, not interactively. This ensures auditability and reproducibility.

The pattern:

  1. Write regression code to scripts/stage8_analysis/{step}_{task-name}.R
  2. Execute via Bash with automatic output capture wrapper script
  3. Validation results get automatically embedded in scripts as comments
  4. If failed, create versioned copy for fixes

Closely read agent_reference/SCRIPT_EXECUTION_REFERENCE.md for the mandatory file-first execution protocol covering complete code file writing, output capture, and file versioning rules. All regression scripts must follow the Inline Audit Trail (IAT) standard -- see agent_reference/INLINE_AUDIT_TRAIL.md. For regression code, document model specification choices (why this estimator, why this clustering level, what identifying assumptions) with # INTENT:, # REASONING:, and # ASSUMES: comments.

See:

  • agent_reference/WORKFLOW_PHASE4_ANALYSIS.md -- Stage 8 (Analysis & Visualization)
  • agent_reference/INLINE_AUDIT_TRAIL.md -- IAT documentation standard

The examples below show plm syntax. In research workflows, wrap them in scripts following the file-first pattern.


Quick Reference

Essential Setup

library(plm)
library(estimatr)    # lm_robust, iv_robust
library(lme4)        # lmer, glmer
library(lmtest)      # coeftest with custom vcov
library(arrow)       # For parquet I/O (DAAF convention)

Data Setup (pdata.frame)

# Declare panel structure -- entity and time identifiers
pdf <- pdata.frame(df, index = c("entity_id", "year"))

# Verify
pdim(pdf)            # Panel dimensions
is.pbalanced(pdf)    # Check balance

Core Operations

OperationCode
Panel FE (within)plm(y ~ x1 + x2, data = pdf, model = "within")
Two-way FEplm(y ~ x1 + x2, data = pdf, model = "within", effect = "twoways")
Random effectsplm(y ~ x1 + x2, data = pdf, model = "random")
Betweenplm(y ~ x1 + x2, data = pdf, model = "between")
First differenceplm(y ~ x1 + x2, data = pdf, model = "fd")
Pooled OLSplm(y ~ x1 + x2, data = pdf, model = "pooling")
Panel IVplm(y ~ x1 + x2 | z1 + z2, data = pdf, model = "within")
Hausman testphtest(fe_fit, re_fit)
Robust SEscoeftest(fit, vcov = vcovHC(fit, type = "HC1"))
Clustered SEscoeftest(fit, vcov = vcovHC(fit, cluster = "group"))
Driscoll-Kraaycoeftest(fit, vcov = vcovSCC(fit))
Summarysummary(fit)
Dynamic GMMpgmm(y ~ lag(y, 1) + x1 | lag(y, 2:99), data = pdf)

Formula Syntax

# Standard panel formula
y ~ x1 + x2

# Panel IV: instruments after |
y ~ x1 + x_endog | z1 + z2 + x1

# Interactions
y ~ x1 * x2          # x1 + x2 + x1:x2

# Transformations
y ~ log(x1) + I(x2^2)

# Suppress intercept (for within estimator, intercept is absorbed anyway)
y ~ x1 + x2 - 1

Post-Estimation

fit <- plm(y ~ x1 + x2, data = pdf, model = "within")

summary(fit)                          # Full summary
coef(fit)                             # Coefficients
vcov(fit)                             # Variance-covariance matrix
fixef(fit)                            # Fixed effects estimates
pFtest(fit, plm(y ~ x1 + x2, data = pdf, model = "pooling"))  # F-test for FE
within_intercept(fit)                 # Overall intercept for within model
broom::tidy(fit, conf.int = TRUE)     # Tidy output
broom::glance(fit)                    # Model-level statistics

Topic Index

TopicReference File
pdata.frame setup./references/quickstart.md
plm() basics./references/quickstart.md
model= argument./references/quickstart.md
summary() output./references/quickstart.md
pdim(), is.pbalanced()./references/quickstart.md
Comparison to linearmodels (Python)./references/quickstart.md
Within (FE) estimator./references/models.md
Random effects (RE)./references/models.md
Between estimator./references/models.md
First difference (FD)./references/models.md
Pooled OLS./references/models.md
Fama-MacBeth (pmg)./references/models.md
Two-way effects./references/models.md
Model comparison./references/models.md
Weighted estimation./references/models.md
Hausman test (phtest)./references/diagnostics.md
Poolability F-test./references/diagnostics.md
Serial correlation tests./references/diagnostics.md
Cross-sectional dependence./references/diagnostics.md
Panel unit root tests./references/diagnostics.md
Panel IV (plm instruments)./references/iv.md
Sargan/Hansen test./references/iv.md
Dynamic GMM (pgmm)./references/iv.md
Arellano-Bond test./references/iv.md
vcovHC (heteroskedasticity-robust)./references/robust.md
Clustered SEs./references/robust.md
Newey-West (vcovNW)./references/robust.md
Driscoll-Kraay (vcovSCC)./references/robust.md
estimatr lm_robust./references/robust.md
estimatr iv_robust./references/robust.md
lme4 lmer./references/mixed-effects.md
lme4 glmer./references/mixed-effects.md
Random intercepts/slopes./references/mixed-effects.md
ICC (intraclass correlation)./references/mixed-effects.md
Conditional vs marginal effects./references/mixed-effects.md
pdata.frame requirements./references/gotchas.md
Unbalanced panels./references/gotchas.md
FE vs RE choice./references/gotchas.md
fixest vs plm routing./references/gotchas.md
linearmodels vs plm comparison./references/gotchas.md

Citation

When plm is used as a primary analytical tool, include in the report's Software & Tools references:

Croissant, Y. & Millo, G. (2008). "Panel Data Econometrics in R: The plm Package." Journal of Statistical Software, 27(2), 1-43.

For estimatr:

Blair, G., Cooper, J., Coppock, A., Humphreys, M., & Sonnet, L. (2022). estimatr: Fast Estimators for Design-Based Inference. R package. https://CRAN.R-project.org/package=estimatr

For lme4:

Bates, D., Machler, M., Bolker, B., & Walker, S. (2015). "Fitting Linear Mixed-Effects Models Using lme4." Journal of Statistical Software, 67(1), 1-48.

Cite when: plm is used for panel estimation (FE, RE, between, FD), Hausman testing, or panel diagnostics. Cite estimatr when HC/CR SEs are the primary inference approach. Cite lme4 when mixed-effects models are estimated. Do not cite when: Only loaded but no estimation performed.

For method-specific citations (e.g., individual estimators or techniques), consult the reference files in this skill and agent_reference/CITATION_REFERENCE.md.

Signals

GitHub stars
235
Forks
34
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
plm
Source
github.com/daaf-contribution-community/daaf