Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
Package: csdm
Title: Cross Section Dependence Models
Title: Cross-Sectional Dependence Models
Version: 1.0.0
Depends: R (>= 3.5.0)
Depends: R (>= 4.0.0)
Imports: MASS
Suggests:
testthat (>= 3.0.0),
knitr,
rmarkdown,
kableExtra,
xtsum
Author: Joao Claudio Macosso
Maintainer: Joao Claudio Macosso <joaoclaudiomacosso@gmail.com>
Description: Estimators and utilities for panel-data models with cross-sectional dependence.
Authors@R:
person(given = c("Joao", "Claudio"),
family = "Macosso",
email = "joaoclaudiomacosso@gmail.com",
role = c("aut", "cre"))
Description: Provides estimators and utilities for large panel-data models with cross-sectional dependence, including mean group (MG), common correlated effects (CCE) and dynamic CCE (DCCE) estimators, and cross-sectionally augmented ARDL (CS-ARDL) specifications, plus related inference and diagnostics.
License: GPL-3
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
Config/testthat/edition: 3
VignetteBuilder: knitr
135 changes: 108 additions & 27 deletions R/csdm.R
Original file line number Diff line number Diff line change
@@ -1,49 +1,130 @@
# csdm.R

#' Unified front door for csdm estimators
#' Panel Model Estimation with Cross Section Dependence
#'
#' @param formula A model formula like `y ~ x1 + x2`.
#' @param data A `data.frame` (or `plm::pdata.frame`) containing the variables in `formula`.
#' @param id,time Column names (strings) for the unit and time indexes.
#' If `data` is a `pdata.frame`, these are taken from its index and the provided values are ignored.
#' @param model Which estimator to fit. Currently implemented: `"mg"`, `"cce"`, `"dcce"`.
#' Estimate panel data models that allow for cross-sectional dependence and
#' heterogeneous slopes. The interface supports Mean Group (MG), Common
#' Correlated Effects (CCE), Dynamic CCE (DCCE), and Cross-Sectionally
#' Augmented ARDL (CS-ARDL) estimators with consistent handling of
#' cross-sectional averages, dynamic structure, and robust inference.
#'
#' @param formula Model formula of the form \code{y ~ x1 + x2}.
#' @param data A \code{data.frame} (or \code{plm::pdata.frame}) containing the
#' variables in \code{formula}.
#' @param id,time Column names (strings) for the unit and time indexes. If
#' \code{data} is a \code{pdata.frame}, these are taken from its index and the
#' provided values are ignored.
#' @param model Estimator to fit. One of \code{"mg"}, \code{"cce"},
#' \code{"dcce"}, or \code{"cs_ardl"}.
Comment on lines +17 to +18
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The model parameter docs list only "mg", "cce", "dcce", and "cs_ardl", but the function signature allows additional values (cs_ecm, cs_dl) that currently error with "Not implemented yet". Please either document these as reserved/unimplemented options or remove them from match.arg() choices until they’re supported to avoid surprising API behavior.

Copilot uses AI. Check for mistakes.
#' @param csa Cross-sectional-average specification, created by [csdm_csa()].
#' @param lr Long-run specification (currently a stub), created by [csdm_lr()].
#' @param pooled Pooled specification (currently a stub), created by [csdm_pooled()].
#' @param trend One of `"none"` or `"unit"` (a linear trend per unit is added as a regressor).
#' `"pooled"` is reserved and not implemented.
#' @param lr Long-run or dynamic specification, created by [csdm_lr()].
#' @param pooled Pooled specification (reserved for future use), created by
#' [csdm_pooled()].
#' @param trend One of \code{"none"} or \code{"unit"} (adds a linear unit trend).
#' \code{"pooled"} is reserved and not implemented.
#' @param fullsample Logical; reserved for future extensions.
#' @param mgmissing Logical; reserved for future extensions.
#' @param vcov Variance-covariance specification, created by [csdm_vcov()].
#' @param ... Reserved for future extensions.
#'
#' @return An object of class `csdm_fit`.
#' @export
#' @return An object of class \code{csdm_fit} containing estimated coefficients,
#' residuals, variance-covariance estimates, model metadata, and diagnostics.
#' Use \code{summary()}, \code{coef()}, \code{residuals()}, \code{vcov()}, and
#' \code{cd_test()} to access standard outputs.
#'
#' @details
#' ## Model equations
#'
#' \describe{
#' \item{MG (Pesaran and Smith, 1995)}{
#' \deqn{y_{it} = x_{it}^\top \beta_i + u_{it}}
#' }
#' \item{CCE (Pesaran, 2006)}{
#' \deqn{y_{it} = x_{it}^\top \beta_i + \lambda_i^\top F_t + u_{it}}
#' }
#' \item{DCCE (Chudik and Pesaran, 2015)}{
#' \deqn{\Delta y_{it} = \Delta x_{it}^\top \beta_i + \lambda_i^\top \Delta F_t + u_{it}}
#' }
#' \item{CS-ARDL (Chudik and Pesaran, 2015)}{
#' \deqn{y_{it} = \phi_i y_{it-1} + x_{it}^\top \theta_i + \lambda_i^\top F_t + u_{it}}
#' }
#' }
#'
#' ## Estimation, identification, and assumptions
#'
#' \describe{
#' \item{MG}{Unit-by-unit estimation with heterogeneous slopes. The reported
#' coefficients are cross-sectional averages of unit estimates. Requires
#' sufficient time series per unit and weak serial dependence in errors.}
#' \item{CCE}{Augments regressions with cross-sectional averages (CSA) to proxy
#' unobserved common factors. Identification relies on large N and T, weak
#' dependence in idiosyncratic errors after CSA, and weak exogeneity of
#' regressors.}
#' \item{DCCE}{Extends CCE to dynamic settings with lagged dependent variables
#' and CSA lags. Identification relies on weak exogeneity, adequate time length
#' for dynamic lags, and a stable factor structure.}
#' \item{CS-ARDL}{Specifies dynamic distributed lags with CSA terms. Estimation
#' follows ARDL-style dynamics in each unit and aggregates to panel averages.
#' Assumes weak exogeneity and sufficient time length for lag structure.}
#' }
#'
#' @references
#' Pesaran, M.H. and Smith, R. (1995). "Estimating long-run relationships from
#' dynamic heterogeneous panels." Journal of Econometrics, 68(1), 79-113.
#'
#' Pesaran, M.H. (2006). "Estimation and inference in large heterogeneous panels
#' with multifactor error structure." Econometrica, 74(4), 967-1012.
#'
#' Chudik, A. and Pesaran, M.H. (2015). "Common correlated effects estimation of
#' heterogeneous dynamic panel data models with weakly exogenous regressors."
#' Journal of Econometrics, 188(2), 393-420.
#'
#' Chudik, A. and Pesaran, M.H. (2015). "Large panel data models with
#' cross-sectional dependence: A survey." Annals of Economics and Finance, 16(1),
#' 53-78.
#'
#' @examples
#' library(csdm)
#' data(PWT_60_07, package = "csdm")
#' df <- PWT_60_07
#'
#' # Keep examples fast: use a small subset
#' # Keep examples fast but fully runnable
#' keep_ids <- unique(df$id)[1:10]
#' # Use enough time periods so DCCE + CSA lags is estimable
#' df_small <- df[df$id %in% keep_ids & df$year >= 1970, ]
#'
#' # xtdcce2-style DCCE specification
#' fit <- csdm(
#' # Mean Group (MG)
#' mg <- csdm(
#' log_rgdpo ~ log_hc + log_ck + log_ngd,
#' data = df_small, id = "id", time = "year", model = "mg"
#' )
#' summary(mg)
#'
#' # Common Correlated Effects (CCE)
#' cce <- csdm(
#' log_rgdpo ~ log_hc + log_ck + log_ngd,
#' data = df_small, id = "id", time = "year", model = "cce",
#' csa = csdm_csa(vars = c("log_rgdpo", "log_hc", "log_ck", "log_ngd"))
#' )
#' summary(cce)
#'
#' # Dynamic CCE (DCCE)
#' dcce <- csdm(
#' log_rgdpo ~ log_hc + log_ck + log_ngd,
#' data = df_small,
#' id = "id",
#' time = "year",
#' model = "dcce",
#' csa = csdm_csa(
#' vars = c("log_rgdpo", "log_hc", "log_ck", "log_ngd"),
#' lags = 3
#' ),
#' lr = csdm_lr(type = "ardl", ylags = 1)
#' data = df_small, id = "id", time = "year", model = "dcce",
#' csa = csdm_csa(vars = c("log_rgdpo", "log_hc", "log_ck", "log_ngd"), lags = 3),
#' lr = csdm_lr(type = "ardl", ylags = 1, xdlags = 0)
#' )
#' summary(dcce)
#'
#' summary(fit)
#' cd_test(fit)
#' # CS-ARDL
#' cs_ardl <- csdm(
#' log_rgdpo ~ log_hc + log_ck + log_ngd,
#' data = df_small, id = "id", time = "year", model = "cs_ardl",
#' csa = csdm_csa(vars = c("log_rgdpo", "log_hc", "log_ck", "log_ngd"), lags = 3),
#' lr = csdm_lr(type = "ardl", ylags = 1, xdlags = 0)
#' )
#' summary(cs_ardl)
#' @export
csdm <- function(
formula, data, id, time,
model = c("mg", "cce", "dcce", "cs_ardl", "cs_ecm", "cs_dl"),
Expand Down
115 changes: 106 additions & 9 deletions R/csdm_methods.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# csdm_methods.R

#' Compact print method for fitted csdm models
#'
#' Prints a concise overview of a fitted \code{csdm_fit} object, including the
#' model type, formula, panel dimensions, and a coefficient table with standard
#' errors when available.
#'
#' @param x A fitted object of class \code{csdm_fit}.
#' @param digits Number of printed digits.
#' @param ... Currently unused.
#'
#' @return Invisibly returns \code{x}.
#' @seealso [summary.csdm_fit()], [coef.csdm_fit()], [residuals.csdm_fit()]
#' @export
print.csdm_fit <- function(x, digits = 4, ...) {
cat("csdm fit (", x$model, ")\n", sep = "")
Expand All @@ -22,17 +34,49 @@ print.csdm_fit <- function(x, digits = 4, ...) {
invisible(x)
}

#' Summarize csdm_fit model results
#' Summarize csdm model estimation results
#'
#' @param object A csdm_fit model object.
#' Computes post-estimation summaries for \code{csdm_fit} objects, including
#' mean-group coefficient inference, model-level diagnostics, and model-specific
#' summary tables (for example, short-run and long-run blocks for CS-ARDL).
#'
#' @param object A fitted model object of class \code{csdm_fit}.
#' @param digits Number of digits to print.
#' @param ... Further arguments passed to methods.
#'
#' @details
#' The summary displays classic Pesaran CD test statistics. For additional CD diagnostics
#' (CDw, CDw+, CD*), use `cd_test()` on the fitted model object.
#' ## Reported inference
#'
#' For each coefficient \eqn{\hat\beta_k}, the summary reports standard errors,
#' \eqn{z}-statistics, and two-sided normal-approximation p-values:
#' \deqn{z_k = \frac{\hat\beta_k}{\operatorname{se}(\hat\beta_k)}, \qquad
#' p_k = 2\{1-\Phi(|z_k|)\}.}
#'
#' ## Diagnostics
#'
#' @return An object of class 'summary.csdm_fit'.
#' The printed summary shows the classic Pesaran CD diagnostic by default. Extended
#' diagnostics (CDw, CDw+, CD*) are available through [cd_test()].
#'
#' @return An object of class \code{summary.csdm_fit} with core metadata
#' (call/formula/model/N/T), coefficient tables, fit statistics, and
#' model-specific components for printing and downstream inspection.
#' @seealso [print.summary.csdm_fit()], [cd_test()], [coef.csdm_fit()], [vcov.csdm_fit()]
#'
#' @examples
#' data(PWT_60_07, package = "csdm")
#' df <- PWT_60_07
#' ids <- unique(df$id)[1:10]
#' df_small <- df[df$id %in% ids & df$year >= 1970, ]
#' fit <- csdm(
#' log_rgdpo ~ log_hc + log_ck + log_ngd,
#' data = df_small,
#' id = "id",
#' time = "year",
#' model = "cce",
#' csa = csdm_csa(vars = c("log_rgdpo", "log_hc", "log_ck", "log_ngd"))
#' )
#' s <- summary(fit)
#' s
#' @export
summary.csdm_fit <- function(object, digits = 4, ...) {
est <- object$coef_mg
Expand Down Expand Up @@ -189,15 +233,23 @@ summary.csdm_fit <- function(object, digits = 4, ...) {
}


#' Print summary of csdm_fit model
#' Print method for csdm summary objects
#'
#' Formats and prints a \code{summary.csdm_fit} object. Output adapts to model
#' type and includes coefficient tables, selected goodness-of-fit diagnostics,
#' and compact model metadata.
#'
#' @param x A summary.csdm_fit object.
#' @param x A \code{summary.csdm_fit} object.
#' @param digits Number of digits to print.
#' @param ... Further arguments passed to methods.
#'
#' @details
#' Displays classic Pesaran CD test statistics in the summary output. For extended CD diagnostics
#' (CDw, CDw+, CD*), call `cd_test()` on the fitted model object.
#' The printout includes classic Pesaran CD diagnostics from the summary object.
#' For a full CD diagnostic panel (CD, CDw, CDw+, CD*), use [cd_test()] on the
#' fitted model.
#'
#' @return Invisibly returns \code{x}.
#' @seealso [summary.csdm_fit()], [cd_test()]
#'
#' @export
print.summary.csdm_fit <- function(x, digits = 4, ...) {
Expand Down Expand Up @@ -290,6 +342,18 @@ print.summary.csdm_fit <- function(x, digits = 4, ...) {
invisible(x)
}

#' Extract model coefficients from a fitted csdm model
#'
#' Returns estimated mean-group coefficients from a \code{csdm_fit} object. For
#' \code{model = "cs_ardl"}, the returned vector includes short-run mean-group
#' coefficients, the adjustment coefficient (named \code{lr_<y>}), and long-run
#' coefficients when available.
#'
#' @param object A fitted object of class \code{csdm_fit}.
#' @param ... Currently unused.
#'
#' @return A named numeric vector of estimated coefficients.
#' @seealso [summary.csdm_fit()], [vcov.csdm_fit()]
#' @export
coef.csdm_fit <- function(object, ...) {
if (identical(object$model, "cs_ardl") && !is.null(object$cs_ardl) && !is.null(object$cs_ardl$mg)) {
Expand All @@ -310,12 +374,32 @@ coef.csdm_fit <- function(object, ...) {
}


#' Extract coefficient covariance matrix from a fitted csdm model
#'
#' @param object A fitted object of class \code{csdm_fit}.
#' @param ... Currently unused.
#'
#' @return A numeric variance-covariance matrix aligned with \code{coef(object)}
#' for models where this is available.
#' @seealso [coef.csdm_fit()], [summary.csdm_fit()]
#' @export
vcov.csdm_fit <- function(object, ...) {
object$vcov_mg
}


#' Extract residual matrix from a fitted csdm model
#'
#' Returns residuals as an \eqn{N x T} matrix (rows are units, columns are time).
#' This method is designed for panel diagnostics and downstream tools such as
#' [cd_test()].
#'
#' @param object A fitted object of class \code{csdm_fit}.
#' @param type Residual type. Currently only \code{"e"} is implemented.
#' @param ... Currently unused.
#'
#' @return A numeric matrix of residuals with dimensions \eqn{N x T}.
#' @seealso [get_residuals()], [cd_test()], [predict.csdm_fit()]
#' @export
residuals.csdm_fit <- function(object, type = c("e", "u"), ...) {
type <- match.arg(type)
Expand All @@ -324,6 +408,19 @@ residuals.csdm_fit <- function(object, type = c("e", "u"), ...) {
}


#' Predict method for csdm models
#'
#' Produces fitted values (index \code{"xb"}) when available, or returns model
#' residuals. Prediction on new data is not yet implemented.
#'
#' @param object A fitted object of class \code{csdm_fit}.
#' @param newdata Optional new data (not yet supported).
#' @param type One of \code{"xb"} for fitted values or \code{"residuals"}.
#' @param ... Currently unused.
#'
#' @return A numeric matrix of fitted values or residuals, depending on
#' \code{type}.
#' @seealso [residuals.csdm_fit()], [summary.csdm_fit()]
#' @export
predict.csdm_fit <- function(object, newdata = NULL, type = c("xb", "residuals"), ...) {
type <- match.arg(type)
Expand Down
Loading