-
Notifications
You must be signed in to change notification settings - Fork 123
v2.3.1.902: bug fixes, new broom methods, and documentation improvements #253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2f3bacf
93d692e
9c008ee
2848590
befc19f
40b7d53
60fbe21
960d9de
7288124
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| Package: did | ||
| Title: Treatment Effects with Multiple Periods and Groups | ||
| Version: 2.3.1.902 | ||
| Version: 2.3.1.903 | ||
|
||
| Authors@R: c(person("Brantly", "Callaway", email = "brantly.callaway@uga.edu", role = c("aut", "cre")), person("Pedro H. C.", "Sant'Anna", email="pedro.santanna@emory.edu", role = c("aut"))) | ||
| URL: https://bcallaway11.github.io/did/, https://github.com/bcallaway11/did/ | ||
| Description: The standard Difference-in-Differences (DID) setup involves two periods and two groups -- a treated group and untreated group. Many applications of DID methods involve more than two periods and have individuals that are treated at different points in time. This package contains tools for computing average treatment effect parameters in Difference in Differences setups with more than two periods and with variation in treatment timing using the methods developed in Callaway and Sant'Anna (2021) <doi:10.1016/j.jeconom.2020.12.001>. The main parameters are group-time average treatment effects which are the average treatment effect for a particular group at a a particular time. These can be aggregated into a fewer number of treatment effect parameters, and the package deals with the cases where there is selective treatment timing, dynamic treatment effects, calendar time effects, or combinations of these. There are also functions for testing the Difference in Differences assumption, and plotting group-time average treatment effects. | ||
|
|
@@ -30,4 +30,5 @@ Suggests: | |
| here, | ||
| knitr, | ||
| covr, | ||
| backports | ||
| backports, | ||
| broom | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -19,6 +19,14 @@ validate_args <- function(args, data){ | |||||||||||||||||||||||||||||
| name_message <- "__ARG__ must be a character scalar and a name of a column from the dataset." | ||||||||||||||||||||||||||||||
| dreamerr::check_set_arg(args$tname, args$gname, args$yname, "match", .choices = data_names, .message = name_message, .up = 1) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Strip idname from clustervars before validation: users may naturally pass | ||||||||||||||||||||||||||||||
| # clustervars = c(idname, extra_var), and idname clustering is implicit/redundant. | ||||||||||||||||||||||||||||||
| # This must happen before the dreamerr check which enforces scalar length. | ||||||||||||||||||||||||||||||
| if (!is.null(args$clustervars) && !is.null(args$idname) && (args$idname %in% args$clustervars)) { | ||||||||||||||||||||||||||||||
| args$clustervars <- setdiff(args$clustervars, args$idname) | ||||||||||||||||||||||||||||||
| if (length(args$clustervars) == 0L) args$clustervars <- NULL | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Flag for clustervars and weightsname | ||||||||||||||||||||||||||||||
| checkvar_message <- "__ARG__ must be NULL or a character scalar that is a name of a column from the dataset." | ||||||||||||||||||||||||||||||
| dreamerr::check_set_arg(args$weightsname, args$clustervars, "NULL | match", .choices = data_names, .message = checkvar_message, .up = 1) | ||||||||||||||||||||||||||||||
|
Comment on lines
30
to
32
|
||||||||||||||||||||||||||||||
| # Flag for clustervars and weightsname | |
| checkvar_message <- "__ARG__ must be NULL or a character scalar that is a name of a column from the dataset." | |
| dreamerr::check_set_arg(args$weightsname, args$clustervars, "NULL | match", .choices = data_names, .message = checkvar_message, .up = 1) | |
| # After stripping idname, ensure all remaining clustervars (if any) are column names. | |
| if (!is.null(args$clustervars)) { | |
| invalid_clust <- setdiff(args$clustervars, data_names) | |
| if (length(invalid_clust) > 0L) { | |
| stop("Each element of 'clustervars' must be the name of a column from the dataset.") | |
| } | |
| } | |
| # Flag for clustervars and weightsname | |
| checkvar_message <- "__ARG__ must be NULL or a character scalar that is a name of a column from the dataset." | |
| dreamerr::check_set_arg(args$weightsname, "NULL | match", .choices = data_names, .message = checkvar_message, .up = 1) |
Copilot
AI
Mar 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idname-stripping logic for clustervars is duplicated here and in validate_args(). Consider returning the (possibly modified) args from validate_args() (or factoring the stripping into a small helper) so the behavior stays consistent and future changes only need to be made in one place.
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,11 +6,60 @@ generics::tidy | |||||||||||||||
| #' @export | ||||||||||||||||
| generics::glance | ||||||||||||||||
|
|
||||||||||||||||
| #' tidy results from MP objects | ||||||||||||||||
| #' Number of unique cross-sectional units in an MP object | ||||||||||||||||
| #' | ||||||||||||||||
| #' @importFrom stats nobs | ||||||||||||||||
| #' @param object a model of class MP produced by the [att_gt()] function | ||||||||||||||||
| #' @param ... additional arguments (ignored) | ||||||||||||||||
| #' @return Integer. The number of unique cross-sectional units in the data. | ||||||||||||||||
| #' @export | ||||||||||||||||
| nobs.MP <- function(object, ...) { | ||||||||||||||||
| as.integer(object$n) | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| #' Number of unique cross-sectional units in an AGGTEobj object | ||||||||||||||||
| #' | ||||||||||||||||
| #' @importFrom stats nobs | ||||||||||||||||
| #' @param object a model of class AGGTEobj produced by the [aggte()] function | ||||||||||||||||
| #' @param ... additional arguments (ignored) | ||||||||||||||||
| #' @return Integer. The number of unique cross-sectional units in the data. | ||||||||||||||||
| #' @export | ||||||||||||||||
| nobs.AGGTEobj <- function(object, ...) { | ||||||||||||||||
| if (object$DIDparams$faster_mode) { | ||||||||||||||||
| as.integer(object$DIDparams$id_count) | ||||||||||||||||
| } else { | ||||||||||||||||
| as.integer(object$DIDparams$n) | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| #' Tidy an MP object into a data frame | ||||||||||||||||
| #' | ||||||||||||||||
| #' Returns a tidy data frame of group-time average treatment effect estimates | ||||||||||||||||
| #' from an [att_gt()] result. | ||||||||||||||||
| #' | ||||||||||||||||
| #' @importFrom generics tidy | ||||||||||||||||
| #' @param x a model of class MP produced by the [att_gt()] function | ||||||||||||||||
| #' @param ... Additional arguments to tidying method. | ||||||||||||||||
| #' | ||||||||||||||||
| #' @return A data frame with one row per ATT(g,t) estimate and columns: | ||||||||||||||||
| #' \describe{ | ||||||||||||||||
| #' \item{term}{ATT(g,t) label} | ||||||||||||||||
| #' \item{group}{the treatment cohort g} | ||||||||||||||||
| #' \item{time}{the time period t} | ||||||||||||||||
| #' \item{estimate}{the ATT(g,t) point estimate} | ||||||||||||||||
| #' \item{std.error}{standard error} | ||||||||||||||||
| #' \item{statistic}{t-statistic (\code{estimate / std.error})} | ||||||||||||||||
| #' \item{p.value}{two-sided pointwise p-value | ||||||||||||||||
| #' (\code{2 * (1 - pnorm(abs(statistic)))}). | ||||||||||||||||
|
Comment on lines
+51
to
+53
|
||||||||||||||||
| #' \item{statistic}{t-statistic (\code{estimate / std.error})} | |
| #' \item{p.value}{two-sided pointwise p-value | |
| #' (\code{2 * (1 - pnorm(abs(statistic)))}). | |
| #' \item{statistic}{z-statistic / normal-approximation test statistic | |
| #' (\code{estimate / std.error})} | |
| #' \item{p.value}{two-sided pointwise p-value based on the standard normal | |
| #' approximation (\code{2 * (1 - pnorm(abs(statistic)))}). |
Copilot
AI
Mar 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tidy.MP() and tidy.AGGTEobj() now compute and expose statistic/p.value, but the test suite doesn’t appear to cover these new columns. Add a small testthat case that checks the columns exist and that p.value matches the expected normal-approximation calculation (including handling of NA standard errors).
Copilot
AI
Mar 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above: the docs describe statistic as a “t-statistic”, but p-values are computed using pnorm() (normal approximation). Consider calling it a z-statistic (or clarifying it’s normal-approximation) to keep the return spec internally consistent.
| #' \item{statistic}{t-statistic (\code{estimate / std.error})} | |
| #' \item{statistic}{z-statistic (normal-approximation; \code{estimate / std.error})} |
Copilot
AI
Mar 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In tidy.AGGTEobj for type == "group", the p.value expression has unbalanced parentheses, which will cause a parse error when the package is loaded. Adjust the parentheses so the 2 * (1 - pnorm(abs(...))) expression is syntactically valid (and consider assigning the statistic vector once to avoid repeating the division).
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR title/description reference version
2.3.1.902, butDESCRIPTIONbumps the package to2.3.1.903. Please align the stated release version (either update the PR metadata/changelog text, or keep the version at 2.3.1.902 if that’s what’s intended).