├── .gitignore
├── man
├── figures
│ ├── logo.png
│ ├── README-unnamed-chunk-3-1.png
│ ├── README-unnamed-chunk-6-1.png
│ └── README-unnamed-chunk-8-1.png
├── ggpte.Rd
├── print.pte_results.Rd
├── print.group_time_att.Rd
├── process_att_gt.Rd
├── summary.pte_results.Rd
├── summary.group_time_att.Rd
├── print.summary.pte_results.Rd
├── pte_results.Rd
├── mboot2.Rd
├── summary.pte_emp_boot.Rd
├── gt_data_frame.Rd
├── attgt_pte_aggregations.Rd
├── attgt_noif.Rd
├── pte_aggte.Rd
├── attgt_if.Rd
├── keep_all_pretreatment_subset.Rd
├── qtt_pte_aggregations.Rd
├── qott_pte_aggregations.Rd
├── keep_all_untreated_subset.Rd
├── did_attgt.Rd
├── group_time_att.Rd
├── pte_emp_boot.Rd
├── two_by_two_subset.Rd
├── pte_attgt.Rd
├── setup_pte_basic.Rd
├── compute.pte.Rd
├── setup_pte.Rd
├── compute.pte2.Rd
├── pte_params.Rd
├── pte_default.Rd
└── panel_empirical_bootstrap.Rd
├── tests
├── testthat
│ ├── testthat-problems.rds
│ ├── test-did-inference.R
│ └── test-did.R
└── testthat.R
├── docs
├── pkgdown.yml
├── reference
│ ├── figures
│ │ ├── README-unnamed-chunk-3-1.png
│ │ ├── README-unnamed-chunk-6-1.png
│ │ └── README-unnamed-chunk-8-1.png
│ ├── ggpte.html
│ ├── process_att_gt.html
│ ├── print.pte_results.html
│ ├── summary.pte_results.html
│ ├── print.group_time_att.html
│ ├── pte_results.html
│ ├── mboot2.html
│ ├── summary.group_time_att.html
│ ├── print.summary.pte_results.html
│ ├── summary.pte_emp_boot.html
│ ├── qtt_pte_aggregations.html
│ ├── qott_pte_aggregations.html
│ ├── gt_data_frame.html
│ ├── orig2t.html
│ ├── t2orig.html
│ ├── attgt_noif.html
│ ├── attgt_pte_aggregations.html
│ ├── attgt_if.html
│ └── two_by_two_subset.html
├── link.svg
├── bootstrap-toc.css
├── docsearch.js
├── sitemap.xml
├── pkgdown.js
├── 404.html
├── bootstrap-toc.js
└── authors.html
├── .Rbuildignore
├── R
├── startup.R
├── zzz.R
├── imports.R
├── imputation_functions.R
├── ggpte.R
├── pte_aggte.R
├── process_att_gt.R
└── subset_functions.R
├── pte.Rproj
├── NAMESPACE
├── DESCRIPTION
└── .github
└── workflows
└── update-citation-cff.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .RData
4 | .Ruserdata
5 |
--------------------------------------------------------------------------------
/man/figures/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcallaway11/pte/HEAD/man/figures/logo.png
--------------------------------------------------------------------------------
/tests/testthat/testthat-problems.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcallaway11/pte/HEAD/tests/testthat/testthat-problems.rds
--------------------------------------------------------------------------------
/docs/pkgdown.yml:
--------------------------------------------------------------------------------
1 | pandoc: 2.9.2.1
2 | pkgdown: 2.0.6
3 | pkgdown_sha: ~
4 | articles: {}
5 | last_built: 2023-05-26T02:34Z
6 |
7 |
--------------------------------------------------------------------------------
/man/figures/README-unnamed-chunk-3-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcallaway11/pte/HEAD/man/figures/README-unnamed-chunk-3-1.png
--------------------------------------------------------------------------------
/man/figures/README-unnamed-chunk-6-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcallaway11/pte/HEAD/man/figures/README-unnamed-chunk-6-1.png
--------------------------------------------------------------------------------
/man/figures/README-unnamed-chunk-8-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcallaway11/pte/HEAD/man/figures/README-unnamed-chunk-8-1.png
--------------------------------------------------------------------------------
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^README\.Rmd$
2 | ^CITATION\.cff$
3 | ^\.github$
4 | ^.*\.Rproj$
5 | ^\.Rproj\.user$
6 | ^docs$
7 | ^R/imputation_functions.R$
8 |
--------------------------------------------------------------------------------
/docs/reference/figures/README-unnamed-chunk-3-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcallaway11/pte/HEAD/docs/reference/figures/README-unnamed-chunk-3-1.png
--------------------------------------------------------------------------------
/docs/reference/figures/README-unnamed-chunk-6-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcallaway11/pte/HEAD/docs/reference/figures/README-unnamed-chunk-6-1.png
--------------------------------------------------------------------------------
/docs/reference/figures/README-unnamed-chunk-8-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcallaway11/pte/HEAD/docs/reference/figures/README-unnamed-chunk-8-1.png
--------------------------------------------------------------------------------
/R/startup.R:
--------------------------------------------------------------------------------
1 | .onAttach <- function(libname, pkgname) {
2 | packageStartupMessage("NOTE: The 'pte' package has been renamed to 'ptetools'. Please update your usage.")
3 | }
4 |
--------------------------------------------------------------------------------
/R/zzz.R:
--------------------------------------------------------------------------------
1 | utils::globalVariables(c("e", "post", "ciu", "cil", "G", "Y", "att", "id", "name", "period", "att.e", "att.g", "group", "length.e", "length.group", "time.period", ".treat"))
2 |
--------------------------------------------------------------------------------
/man/ggpte.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ggpte.R
3 | \name{ggpte}
4 | \alias{ggpte}
5 | \title{ggpte}
6 | \usage{
7 | ggpte(pte_results)
8 | }
9 | \arguments{
10 | \item{pte_results}{A \code{pte_results} object}
11 | }
12 | \description{
13 | Simple event study plots for panel treatment effects
14 | }
15 |
--------------------------------------------------------------------------------
/R/imports.R:
--------------------------------------------------------------------------------
1 | #' Panel Treatment Effects
2 | #'
3 | #' Tools for estimating treatment effects with panel data.
4 | #'
5 | #' @docType package
6 | #' @name pte
7 | #' @import stats
8 | #' @import utils
9 | #' @import ggplot2
10 | #' @import tidyr
11 | #' @import BMisc
12 | #' @importFrom dplyr bind_rows group_by group_map inner_join mutate transmute
13 | "_PACKAGE"
14 |
--------------------------------------------------------------------------------
/pte.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | BuildType: Package
16 | PackageUseDevtools: Yes
17 | PackageInstallArgs: --no-multiarch --with-keep.source
18 |
--------------------------------------------------------------------------------
/man/print.pte_results.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{print.pte_results}
4 | \alias{print.pte_results}
5 | \title{print.pte_results}
6 | \usage{
7 | \method{print}{pte_results}(x, ...)
8 | }
9 | \arguments{
10 | \item{x}{a \code{pte_results} object}
11 |
12 | \item{...}{extra arguments}
13 | }
14 | \description{
15 | prints value of a \code{pte_results} object
16 | }
17 |
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | # This file is part of the standard setup for testthat.
2 | # It is recommended that you do not modify it.
3 | #
4 | # Where should you do additional test configuration?
5 | # Learn more about the roles of various files in:
6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
7 | # * https://testthat.r-lib.org/articles/special-files.html
8 |
9 | library(testthat)
10 | library(pte)
11 |
12 | test_check("pte")
13 |
--------------------------------------------------------------------------------
/man/print.group_time_att.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{print.group_time_att}
4 | \alias{print.group_time_att}
5 | \title{print.group_time_att}
6 | \usage{
7 | \method{print}{group_time_att}(x, ...)
8 | }
9 | \arguments{
10 | \item{x}{a \code{group_time_att} object}
11 |
12 | \item{...}{extra arguments}
13 | }
14 | \description{
15 | prints value of a \code{group_time_att} object
16 | }
17 |
--------------------------------------------------------------------------------
/man/process_att_gt.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/process_att_gt.R
3 | \name{process_att_gt}
4 | \alias{process_att_gt}
5 | \title{process_att_gt}
6 | \usage{
7 | process_att_gt(att_gt_results, ptep)
8 | }
9 | \arguments{
10 | \item{att_gt_results}{ATT(g,t)'s}
11 |
12 | \item{ptep}{\code{pte_params} object}
13 | }
14 | \description{
15 | process attgt results when influence function is available
16 | }
17 |
--------------------------------------------------------------------------------
/man/summary.pte_results.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{summary.pte_results}
4 | \alias{summary.pte_results}
5 | \title{summary.pte_results}
6 | \usage{
7 | \method{summary}{pte_results}(object, ...)
8 | }
9 | \arguments{
10 | \item{object}{an \code{pte_results} object}
11 |
12 | \item{...}{other arguments}
13 | }
14 | \description{
15 | A function to summarize \code{pte} results.
16 | }
17 |
--------------------------------------------------------------------------------
/man/summary.group_time_att.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{summary.group_time_att}
4 | \alias{summary.group_time_att}
5 | \title{summary.group_time_att}
6 | \usage{
7 | \method{summary}{group_time_att}(object, ...)
8 | }
9 | \arguments{
10 | \item{object}{an \code{group_time_att} object}
11 |
12 | \item{...}{extra arguments}
13 | }
14 | \description{
15 | prints a summary of a \code{group_time_att} object
16 | }
17 |
--------------------------------------------------------------------------------
/man/print.summary.pte_results.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{print.summary.pte_results}
4 | \alias{print.summary.pte_results}
5 | \title{print.summary.pte_results}
6 | \usage{
7 | \method{print}{summary.pte_results}(x, ...)
8 | }
9 | \arguments{
10 | \item{x}{a \code{summary.pte_results} object}
11 |
12 | \item{...}{extra arguments}
13 | }
14 | \description{
15 | prints value of a \code{summary.pte_results} object
16 | }
17 |
--------------------------------------------------------------------------------
/man/pte_results.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{pte_results}
4 | \alias{pte_results}
5 | \title{pte_results}
6 | \usage{
7 | pte_results(att_gt, overall_att, event_study, ptep)
8 | }
9 | \arguments{
10 | \item{att_gt}{attgt results}
11 |
12 | \item{overall_att}{overall_att results}
13 |
14 | \item{event_study}{event_study results}
15 |
16 | \item{ptep}{\code{pte_params} object}
17 | }
18 | \description{
19 | class for holding pte results
20 | }
21 |
--------------------------------------------------------------------------------
/man/mboot2.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/process_att_gt.R
3 | \name{mboot2}
4 | \alias{mboot2}
5 | \title{mboot2}
6 | \usage{
7 | mboot2(inffunc, biters = 1000, alp = 0.05)
8 | }
9 | \arguments{
10 | \item{inffunc}{influence function matrix}
11 |
12 | \item{biters}{number of bootstrap iterations; default is 100}
13 |
14 | \item{alp}{significance level; default is 0.05}
15 | }
16 | \description{
17 | function for using multiplier bootstrap to conduct
18 | inference
19 | }
20 |
--------------------------------------------------------------------------------
/man/summary.pte_emp_boot.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{summary.pte_emp_boot}
4 | \alias{summary.pte_emp_boot}
5 | \title{summary.pte_emp_boot}
6 | \usage{
7 | \method{summary}{pte_emp_boot}(object, ...)
8 | }
9 | \arguments{
10 | \item{object}{a \code{pte_emp_boot} object}
11 |
12 | \item{...}{additional function arguments}
13 | }
14 | \value{
15 | \code{summary.pte_results} object
16 | }
17 | \description{
18 | Summary for \code{pte_emp_boot} object
19 | }
20 |
--------------------------------------------------------------------------------
/R/imputation_functions.R:
--------------------------------------------------------------------------------
1 | # in progress...not sure if we'll actually use this
2 | #' @keywords internal
3 | twfe_imputation <- function(data, ptep) {
4 |
5 | browser()
6 | yname <- ptep$yname
7 | idname <- ptep$idname
8 | tname <- ptep$tname
9 | gname <- ptep$gname
10 |
11 | formla <- paste0(yname, "~", 0)
12 | formla <- paste0(formla, " | ", idname, " + ", tname)
13 | formla <- as.formula(formla)
14 |
15 | pre_data <- data[ ( data[,tname] < data[,gname] ) | data[,gname]==0, ]
16 |
17 | twfe_est <- fixest::feols(formla, data=pre_data)
18 |
19 | y0 <- predict(twfe_est, newdata=data)
20 |
21 | y0
22 | }
23 |
--------------------------------------------------------------------------------
/man/gt_data_frame.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{gt_data_frame}
4 | \alias{gt_data_frame}
5 | \title{gt_data_frame}
6 | \usage{
7 | gt_data_frame(data)
8 | }
9 | \arguments{
10 | \item{data}{data that will be checked to see if has right format for
11 | computing group-time average treatment effects}
12 | }
13 | \value{
14 | \code{gt_data_frame} object
15 | }
16 | \description{
17 | function to take in a data.frame, check if it has the right
18 | columns to be used to calculate a group-time average treatment effect,
19 | and sets the class of the data.frame to include \code{gt_data_frame}
20 | }
21 |
--------------------------------------------------------------------------------
/R/ggpte.R:
--------------------------------------------------------------------------------
1 | #' @title ggpte
2 | #'
3 | #' @description Simple event study plots for panel treatment effects
4 | #'
5 | #' @param pte_results A \code{pte_results} object
6 | #'
7 | #' @export
8 | ggpte <- function(pte_results) {
9 | plot_df <- summary(pte_results)$event_study
10 | colnames(plot_df) <- c("e", "att", "se", "cil", "ciu")
11 | plot_df$post <- as.factor(1*(plot_df$e >= 0))
12 | ggplot(plot_df, aes(x=e, y=att)) +
13 | geom_line(aes(color=post)) +
14 | geom_point(aes(color=post)) +
15 | geom_line(aes(y=ciu), linetype="dashed", alpha=0.5) +
16 | geom_line(aes(y=cil), linetype="dashed", alpha=0.5) +
17 | theme_bw() +
18 | theme(legend.position="bottom")
19 | }
20 |
--------------------------------------------------------------------------------
/man/attgt_pte_aggregations.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/empirical_bootstrap.R
3 | \name{attgt_pte_aggregations}
4 | \alias{attgt_pte_aggregations}
5 | \title{attgt_pte_aggregations}
6 | \usage{
7 | attgt_pte_aggregations(attgt.list, ptep)
8 | }
9 | \arguments{
10 | \item{attgt.list}{list of attgt results from \code{compute.pte}}
11 |
12 | \item{ptep}{\code{pte_params} object}
13 | }
14 | \value{
15 | \code{pte_emp_boot} object
16 | }
17 | \description{
18 | Aggregate group-time average treatment effects into
19 | overall, group, and dynamic effects. This function is only used
20 | for (i) computing standard errors using the empirical bootstrap,
21 | and (ii) combining distributions at the (g,t) level
22 | }
23 |
--------------------------------------------------------------------------------
/docs/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
--------------------------------------------------------------------------------
/man/attgt_noif.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{attgt_noif}
4 | \alias{attgt_noif}
5 | \title{attgt_noif}
6 | \usage{
7 | attgt_noif(attgt, extra_gt_returns = NULL)
8 | }
9 | \arguments{
10 | \item{attgt}{group-time average treatment effect}
11 |
12 | \item{extra_gt_returns}{A place to return anything extra from particular
13 | group-time average treatment effect calculations. For DID, this might
14 | be something like propensity score estimates, regressions of untreated
15 | potential outcomes on covariates. For ife, this could be something
16 | like the first step regression 2sls estimates. This argument is also
17 | potentially useful for debugging.}
18 | }
19 | \value{
20 | attgt_noif object
21 | }
22 | \description{
23 | Class for holding group-time average treatment effects
24 | which don't include influence functions
25 | }
26 |
--------------------------------------------------------------------------------
/man/pte_aggte.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/pte_aggte.R
3 | \name{pte_aggte}
4 | \alias{pte_aggte}
5 | \title{pte_aggte}
6 | \usage{
7 | pte_aggte(attgt, type = "overall")
8 | }
9 | \arguments{
10 | \item{attgt}{A group_time_att object to be aggregated}
11 |
12 | \item{type}{The type of aggregation to be done. Default is "overall"}
13 | }
14 | \description{
15 | This is a slight edit of the aggte function from the \code{did} package.
16 | Currently, it only provides aggregations for "overall" treatment effects
17 | and event studies. It also will provide the weights directly which is
18 | currently used for constructing aggregations based on distributions.
19 | The other difference is that, \code{pte_aggte} provides inference results
20 | where the only randomness is coming from the outcomes (not from the group
21 | assignment nor from the covariates).
22 | }
23 |
--------------------------------------------------------------------------------
/man/attgt_if.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{attgt_if}
4 | \alias{attgt_if}
5 | \title{attgt_if}
6 | \usage{
7 | attgt_if(attgt, inf_func, extra_gt_returns = NULL)
8 | }
9 | \arguments{
10 | \item{attgt}{group-time average treatment effect}
11 |
12 | \item{inf_func}{influence function}
13 |
14 | \item{extra_gt_returns}{A place to return anything extra from particular
15 | group-time average treatment effect calculations. For DID, this might
16 | be something like propensity score estimates, regressions of untreated
17 | potential outcomes on covariates. For ife, this could be something
18 | like the first step regression 2sls estimates. This argument is also
19 | potentially useful for debugging.}
20 | }
21 | \value{
22 | attgt_if object
23 | }
24 | \description{
25 | Class for holding group-time average treatment effects
26 | along with their influence function
27 | }
28 |
--------------------------------------------------------------------------------
/R/pte_aggte.R:
--------------------------------------------------------------------------------
1 | #' @title pte_aggte
2 | #'
3 | #' @description This is a slight edit of the aggte function from the `did` package.
4 | #' Currently, it only provides aggregations for "overall" treatment effects
5 | #' and event studies. It also will provide the weights directly which is
6 | #' currently used for constructing aggregations based on distributions.
7 | #' The other difference is that, `pte_aggte` provides inference results
8 | #' where the only randomness is coming from the outcomes (not from the group
9 | #' assignment nor from the covariates).
10 | #'
11 | #' @param attgt A group_time_att object to be aggregated
12 | #' @param type The type of aggregation to be done. Default is "overall"
13 | pte_aggte <- function(attgt,
14 | type="overall") {
15 |
16 | group <- attgt$group
17 | time.period <- attgt$time.period
18 | att <- attgt$att
19 | ptep <- attgt$ptep
20 | bstrap <- ptep$bstrap
21 | cband <- ptep$bstrap
22 | alp <- ptep$alp
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/man/keep_all_pretreatment_subset.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/subset_functions.R
3 | \name{keep_all_pretreatment_subset}
4 | \alias{keep_all_pretreatment_subset}
5 | \title{keep_all_pretreatment_subset}
6 | \usage{
7 | keep_all_pretreatment_subset(data, g, tp, ...)
8 | }
9 | \arguments{
10 | \item{data}{the full dataset}
11 |
12 | \item{g}{the current group}
13 |
14 | \item{tp}{the current time period}
15 |
16 | \item{...}{additional arguments}
17 | }
18 | \value{
19 | all data but in correct format for computing ATT(g,t)
20 | }
21 | \description{
22 | A function that takes an original data set and keeps all
23 | data for all groups that are not-yet-treated by period \code{tp} as well
24 | as for group \code{g}.
25 |
26 | In particular, this keeps more data than functions like \code{two_by_two}
27 | subset that use a fixed base period.
28 |
29 | A main use case for this function is the interactive fixed effects approach
30 | proposed in Callaway and Tsyawo (2023).
31 | }
32 |
--------------------------------------------------------------------------------
/man/qtt_pte_aggregations.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/empirical_bootstrap.R
3 | \name{qtt_pte_aggregations}
4 | \alias{qtt_pte_aggregations}
5 | \title{qtt_pte_aggregations}
6 | \usage{
7 | qtt_pte_aggregations(attgt.list, ptep, extra_gt_returns)
8 | }
9 | \arguments{
10 | \item{attgt.list}{list of attgt results from \code{compute.pte}}
11 |
12 | \item{ptep}{\code{pte_params} object}
13 |
14 | \item{extra_gt_returns}{A place to return anything extra from particular
15 | group-time average treatment effect calculations. For DID, this might
16 | be something like propensity score estimates, regressions of untreated
17 | potential outcomes on covariates. For ife, this could be something
18 | like the first step regression 2sls estimates. This argument is also
19 | potentially useful for debugging.}
20 | }
21 | \value{
22 | \code{pte_emp_boot} object
23 | }
24 | \description{
25 | Aggregate group-time distributions into qtt versions of
26 | overall, group, and dynamic effects.
27 | }
28 |
--------------------------------------------------------------------------------
/man/qott_pte_aggregations.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/empirical_bootstrap.R
3 | \name{qott_pte_aggregations}
4 | \alias{qott_pte_aggregations}
5 | \title{qott_pte_aggregations}
6 | \usage{
7 | qott_pte_aggregations(attgt.list, ptep, extra_gt_returns)
8 | }
9 | \arguments{
10 | \item{attgt.list}{list of attgt results from \code{compute.pte}}
11 |
12 | \item{ptep}{\code{pte_params} object}
13 |
14 | \item{extra_gt_returns}{A place to return anything extra from particular
15 | group-time average treatment effect calculations. For DID, this might
16 | be something like propensity score estimates, regressions of untreated
17 | potential outcomes on covariates. For ife, this could be something
18 | like the first step regression 2sls estimates. This argument is also
19 | potentially useful for debugging.}
20 | }
21 | \value{
22 | \code{pte_emp_boot} object
23 | }
24 | \description{
25 | Aggregate group-time distribution of the treatment effect into
26 | overall, group, and dynamic effects.
27 | }
28 |
--------------------------------------------------------------------------------
/man/keep_all_untreated_subset.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/subset_functions.R
3 | \name{keep_all_untreated_subset}
4 | \alias{keep_all_untreated_subset}
5 | \title{keep_all_untreated_subset}
6 | \usage{
7 | keep_all_untreated_subset(data, g, tp, ...)
8 | }
9 | \arguments{
10 | \item{data}{the full dataset}
11 |
12 | \item{g}{the current group}
13 |
14 | \item{tp}{the current time period}
15 |
16 | \item{...}{extra arguments to get the subset correct}
17 | }
18 | \value{
19 | all data but in correct format for computing ATT(g,t)
20 | }
21 | \description{
22 | A function that takes an original data set and keeps all
23 | pre-treatment data for all groups. For group g, it also includes data
24 | for the current period.
25 |
26 | Also, note that if \code{tp} is still a pre-treatment period for group g,
27 | then periods after \code{tp} will also be dropped for group g. This is a
28 | design choice and is useful especially for estimating placebo
29 | group-time average treatment effects in pre-treatment periods.
30 |
31 | A main use case for this function is to compute ATT(g,t)'s using a global
32 | estimation strategy such as imputation in Gardner (2022).
33 | }
34 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | S3method(print,group_time_att)
4 | S3method(print,pte_results)
5 | S3method(print,summary.pte_results)
6 | S3method(summary,group_time_att)
7 | S3method(summary,pte_emp_boot)
8 | S3method(summary,pte_results)
9 | export(attgt_if)
10 | export(attgt_noif)
11 | export(attgt_pte_aggregations)
12 | export(compute.pte)
13 | export(compute.pte2)
14 | export(did_attgt)
15 | export(ggpte)
16 | export(group_time_att)
17 | export(gt_data_frame)
18 | export(keep_all_pretreatment_subset)
19 | export(keep_all_untreated_subset)
20 | export(mboot2)
21 | export(panel_empirical_bootstrap)
22 | export(process_att_gt)
23 | export(pte)
24 | export(pte2)
25 | export(pte_attgt)
26 | export(pte_default)
27 | export(pte_emp_boot)
28 | export(pte_params)
29 | export(pte_results)
30 | export(qott_pte_aggregations)
31 | export(qtt_pte_aggregations)
32 | export(setup_pte)
33 | export(setup_pte_basic)
34 | export(two_by_two_subset)
35 | import(BMisc)
36 | import(ggplot2)
37 | import(stats)
38 | import(tidyr)
39 | import(utils)
40 | importFrom(dplyr,bind_rows)
41 | importFrom(dplyr,group_by)
42 | importFrom(dplyr,group_map)
43 | importFrom(dplyr,inner_join)
44 | importFrom(dplyr,mutate)
45 | importFrom(dplyr,transmute)
46 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: pte
2 | Title: Panel Treatment Effects
3 | Version: 0.0.0.9000
4 | Authors@R:
5 | person(given = "Brantly",
6 | family = "Callaway",
7 | role = c("aut", "cre"),
8 | email = "brantly.callaway@uga.edu")
9 | URL: https://github.com/bcallaway11/pte
10 | Description: This is fairly generic code for estimating treatment effects with panel data. This is useful code in my own work and will perhaps be useful to others. It builds heavily on the \code{did} package. In particular, it breaks into separate steps organizing the data, looping over groups and time periods, computing group-time average treatment effects, and aggregating group-time average treatment effects. Often, one is able to implement a new identification/estimation procedure by simply replacing the step on estimating group-time average treatment effects. See several different examples of this approach in the README.
11 | License: GPL-3
12 | Encoding: UTF-8
13 | LazyData: true
14 | Roxygen: list(markdown = TRUE)
15 | RoxygenNote: 7.3.2
16 | Imports:
17 | BMisc (>= 1.4.7),
18 | Matrix,
19 | did (>= 2.0.0),
20 | ggplot2,
21 | DRDID,
22 | tidyr,
23 | dplyr,
24 | pbapply
25 | Suggests:
26 | testthat (>= 3.0.0)
27 | Config/testthat/edition: 3
28 |
--------------------------------------------------------------------------------
/man/did_attgt.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/attgt_functions.R
3 | \name{did_attgt}
4 | \alias{did_attgt}
5 | \title{did_attgt}
6 | \usage{
7 | did_attgt(gt_data, xformla, ...)
8 | }
9 | \arguments{
10 | \item{gt_data}{data that is "local" to a particular group-time average
11 | treatment effect}
12 |
13 | \item{xformla}{one-sided formula for covariates used in the propensity score
14 | and outcome regression models}
15 |
16 | \item{...}{extra function arguments; not used here}
17 | }
18 | \value{
19 | attgt_if
20 | }
21 | \description{
22 | Takes a "local" data.frame and computes
23 | an estimate of a group time average treatment effect
24 | and a corresponding influence function using a difference in differences
25 | approach.
26 |
27 | The code relies on \code{gt_data} having certain variables defined.
28 | In particular, there should be an \code{id} column (individual identifier),
29 | \code{D} (treated group identifier), \code{period} (time period), \code{name}
30 | (equal to "pre" for pre-treatment periods and equal to "post" for post
31 | treatment periods), \code{Y} (outcome).
32 |
33 | In our case, we call \code{pte::two_by_two_subset} which sets up the
34 | data to have this format before the call to \code{did_attgt}.
35 | }
36 |
--------------------------------------------------------------------------------
/tests/testthat/test-did-inference.R:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------------------
2 | # inference tests for did
3 | #------------------------------------------------------------------------
4 |
5 | library(did)
6 | library(pbapply)
7 |
8 |
9 | # skip_inf <- menu(c("run", "skip"), title="would you like to run or skip the inference tests?")
10 | # skip_inf <- skip_inf == 2
11 |
12 | test_that("tests for inference", {
13 | # skip_if(skip_inf)
14 | # cl <- as.numeric(readline("how many clusters would like to use for the inference tests? "))
15 | cl <- 1
16 | mc_sims <- 100
17 | rejs <- pblapply(1:mc_sims, function(mc) {
18 | sp <- did::reset.sim()
19 | data <- did::build_sim_dataset(sp)
20 |
21 | res <- pte(
22 | yname = "Y",
23 | gname = "G",
24 | tname = "period",
25 | idname = "id",
26 | data = data,
27 | setup_pte_fun = setup_pte,
28 | subset_fun = two_by_two_subset,
29 | attgt_fun = did_attgt,
30 | xformla = ~X
31 | )
32 | # truth is that att = 1
33 | tstat <- (res$overall_att$overall.att - 1) / res$overall_att$overall.se
34 | rej <- 1 * (abs(tstat) > qnorm(.975))
35 | rej
36 | }, cl = cl)
37 |
38 | rej_frac <- mean(unlist(rejs))
39 |
40 | expect_equal(rej_frac, 0.06, tolerance = .05) # make test fail if reject 0
41 | })
42 |
--------------------------------------------------------------------------------
/man/group_time_att.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{group_time_att}
4 | \alias{group_time_att}
5 | \title{group_time_att}
6 | \usage{
7 | group_time_att(
8 | group,
9 | time.period,
10 | att,
11 | V_analytical,
12 | se,
13 | crit_val,
14 | inf_func,
15 | n,
16 | W,
17 | Wpval,
18 | cband,
19 | alp,
20 | ptep,
21 | extra_gt_returns
22 | )
23 | }
24 | \arguments{
25 | \item{group}{numeric vector of groups for ATT(g,t)}
26 |
27 | \item{time.period}{numeric vector of time periods for ATT(g,t)}
28 |
29 | \item{att}{numeric vector containing the value of ATT(g,t) for
30 | corresponding group and time period}
31 |
32 | \item{V_analytical}{analytical asymptotic variance matrix for ATT(g,t)'s}
33 |
34 | \item{se}{numeric vector of standard errors}
35 |
36 | \item{crit_val}{critical value (usually a critical value for conducting
37 | uniform inference)}
38 |
39 | \item{inf_func}{matrix of influence function}
40 |
41 | \item{n}{number of unique individuals}
42 |
43 | \item{W}{Wald statistic for ATT(g,t) version of pre-test of parallel trends
44 | assumption}
45 |
46 | \item{Wpval}{p-value for Wald pre-test of ATT(g,t) version of parallel
47 | trends assumption}
48 |
49 | \item{cband}{logical indicating whether or not to report a confidence band}
50 |
51 | \item{alp}{significance level}
52 |
53 | \item{ptep}{\code{pte_params} object}
54 |
55 | \item{extra_gt_returns}{list containing extra returns at the group-time level}
56 | }
57 | \value{
58 | object of class \code{group_time_att}
59 | }
60 | \description{
61 | group_time_att class
62 | }
63 |
--------------------------------------------------------------------------------
/man/pte_emp_boot.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/classes.R
3 | \name{pte_emp_boot}
4 | \alias{pte_emp_boot}
5 | \title{pte_emp_boot}
6 | \usage{
7 | pte_emp_boot(
8 | attgt_results,
9 | overall_results,
10 | group_results,
11 | dyn_results,
12 | overall_weights = NULL,
13 | dyn_weights = NULL,
14 | group_weights = NULL,
15 | extra_gt_returns = NULL
16 | )
17 | }
18 | \arguments{
19 | \item{attgt_results}{\code{data.frame} holding attgt results}
20 |
21 | \item{overall_results}{\code{data.frame} holding overall results}
22 |
23 | \item{group_results}{\code{data.frame} holding group results}
24 |
25 | \item{dyn_results}{\code{data.frame} holding dynamic results}
26 |
27 | \item{overall_weights}{vector containing weights on underlying ATT(g,t)
28 | for overall treatment effect parameter}
29 |
30 | \item{dyn_weights}{list containing weights on underlying ATT(g,t)
31 | for each value of \code{e} corresponding to the dynamic treatment
32 | effect parameters.}
33 |
34 | \item{group_weights}{list containing weights on underlying ATT(g,t)
35 | corresponding to deliver averaged group-specific treatment effects}
36 |
37 | \item{extra_gt_returns}{A place to return anything extra from particular
38 | group-time average treatment effect calculations. For DID, this might
39 | be something like propensity score estimates, regressions of untreated
40 | potential outcomes on covariates. For ife, this could be something
41 | like the first step regression 2sls estimates. This argument is also
42 | potentially useful for debugging.}
43 | }
44 | \value{
45 | pte_emp_boot object
46 | }
47 | \description{
48 | pte_emp_boot
49 |
50 | Class for holding \code{pte} empirical bootstrap results
51 | }
52 |
--------------------------------------------------------------------------------
/.github/workflows/update-citation-cff.yaml:
--------------------------------------------------------------------------------
1 | # Workflow derived from https://github.com/r-lib/actions/tree/master/examples
2 | # The action runs when:
3 | # - A new release is published
4 | # - The DESCRIPTION or inst/CITATION are modified
5 | # - Can be run manually
6 | # For customizing the triggers, visit https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows
7 | on:
8 | release:
9 | types: [published]
10 | push:
11 | branches: [master, main]
12 | paths:
13 | - DESCRIPTION
14 | - inst/CITATION
15 | workflow_dispatch:
16 |
17 | name: Update CITATION.cff
18 |
19 | jobs:
20 | update-citation-cff:
21 | runs-on: macos-latest
22 | env:
23 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
24 | steps:
25 | - uses: actions/checkout@v2
26 | - uses: r-lib/actions/setup-r@v2
27 | - uses: r-lib/actions/setup-r-dependencies@v2
28 | with:
29 | extra-packages: |
30 | any::cffr
31 | any::V8
32 |
33 | - name: Update CITATION.cff
34 | run: |
35 |
36 | library(cffr)
37 |
38 | # Customize with your own code
39 | # See https://docs.ropensci.org/cffr/articles/cffr.html
40 |
41 | # Write your own keys
42 | mykeys <- list()
43 |
44 | # Create your CITATION.cff file
45 | cff_write(keys = mykeys)
46 |
47 | shell: Rscript {0}
48 |
49 | - name: Commit results
50 | run: |
51 | git config --local user.name "$GITHUB_ACTOR"
52 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
53 | git add CITATION.cff
54 | git commit -m 'Update CITATION.cff' || echo "No changes to commit"
55 | git push origin || echo "No changes to commit"
56 |
--------------------------------------------------------------------------------
/man/two_by_two_subset.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/subset_functions.R
3 | \name{two_by_two_subset}
4 | \alias{two_by_two_subset}
5 | \title{two_by_two_subset}
6 | \usage{
7 | two_by_two_subset(
8 | data,
9 | g,
10 | tp,
11 | control_group = "notyettreated",
12 | anticipation = 0,
13 | base_period = "varying",
14 | ...
15 | )
16 | }
17 | \arguments{
18 | \item{data}{the full dataset}
19 |
20 | \item{g}{the current group}
21 |
22 | \item{tp}{the current time period}
23 |
24 | \item{control_group}{whether to use "notyettreated" (default) or
25 | "nevertreated"}
26 |
27 | \item{anticipation}{the number of periods of anticipation (i.e., number
28 | of periods before the treatment happens where the treatment can "already"
29 | affect the outcome)}
30 |
31 | \item{base_period}{The type of base period to use. This only affects
32 | the numeric value of results in pre-treatment periods. Results in
33 | post-treatment periods are not affected by this choice. The default
34 | is "varying", where the base period will "back up" to the immediately
35 | preceding period in pre-treatment periods. The other option is "universal"
36 | where the base period is fixed in pre-treatment periods to be the period
37 | right before the treatment starts. "Universal" is commonly used in
38 | difference-in-differences applications, but can be unnatural for other
39 | identification strategies.}
40 |
41 | \item{...}{extra arguments to get the subset correct}
42 | }
43 | \value{
44 | list that contains correct subset of data, \code{n1}
45 | number of observations
46 | in this subset, and \code{disidx} a vector of the correct ids for this
47 | subset.
48 | }
49 | \description{
50 | A function for computing a 2x2 subset of original data.
51 | This is the subset with post treatment periods separately for the
52 | treated group and comparison group and pre-treatment periods in the period
53 | immediately before the treated group became treated.
54 | }
55 |
--------------------------------------------------------------------------------
/man/pte_attgt.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/attgt_functions.R
3 | \name{pte_attgt}
4 | \alias{pte_attgt}
5 | \title{pte_attgt}
6 | \usage{
7 | pte_attgt(
8 | gt_data,
9 | xformla,
10 | d_outcome = FALSE,
11 | d_covs_formula = ~-1,
12 | lagged_outcome_cov = FALSE,
13 | est_method = "dr",
14 | ...
15 | )
16 | }
17 | \arguments{
18 | \item{gt_data}{data that is "local" to a particular group-time average
19 | treatment effect}
20 |
21 | \item{xformla}{one-sided formula for covariates used in the propensity score
22 | and outcome regression models}
23 |
24 | \item{d_outcome}{Whether or not to take the first difference of the outcome.
25 | The default is FALSE. To use difference-in-differences, set this to be TRUE.}
26 |
27 | \item{d_covs_formula}{A formula for time varying covariates to enter the
28 | first estimation step models. The default is not to include any, and, hence,
29 | to only include pre-treatment covariats.}
30 |
31 | \item{lagged_outcome_cov}{Whether to include the lagged outcome as a covariate.
32 | Default is FALSE.}
33 |
34 | \item{est_method}{Which type of estimation method to use. Default is "dr" for
35 | doubly robust. The other option is "reg" for regression adjustment.}
36 |
37 | \item{...}{extra function arguments; not used here}
38 | }
39 | \value{
40 | attgt_if
41 | }
42 | \description{
43 | \code{pte_attgt} takes a "local" data.frame and computes
44 | an estimate of a group time average treatment effect
45 | and a corresponding influence function. This function generalizes
46 | a number of existing methods.
47 |
48 | The code relies on \code{this.data} having certain variables defined.
49 | In particular, there should be an \code{id} column (individual identifier),
50 | \code{G} (group identifier), \code{period} (time period), \code{name}
51 | (equal to "pre" for pre-treatment periods and equal to "post" for post
52 | treatment periods), \code{Y} (outcome).
53 |
54 | In our case, we call \code{pte::two_by_two_subset} which sets up the
55 | data to have this format before the call to \code{pte_attgt}
56 | }
57 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 |
6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */
7 |
8 | /* All levels of nav */
9 | nav[data-toggle='toc'] .nav > li > a {
10 | display: block;
11 | padding: 4px 20px;
12 | font-size: 13px;
13 | font-weight: 500;
14 | color: #767676;
15 | }
16 | nav[data-toggle='toc'] .nav > li > a:hover,
17 | nav[data-toggle='toc'] .nav > li > a:focus {
18 | padding-left: 19px;
19 | color: #563d7c;
20 | text-decoration: none;
21 | background-color: transparent;
22 | border-left: 1px solid #563d7c;
23 | }
24 | nav[data-toggle='toc'] .nav > .active > a,
25 | nav[data-toggle='toc'] .nav > .active:hover > a,
26 | nav[data-toggle='toc'] .nav > .active:focus > a {
27 | padding-left: 18px;
28 | font-weight: bold;
29 | color: #563d7c;
30 | background-color: transparent;
31 | border-left: 2px solid #563d7c;
32 | }
33 |
34 | /* Nav: second level (shown on .active) */
35 | nav[data-toggle='toc'] .nav .nav {
36 | display: none; /* Hide by default, but at >768px, show it */
37 | padding-bottom: 10px;
38 | }
39 | nav[data-toggle='toc'] .nav .nav > li > a {
40 | padding-top: 1px;
41 | padding-bottom: 1px;
42 | padding-left: 30px;
43 | font-size: 12px;
44 | font-weight: normal;
45 | }
46 | nav[data-toggle='toc'] .nav .nav > li > a:hover,
47 | nav[data-toggle='toc'] .nav .nav > li > a:focus {
48 | padding-left: 29px;
49 | }
50 | nav[data-toggle='toc'] .nav .nav > .active > a,
51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a,
52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a {
53 | padding-left: 28px;
54 | font-weight: 500;
55 | }
56 |
57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */
58 | nav[data-toggle='toc'] .nav > .active > ul {
59 | display: block;
60 | }
61 |
--------------------------------------------------------------------------------
/docs/docsearch.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | // register a handler to move the focus to the search bar
4 | // upon pressing shift + "/" (i.e. "?")
5 | $(document).on('keydown', function(e) {
6 | if (e.shiftKey && e.keyCode == 191) {
7 | e.preventDefault();
8 | $("#search-input").focus();
9 | }
10 | });
11 |
12 | $(document).ready(function() {
13 | // do keyword highlighting
14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */
15 | var mark = function() {
16 |
17 | var referrer = document.URL ;
18 | var paramKey = "q" ;
19 |
20 | if (referrer.indexOf("?") !== -1) {
21 | var qs = referrer.substr(referrer.indexOf('?') + 1);
22 | var qs_noanchor = qs.split('#')[0];
23 | var qsa = qs_noanchor.split('&');
24 | var keyword = "";
25 |
26 | for (var i = 0; i < qsa.length; i++) {
27 | var currentParam = qsa[i].split('=');
28 |
29 | if (currentParam.length !== 2) {
30 | continue;
31 | }
32 |
33 | if (currentParam[0] == paramKey) {
34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20"));
35 | }
36 | }
37 |
38 | if (keyword !== "") {
39 | $(".contents").unmark({
40 | done: function() {
41 | $(".contents").mark(keyword);
42 | }
43 | });
44 | }
45 | }
46 | };
47 |
48 | mark();
49 | });
50 | });
51 |
52 | /* Search term highlighting ------------------------------*/
53 |
54 | function matchedWords(hit) {
55 | var words = [];
56 |
57 | var hierarchy = hit._highlightResult.hierarchy;
58 | // loop to fetch from lvl0, lvl1, etc.
59 | for (var idx in hierarchy) {
60 | words = words.concat(hierarchy[idx].matchedWords);
61 | }
62 |
63 | var content = hit._highlightResult.content;
64 | if (content) {
65 | words = words.concat(content.matchedWords);
66 | }
67 |
68 | // return unique words
69 | var words_uniq = [...new Set(words)];
70 | return words_uniq;
71 | }
72 |
73 | function updateHitURL(hit) {
74 |
75 | var words = matchedWords(hit);
76 | var url = "";
77 |
78 | if (hit.anchor) {
79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor;
80 | } else {
81 | url = hit.url + '?q=' + escape(words.join(" "));
82 | }
83 |
84 | return url;
85 | }
86 |
--------------------------------------------------------------------------------
/man/setup_pte_basic.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/pte_params.R
3 | \name{setup_pte_basic}
4 | \alias{setup_pte_basic}
5 | \title{Example setup panel treatment effects parameters}
6 | \usage{
7 | setup_pte_basic(
8 | yname,
9 | gname,
10 | tname,
11 | idname,
12 | data,
13 | cband = TRUE,
14 | alp = 0.05,
15 | boot_type = "multiplier",
16 | gt_type = "att",
17 | ret_quantile = 0.5,
18 | biters = 100,
19 | cl = 1,
20 | ...
21 | )
22 | }
23 | \arguments{
24 | \item{yname}{Name of outcome in \code{data}}
25 |
26 | \item{gname}{Name of group in \code{data}}
27 |
28 | \item{tname}{Name of time period in \code{data}}
29 |
30 | \item{idname}{Name of id in \code{data}}
31 |
32 | \item{data}{balanced panel data}
33 |
34 | \item{cband}{whether or not to report a uniform (instead of pointwise)
35 | confidence band (default is TRUE)}
36 |
37 | \item{alp}{significance level; default is 0.05}
38 |
39 | \item{boot_type}{which type of bootstrap to use}
40 |
41 | \item{gt_type}{which type of group-time effects are computed.
42 | The default is "att". Different estimation strategies can implement
43 | their own choices for \code{gt_type}}
44 |
45 | \item{ret_quantile}{For functions that compute quantile treatment effects,
46 | this is a specific quantile at which to report results, e.g.,
47 | \code{ret_quantile = 0.5} will return that the qte at the median.}
48 |
49 | \item{biters}{number of bootstrap iterations; default is 100}
50 |
51 | \item{cl}{number of clusters to be used when bootstrapping; default is 1}
52 |
53 | \item{...}{additional arguments}
54 | }
55 | \value{
56 | \code{pte_params} object
57 | }
58 | \description{
59 | This is a lightweight (example) function for how to setup
60 | the data to be used in the \code{pte} package.
61 |
62 | \code{setup_pte_basic} takes in information about the structure of \code{data}
63 | and returns a \code{pte_params} object. The key piece of information
64 | that is computed by this function is the list of groups and list of
65 | time periods where ATT(g,t) should be computed. In particular, this function
66 | omits the never-treated group but includes all other groups and drops the first
67 | time period. This setup is basically geared towards the 2x2 case ---
68 | i.e., where ATT could be identified with two periods, a treated and
69 | untreated group, and the first period being pre-treatment for both groups.
70 | This is the relevant case for DID, but is also relevant for other cases as well.
71 | However, for example, if more pre-treatment periods were needed, then this
72 | function should be replaced by something else.
73 |
74 | For code that is written with the idea of being easy-to-use by other
75 | researchers, this is a good place to do some error handling / checking
76 | that the data is in the correct format, etc.
77 | }
78 |
--------------------------------------------------------------------------------
/docs/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /404.html
5 |
6 |
7 | /authors.html
8 |
9 |
10 | /index.html
11 |
12 |
13 | /reference/attgt_if.html
14 |
15 |
16 | /reference/attgt_noif.html
17 |
18 |
19 | /reference/attgt_pte_aggregations.html
20 |
21 |
22 | /reference/compute.pte.html
23 |
24 |
25 | /reference/compute.pte2.html
26 |
27 |
28 | /reference/did_attgt.html
29 |
30 |
31 | /reference/ggpte.html
32 |
33 |
34 | /reference/group_time_att.html
35 |
36 |
37 | /reference/gt_data_frame.html
38 |
39 |
40 | /reference/index.html
41 |
42 |
43 | /reference/mboot2.html
44 |
45 |
46 | /reference/orig2t.html
47 |
48 |
49 | /reference/panel_empirical_bootstrap.html
50 |
51 |
52 | /reference/print.group_time_att.html
53 |
54 |
55 | /reference/print.pte_results.html
56 |
57 |
58 | /reference/print.summary.pte_results.html
59 |
60 |
61 | /reference/process_att_gt.html
62 |
63 |
64 | /reference/pte.html
65 |
66 |
67 | /reference/pte2.html
68 |
69 |
70 | /reference/pte_aggte.html
71 |
72 |
73 | /reference/pte_attgt.html
74 |
75 |
76 | /reference/pte_default.html
77 |
78 |
79 | /reference/pte_emp_boot.html
80 |
81 |
82 | /reference/pte_params.html
83 |
84 |
85 | /reference/pte_results.html
86 |
87 |
88 | /reference/qott_pte_aggregations.html
89 |
90 |
91 | /reference/qtt_pte_aggregations.html
92 |
93 |
94 | /reference/setup_pte.html
95 |
96 |
97 | /reference/setup_pte_basic.html
98 |
99 |
100 | /reference/summary.group_time_att.html
101 |
102 |
103 | /reference/summary.pte_emp_boot.html
104 |
105 |
106 | /reference/summary.pte_results.html
107 |
108 |
109 | /reference/t2orig.html
110 |
111 |
112 | /reference/two_by_two_subset.html
113 |
114 |
115 |
--------------------------------------------------------------------------------
/man/compute.pte.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/pte.R
3 | \name{compute.pte}
4 | \alias{compute.pte}
5 | \title{compute.pte}
6 | \usage{
7 | compute.pte(ptep, subset_fun, attgt_fun, ...)
8 | }
9 | \arguments{
10 | \item{ptep}{\code{pte_params} object}
11 |
12 | \item{subset_fun}{This is a function that should take in \code{data},
13 | \code{g} (for group), \code{tp} (for time period), and \code{...}
14 | and be able to return the appropriate \code{data.frame} that can be used
15 | by \code{attgt_fun} to produce ATT(g=g,t=tp). The data frame should
16 | be constructed using \code{gt_data_frame} in order to guarantee that
17 | it has the appropriate columns that identify which group an observation
18 | belongs to, etc.}
19 |
20 | \item{attgt_fun}{This is a function that should work in the case where
21 | there is a single group and the "right" number of time periods to
22 | recover an estimate of the ATT. For example, in the contest of
23 | difference in differences, it would need to work for a single group,
24 | find the appropriate comparison group (untreated units), find the right
25 | time periods (pre- and post-treatment), and then recover an estimate
26 | of ATT for that group. It will be called over and over separately
27 | by groups and by time periods to compute ATT(g,t)'s.
28 |
29 | The function needs to work in a very specific way. It should take in the
30 | arguments: \code{data}, \code{...}. \code{data} should be constructed
31 | using the function \code{gt_data_frame} which checks to make sure
32 | that \code{data} has the correct columns defined.
33 | \code{...} are additional arguments (such as
34 | formulas for covariates) that \code{attgt_fun} needs. From these arguments
35 | \code{attgt_fun} must return a list with element \code{ATT} containing the
36 | group-time average treatment effect for that group and that time period.
37 |
38 | If \code{attgt_fun} returns an influence function (which should be provided
39 | in a list element named \code{inf_func}), then the code will use the
40 | multiplier bootstrap to compute standard errors for group-time average
41 | treatment effects, an overall treatment effect parameter, and a dynamic
42 | treatment effect parameter (i.e., event study parameter). If
43 | \code{attgt_fun} does not return an influence function, then the same
44 | objects will be computed using the empirical bootstrap. This is usually
45 | (perhaps substantially) easier to code, but also will usually be (perhaps
46 | substantially) computationally slower.}
47 |
48 | \item{...}{extra arguments that can be passed to create the correct subsets
49 | of the data (depending on \code{subset_fun}), to estimate group time
50 | average treatment effects (depending on \code{attgt_fun}), or to
51 | aggregating treatment effects (particularly useful are \code{min_e},
52 | \code{max_e}, and \code{balance_e} arguments to event study aggregations)}
53 | }
54 | \value{
55 | list of attgt results and, sometimes, and influence function
56 | }
57 | \description{
58 | Function that actually computes panel treatment effects
59 | }
60 |
--------------------------------------------------------------------------------
/man/setup_pte.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/pte_params.R
3 | \name{setup_pte}
4 | \alias{setup_pte}
5 | \title{Setup panel treatment effects parameters}
6 | \usage{
7 | setup_pte(
8 | yname,
9 | gname,
10 | tname,
11 | idname,
12 | data,
13 | required_pre_periods = 1,
14 | anticipation = 0,
15 | base_period = "varying",
16 | cband = TRUE,
17 | alp = 0.05,
18 | boot_type = "multiplier",
19 | weightsname = NULL,
20 | gt_type = "att",
21 | ret_quantile = 0.5,
22 | biters = 100,
23 | cl = 1,
24 | ...
25 | )
26 | }
27 | \arguments{
28 | \item{yname}{Name of outcome in \code{data}}
29 |
30 | \item{gname}{Name of group in \code{data}}
31 |
32 | \item{tname}{Name of time period in \code{data}}
33 |
34 | \item{idname}{Name of id in \code{data}}
35 |
36 | \item{data}{balanced panel data}
37 |
38 | \item{required_pre_periods}{The number of required pre-treatment periods to implement
39 | the estimation strategy. Default is 1.}
40 |
41 | \item{anticipation}{how many periods before the treatment actually takes
42 | place that it can have an effect on outcomes}
43 |
44 | \item{base_period}{The type of base period to use. This only affects
45 | the numeric value of results in pre-treatment periods. Results in
46 | post-treatment periods are not affected by this choice. The default
47 | is "varying", where the base period will "back up" to the immediately
48 | preceding period in pre-treatment periods. The other option is "universal"
49 | where the base period is fixed in pre-treatment periods to be the period
50 | right before the treatment starts. "Universal" is commonly used in
51 | difference-in-differences applications, but can be unnatural for other
52 | identification strategies.}
53 |
54 | \item{cband}{whether or not to report a uniform (instead of pointwise)
55 | confidence band (default is TRUE)}
56 |
57 | \item{alp}{significance level; default is 0.05}
58 |
59 | \item{boot_type}{which type of bootstrap to use}
60 |
61 | \item{weightsname}{The name of the column that contains sampling weights.
62 | The defaul is NULL, in which case no sampling weights are used.}
63 |
64 | \item{gt_type}{which type of group-time effects are computed.
65 | The default is "att". Different estimation strategies can implement
66 | their own choices for \code{gt_type}}
67 |
68 | \item{ret_quantile}{For functions that compute quantile treatment effects,
69 | this is a specific quantile at which to report results, e.g.,
70 | \code{ret_quantile = 0.5} will return that the qte at the median.}
71 |
72 | \item{biters}{number of bootstrap iterations; default is 100}
73 |
74 | \item{cl}{number of clusters to be used when bootstrapping; default is 1}
75 |
76 | \item{...}{additional arguments}
77 | }
78 | \value{
79 | \code{pte_params} object
80 | }
81 | \description{
82 | This is a function for how to setup
83 | the data to be used in the \code{pte} package.
84 |
85 | The \code{setup_pte} function builds on \code{setup_pte_basic} and
86 | attempts to provide a general purpose function (with error handling)
87 | to arrange the data in a way that can be processed by \code{subset_fun}
88 | and \code{attgt_fun} in the next steps.
89 | }
90 |
--------------------------------------------------------------------------------
/man/compute.pte2.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/pte.R
3 | \name{compute.pte2}
4 | \alias{compute.pte2}
5 | \title{compute.pte2}
6 | \usage{
7 | compute.pte2(ptep, subset_fun, attgt_fun, ...)
8 | }
9 | \arguments{
10 | \item{ptep}{\code{pte_params} object}
11 |
12 | \item{subset_fun}{This is a function that should take in \code{data},
13 | \code{g} (for group), \code{tp} (for time period), and \code{...}
14 | and be able to return the appropriate \code{data.frame} that can be used
15 | by \code{attgt_fun} to produce ATT(g=g,t=tp). The data frame should
16 | be constructed using \code{gt_data_frame} in order to guarantee that
17 | it has the appropriate columns that identify which group an observation
18 | belongs to, etc.}
19 |
20 | \item{attgt_fun}{This is a function that should work in the case where
21 | there is a single group and the "right" number of time periods to
22 | recover an estimate of the ATT. For example, in the contest of
23 | difference in differences, it would need to work for a single group,
24 | find the appropriate comparison group (untreated units), find the right
25 | time periods (pre- and post-treatment), and then recover an estimate
26 | of ATT for that group. It will be called over and over separately
27 | by groups and by time periods to compute ATT(g,t)'s.
28 |
29 | The function needs to work in a very specific way. It should take in the
30 | arguments: \code{data}, \code{...}. \code{data} should be constructed
31 | using the function \code{gt_data_frame} which checks to make sure
32 | that \code{data} has the correct columns defined.
33 | \code{...} are additional arguments (such as
34 | formulas for covariates) that \code{attgt_fun} needs. From these arguments
35 | \code{attgt_fun} must return a list with element \code{ATT} containing the
36 | group-time average treatment effect for that group and that time period.
37 |
38 | If \code{attgt_fun} returns an influence function (which should be provided
39 | in a list element named \code{inf_func}), then the code will use the
40 | multiplier bootstrap to compute standard errors for group-time average
41 | treatment effects, an overall treatment effect parameter, and a dynamic
42 | treatment effect parameter (i.e., event study parameter). If
43 | \code{attgt_fun} does not return an influence function, then the same
44 | objects will be computed using the empirical bootstrap. This is usually
45 | (perhaps substantially) easier to code, but also will usually be (perhaps
46 | substantially) computationally slower.}
47 |
48 | \item{...}{extra arguments that can be passed to create the correct subsets
49 | of the data (depending on \code{subset_fun}), to estimate group time
50 | average treatment effects (depending on \code{attgt_fun}), or to
51 | aggregating treatment effects (particularly useful are \code{min_e},
52 | \code{max_e}, and \code{balance_e} arguments to event study aggregations)}
53 | }
54 | \value{
55 | list of attgt results and, sometimes, an influence function
56 | }
57 | \description{
58 | Function that actually computes panel treatment effects.
59 | The difference relative to \code{compute.pte} is that this function
60 | loops over time periods first (instead of groups) and tries to
61 | estimate model for untreated potential outcomes jointly for all groups.
62 | }
63 |
--------------------------------------------------------------------------------
/docs/pkgdown.js:
--------------------------------------------------------------------------------
1 | /* http://gregfranko.com/blog/jquery-best-practices/ */
2 | (function($) {
3 | $(function() {
4 |
5 | $('.navbar-fixed-top').headroom();
6 |
7 | $('body').css('padding-top', $('.navbar').height() + 10);
8 | $(window).resize(function(){
9 | $('body').css('padding-top', $('.navbar').height() + 10);
10 | });
11 |
12 | $('[data-toggle="tooltip"]').tooltip();
13 |
14 | var cur_path = paths(location.pathname);
15 | var links = $("#navbar ul li a");
16 | var max_length = -1;
17 | var pos = -1;
18 | for (var i = 0; i < links.length; i++) {
19 | if (links[i].getAttribute("href") === "#")
20 | continue;
21 | // Ignore external links
22 | if (links[i].host !== location.host)
23 | continue;
24 |
25 | var nav_path = paths(links[i].pathname);
26 |
27 | var length = prefix_length(nav_path, cur_path);
28 | if (length > max_length) {
29 | max_length = length;
30 | pos = i;
31 | }
32 | }
33 |
34 | // Add class to parent
, and enclosing
if in dropdown
35 | if (pos >= 0) {
36 | var menu_anchor = $(links[pos]);
37 | menu_anchor.parent().addClass("active");
38 | menu_anchor.closest("li.dropdown").addClass("active");
39 | }
40 | });
41 |
42 | function paths(pathname) {
43 | var pieces = pathname.split("/");
44 | pieces.shift(); // always starts with /
45 |
46 | var end = pieces[pieces.length - 1];
47 | if (end === "index.html" || end === "")
48 | pieces.pop();
49 | return(pieces);
50 | }
51 |
52 | // Returns -1 if not found
53 | function prefix_length(needle, haystack) {
54 | if (needle.length > haystack.length)
55 | return(-1);
56 |
57 | // Special case for length-0 haystack, since for loop won't run
58 | if (haystack.length === 0) {
59 | return(needle.length === 0 ? 0 : -1);
60 | }
61 |
62 | for (var i = 0; i < haystack.length; i++) {
63 | if (needle[i] != haystack[i])
64 | return(i);
65 | }
66 |
67 | return(haystack.length);
68 | }
69 |
70 | /* Clipboard --------------------------*/
71 |
72 | function changeTooltipMessage(element, msg) {
73 | var tooltipOriginalTitle=element.getAttribute('data-original-title');
74 | element.setAttribute('data-original-title', msg);
75 | $(element).tooltip('show');
76 | element.setAttribute('data-original-title', tooltipOriginalTitle);
77 | }
78 |
79 | if(ClipboardJS.isSupported()) {
80 | $(document).ready(function() {
81 | var copyButton = "";
82 |
83 | $("div.sourceCode").addClass("hasCopyButton");
84 |
85 | // Insert copy buttons:
86 | $(copyButton).prependTo(".hasCopyButton");
87 |
88 | // Initialize tooltips:
89 | $('.btn-copy-ex').tooltip({container: 'body'});
90 |
91 | // Initialize clipboard:
92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', {
93 | text: function(trigger) {
94 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, "");
95 | }
96 | });
97 |
98 | clipboardBtnCopies.on('success', function(e) {
99 | changeTooltipMessage(e.trigger, 'Copied!');
100 | e.clearSelection();
101 | });
102 |
103 | clipboardBtnCopies.on('error', function() {
104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy');
105 | });
106 | });
107 | }
108 | })(window.jQuery || window.$)
109 |
--------------------------------------------------------------------------------
/man/pte_params.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/pte_params.R
3 | \name{pte_params}
4 | \alias{pte_params}
5 | \title{pte_params}
6 | \usage{
7 | pte_params(
8 | yname,
9 | gname,
10 | tname,
11 | idname,
12 | data,
13 | glist,
14 | tlist,
15 | cband,
16 | alp,
17 | boot_type,
18 | anticipation = NULL,
19 | base_period = NULL,
20 | weightsname = NULL,
21 | control_group = "notyettreated",
22 | gt_type = "att",
23 | ret_quantile = 0.5,
24 | global_fun = FALSE,
25 | time_period_fun = FALSE,
26 | group_fun = FALSE,
27 | biters,
28 | cl
29 | )
30 | }
31 | \arguments{
32 | \item{yname}{Name of outcome in \code{data}}
33 |
34 | \item{gname}{Name of group in \code{data}}
35 |
36 | \item{tname}{Name of time period in \code{data}}
37 |
38 | \item{idname}{Name of id in \code{data}}
39 |
40 | \item{data}{balanced panel data}
41 |
42 | \item{glist}{list of groups to create group-time average treatment effects
43 | for}
44 |
45 | \item{tlist}{list of time periods to create group-time average treatment
46 | effects for}
47 |
48 | \item{cband}{whether or not to report a uniform (instead of pointwise)
49 | confidence band (default is TRUE)}
50 |
51 | \item{alp}{significance level; default is 0.05}
52 |
53 | \item{boot_type}{which type of bootstrap to use}
54 |
55 | \item{anticipation}{how many periods before the treatment actually takes
56 | place that it can have an effect on outcomes}
57 |
58 | \item{base_period}{The type of base period to use. This only affects
59 | the numeric value of results in pre-treatment periods. Results in
60 | post-treatment periods are not affected by this choice. The default
61 | is "varying", where the base period will "back up" to the immediately
62 | preceding period in pre-treatment periods. The other option is "universal"
63 | where the base period is fixed in pre-treatment periods to be the period
64 | right before the treatment starts. "Universal" is commonly used in
65 | difference-in-differences applications, but can be unnatural for other
66 | identification strategies.}
67 |
68 | \item{weightsname}{The name of the column that contains sampling weights.
69 | The defaul is NULL, in which case no sampling weights are used.}
70 |
71 | \item{control_group}{Which group is used as the comparison group.
72 | The default choice is "notyettreated", but
73 | different estimation strategies can implement their own choices
74 | for the control group}
75 |
76 | \item{gt_type}{which type of group-time effects are computed.
77 | The default is "att". Different estimation strategies can implement
78 | their own choices for \code{gt_type}}
79 |
80 | \item{ret_quantile}{For functions that compute quantile treatment effects,
81 | this is a specific quantile at which to report results, e.g.,
82 | \code{ret_quantile = 0.5} will return that the qte at the median.}
83 |
84 | \item{global_fun}{Logical indicating whether or not untreated potential
85 | outcomes can be estimated in one shot, i.e., for all groups and time periods.
86 | Main use case would be for one-shot imputation estimators. Not supported yet.}
87 |
88 | \item{time_period_fun}{Logical indicating whether or not untreated potential
89 | outcomes can be estimated for all groups in the same time period. Not supported yet.}
90 |
91 | \item{group_fun}{Logical indicating whether or not untreated potential outcomes
92 | can be estimated for all time periods for a single group. Not supported yet.
93 | These functions aim at reducing or eliminating running the same code multiple times.}
94 |
95 | \item{biters}{number of bootstrap iterations; default is 100}
96 |
97 | \item{cl}{number of clusters to be used when bootstrapping; default is 1}
98 | }
99 | \description{
100 | Objects that contain pte parameters
101 | }
102 |
--------------------------------------------------------------------------------
/man/pte_default.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/pte.R
3 | \name{pte_default}
4 | \alias{pte_default}
5 | \title{pte_default}
6 | \usage{
7 | pte_default(
8 | yname,
9 | gname,
10 | tname,
11 | idname,
12 | data,
13 | xformla = ~1,
14 | d_outcome = FALSE,
15 | d_covs_formula = ~-1,
16 | lagged_outcome_cov = FALSE,
17 | est_method = "dr",
18 | anticipation = 0,
19 | base_period = "varying",
20 | control_group = "notyettreated",
21 | weightsname = NULL,
22 | cband = TRUE,
23 | alp = 0.05,
24 | boot_type = "multiplier",
25 | biters = 100,
26 | cl = 1
27 | )
28 | }
29 | \arguments{
30 | \item{yname}{Name of outcome in \code{data}}
31 |
32 | \item{gname}{Name of group in \code{data}}
33 |
34 | \item{tname}{Name of time period in \code{data}}
35 |
36 | \item{idname}{Name of id in \code{data}}
37 |
38 | \item{data}{balanced panel data}
39 |
40 | \item{xformla}{one-sided formula for covariates used in the propensity score
41 | and outcome regression models}
42 |
43 | \item{d_outcome}{Whether or not to take the first difference of the outcome.
44 | The default is FALSE. To use difference-in-differences, set this to be TRUE.}
45 |
46 | \item{d_covs_formula}{A formula for time varying covariates to enter the
47 | first estimation step models. The default is not to include any, and, hence,
48 | to only include pre-treatment covariats.}
49 |
50 | \item{lagged_outcome_cov}{Whether to include the lagged outcome as a covariate.
51 | Default is FALSE.}
52 |
53 | \item{est_method}{Which type of estimation method to use. Default is "dr" for
54 | doubly robust. The other option is "reg" for regression adjustment.}
55 |
56 | \item{anticipation}{how many periods before the treatment actually takes
57 | place that it can have an effect on outcomes}
58 |
59 | \item{base_period}{The type of base period to use. This only affects
60 | the numeric value of results in pre-treatment periods. Results in
61 | post-treatment periods are not affected by this choice. The default
62 | is "varying", where the base period will "back up" to the immediately
63 | preceding period in pre-treatment periods. The other option is "universal"
64 | where the base period is fixed in pre-treatment periods to be the period
65 | right before the treatment starts. "Universal" is commonly used in
66 | difference-in-differences applications, but can be unnatural for other
67 | identification strategies.}
68 |
69 | \item{control_group}{Which group is used as the comparison group.
70 | The default choice is "notyettreated", but
71 | different estimation strategies can implement their own choices
72 | for the control group}
73 |
74 | \item{weightsname}{The name of the column that contains sampling weights.
75 | The defaul is NULL, in which case no sampling weights are used.}
76 |
77 | \item{cband}{whether or not to report a uniform (instead of pointwise)
78 | confidence band (default is TRUE)}
79 |
80 | \item{alp}{significance level; default is 0.05}
81 |
82 | \item{boot_type}{should be one of "multiplier" (the default) or "empirical".
83 | The multiplier bootstrap is generally much faster, but \code{attgt_fun} needs
84 | to provide an expression for the influence function (which could be challenging
85 | to figure out). If no influence function is provided, then the \code{pte}
86 | package will use the empirical bootstrap no matter what the value of this
87 | parameter.}
88 |
89 | \item{biters}{number of bootstrap iterations; default is 100}
90 |
91 | \item{cl}{number of clusters to be used when bootstrapping; default is 1}
92 | }
93 | \value{
94 | \code{pte_results} object
95 | }
96 | \description{
97 | This is a generic/example wrapper for a call to the \code{pte} function.
98 |
99 | This function provides access to difference-in-differences and unconfoundedness
100 | based identification/estimation strategies given (i) panel data and (ii)
101 | staggered treatment adoption
102 | }
103 |
--------------------------------------------------------------------------------
/tests/testthat/test-did.R:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------------------
2 | # Some tests for `did`
3 | #------------------------------------------------------------------------
4 |
5 | library(did)
6 |
7 | test_that("did basics", {
8 | sp <- did::reset.sim()
9 | data <- did::build_sim_dataset(sp)
10 |
11 | res <- pte(yname="Y",
12 | gname="G",
13 | tname="period",
14 | idname="id",
15 | data=data,
16 | setup_pte_fun=setup_pte,
17 | subset_fun=two_by_two_subset,
18 | attgt_fun=did_attgt,
19 | xformla=~X)
20 |
21 | expect_equal(res$overall_att$overall.att, 1, tolerance=.5)
22 | dyn_idx <- res$event_study$egt == 0
23 | expect_equal(res$event_study$att.egt[dyn_idx], 1, tolerance=0.5)
24 |
25 | # compare to results from did package
26 | cs_res <- did::att_gt(yname="Y",
27 | gname="G",
28 | tname="period",
29 | idname="id",
30 | data=data,
31 | xformla=~X)
32 |
33 | cs_overall <- did::aggte(cs_res, type="group")$overall.att
34 | expect_equal(res$overall_att$overall.att, cs_overall)
35 | cs_dyn <- did::aggte(cs_res, type="dynamic")$att.egt[dyn_idx]
36 | expect_equal(res$event_study$att.egt[dyn_idx], cs_dyn)
37 | c})
38 |
39 | test_that("empirical bootstrap", {
40 | sp <- did::reset.sim()
41 | data <- did::build_sim_dataset(sp)
42 |
43 | res <- pte(yname="Y",
44 | gname="G",
45 | tname="period",
46 | idname="id",
47 | data=data,
48 | setup_pte_fun=setup_pte,
49 | subset_fun=two_by_two_subset,
50 | attgt_fun=did_attgt,
51 | xformla=~X,
52 | boot_type="empirical",
53 | biters=10) # just checking that this runs
54 |
55 | expect_equal(res$overall_att$overall.att, 1)
56 | message("this is failing because the names are not correct on the returns
57 | for the empirical bootstrap case")
58 | })
59 |
60 | test_that("periods that look like years works ok and unbalanced groups", {
61 | data(mpdta)
62 | res <- pte(
63 | yname = "lemp",
64 | gname = "first.treat",
65 | tname = "year",
66 | idname = "countyreal",
67 | data = mpdta,
68 | setup_pte_fun = setup_pte,
69 | subset_fun = two_by_two_subset,
70 | attgt_fun = did_attgt,
71 | xformla = ~ lpop
72 | )
73 | # this is to test if summary is working // had issues with ife version of this
74 | expect_equal(summary(res)$overall_att$overall_att,-0.0323)
75 | dyn_idx <- summary(res)$event_study[, "Event Time"] == 0
76 | expect_equal(summary(res)$event_study$Estimat[dyn_idx],-0.0201)
77 |
78 | #------------------------------------------------------------------------
79 | # case where the group variable is named G
80 | #------------------------------------------------------------------------
81 | data(mpdta)
82 | mpdta$G <- mpdta$first.treat
83 | res <- pte(
84 | yname = "lemp",
85 | gname = "G",
86 | tname = "year",
87 | idname = "countyreal",
88 | data = mpdta,
89 | setup_pte_fun = setup_pte,
90 | subset_fun = two_by_two_subset,
91 | attgt_fun = did_attgt,
92 | xformla = ~ lpop
93 | )
94 | # this is to test if summary is working // had issues with ife version of this
95 | expect_equal(summary(res)$overall_att$overall_att,-0.0323)
96 | dyn_idx <- summary(res)$event_study[, "Event Time"] == 0
97 | expect_equal(summary(res)$event_study$Estimat[dyn_idx],-0.0201)
98 | })
99 |
100 | test_that("no formula for covariates is ok", {
101 | sp <- did::reset.sim()
102 | data <- did::build_sim_dataset(sp)
103 |
104 | res <- pte(yname="Y",
105 | gname="G",
106 | tname="period",
107 | idname="id",
108 | data=data,
109 | setup_pte_fun=setup_pte,
110 | subset_fun=two_by_two_subset,
111 | attgt_fun=did_attgt)
112 |
113 | expect_equal(res$overall_att$overall.att, 1, tolerance=.5)
114 | })
--------------------------------------------------------------------------------
/docs/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Page not found (404) • pte
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
67 |
68 | Content not found. Please use links in the navbar.
69 |
70 |
71 |
72 |
73 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/man/panel_empirical_bootstrap.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/empirical_bootstrap.R
3 | \name{panel_empirical_bootstrap}
4 | \alias{panel_empirical_bootstrap}
5 | \title{panel_empirical_bootstrap}
6 | \usage{
7 | panel_empirical_bootstrap(
8 | attgt.list,
9 | ptep,
10 | setup_pte_fun,
11 | subset_fun,
12 | attgt_fun,
13 | extra_gt_returns,
14 | ...
15 | )
16 | }
17 | \arguments{
18 | \item{attgt.list}{list of attgt results from \code{compute.pte}}
19 |
20 | \item{ptep}{\code{pte_params} object}
21 |
22 | \item{setup_pte_fun}{This is a function that should take in \code{data},
23 | \code{yname} (the name of the outcome variable in \code{data}),
24 | \code{gname} (the name of the group variable),
25 | \code{idname} (the name of the id variable),
26 | and possibly other arguments such as the significance level \code{alp},
27 | the number of bootstrap iterations \code{biters}, and how many clusters
28 | for parallel computing in the bootstrap \code{cl}. The key thing that
29 | needs to be figured out in this function is which groups and time periods
30 | ATT(g,t) should be computed in. The function should
31 | return a \code{pte_params} object which contains all of the parameters
32 | passed into the function as well as \code{glist} and \code{tlist} which
33 | should be ordered lists of groups and time periods for ATT(g,t) to be computed.
34 |
35 | This function provides also provides a good place for error handling related
36 | to the types of data that can be handled.
37 |
38 | The \code{pte} package contains the function \code{setup_pte} that is
39 | a lightweight function that basically just takes the data, omits
40 | the never-treated group from \code{glist} but includes all other groups
41 | and drops the first time period. This works in cases where ATT would
42 | be identified in the 2x2 case (i.e., where there are two time periods,
43 | no units are treated in the first period and the identification strategy
44 | "works" with access to a treated and untreated group and untreated
45 | potential outcomes for both groups in the first period) --- for example,
46 | this approach works if DID is the identification strategy.}
47 |
48 | \item{subset_fun}{This is a function that should take in \code{data},
49 | \code{g} (for group), \code{tp} (for time period), and \code{...}
50 | and be able to return the appropriate \code{data.frame} that can be used
51 | by \code{attgt_fun} to produce ATT(g=g,t=tp). The data frame should
52 | be constructed using \code{gt_data_frame} in order to guarantee that
53 | it has the appropriate columns that identify which group an observation
54 | belongs to, etc.}
55 |
56 | \item{attgt_fun}{This is a function that should work in the case where
57 | there is a single group and the "right" number of time periods to
58 | recover an estimate of the ATT. For example, in the contest of
59 | difference in differences, it would need to work for a single group,
60 | find the appropriate comparison group (untreated units), find the right
61 | time periods (pre- and post-treatment), and then recover an estimate
62 | of ATT for that group. It will be called over and over separately
63 | by groups and by time periods to compute ATT(g,t)'s.
64 |
65 | The function needs to work in a very specific way. It should take in the
66 | arguments: \code{data}, \code{...}. \code{data} should be constructed
67 | using the function \code{gt_data_frame} which checks to make sure
68 | that \code{data} has the correct columns defined.
69 | \code{...} are additional arguments (such as
70 | formulas for covariates) that \code{attgt_fun} needs. From these arguments
71 | \code{attgt_fun} must return a list with element \code{ATT} containing the
72 | group-time average treatment effect for that group and that time period.
73 |
74 | If \code{attgt_fun} returns an influence function (which should be provided
75 | in a list element named \code{inf_func}), then the code will use the
76 | multiplier bootstrap to compute standard errors for group-time average
77 | treatment effects, an overall treatment effect parameter, and a dynamic
78 | treatment effect parameter (i.e., event study parameter). If
79 | \code{attgt_fun} does not return an influence function, then the same
80 | objects will be computed using the empirical bootstrap. This is usually
81 | (perhaps substantially) easier to code, but also will usually be (perhaps
82 | substantially) computationally slower.}
83 |
84 | \item{extra_gt_returns}{A place to return anything extra from particular
85 | group-time average treatment effect calculations. For DID, this might
86 | be something like propensity score estimates, regressions of untreated
87 | potential outcomes on covariates. For ife, this could be something
88 | like the first step regression 2sls estimates. This argument is also
89 | potentially useful for debugging.}
90 |
91 | \item{...}{extra arguments that can be passed to create the correct subsets
92 | of the data (depending on \code{subset_fun}), to estimate group time
93 | average treatment effects (depending on \code{attgt_fun}), or to
94 | aggregating treatment effects (particularly useful are \code{min_e},
95 | \code{max_e}, and \code{balance_e} arguments to event study aggregations)}
96 | }
97 | \value{
98 | \code{pte_emp_boot} object
99 | }
100 | \description{
101 | Computes empirical bootstrap pointwise standard errors
102 | }
103 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 | (function() {
6 | 'use strict';
7 |
8 | window.Toc = {
9 | helpers: {
10 | // return all matching elements in the set, or their descendants
11 | findOrFilter: function($el, selector) {
12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
13 | // http://stackoverflow.com/a/12731439/358804
14 | var $descendants = $el.find(selector);
15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])');
16 | },
17 |
18 | generateUniqueIdBase: function(el) {
19 | var text = $(el).text();
20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-');
21 | return anchor || el.tagName.toLowerCase();
22 | },
23 |
24 | generateUniqueId: function(el) {
25 | var anchorBase = this.generateUniqueIdBase(el);
26 | for (var i = 0; ; i++) {
27 | var anchor = anchorBase;
28 | if (i > 0) {
29 | // add suffix
30 | anchor += '-' + i;
31 | }
32 | // check if ID already exists
33 | if (!document.getElementById(anchor)) {
34 | return anchor;
35 | }
36 | }
37 | },
38 |
39 | generateAnchor: function(el) {
40 | if (el.id) {
41 | return el.id;
42 | } else {
43 | var anchor = this.generateUniqueId(el);
44 | el.id = anchor;
45 | return anchor;
46 | }
47 | },
48 |
49 | createNavList: function() {
50 | return $('
function to take in a data.frame, check if it has the right
52 | columns to be used to calculate a group-time average treatment effect,
53 | and sets the class of the data.frame to include gt_data_frame
54 |
55 |
56 |
57 |
gt_data_frame(data)
58 |
59 |
60 |
61 |
Arguments
62 |
data
63 |
data that will be checked to see if has right format for
64 | computing group-time average treatment effects
A helper function to switch from original time periods to
53 | "new" time periods (which are just time periods going from 1 to total
54 | number of available periods). This allows for periods not being
55 | exactly spaced apart by 1.
56 |
57 |
58 |
59 |
orig2t(orig, original_time.periods)
60 |
61 |
62 |
63 |
Arguments
64 |
original_time.periods
65 |
vector containing all original time periods.
66 |
67 |
68 |
69 |
Value
70 |
71 |
72 |
new time period converted from original time period
Class for holding group-time average treatment effects
51 | which don't include influence functions
52 |
53 |
54 |
55 |
attgt_noif(attgt, extra_gt_returns =NULL)
56 |
57 |
58 |
59 |
Arguments
60 |
attgt
61 |
group-time average treatment effect
62 |
63 |
64 |
extra_gt_returns
65 |
A place to return anything extra from particular
66 | group-time average treatment effect calculations. For DID, this might
67 | be something like propensity score estimates, regressions of untreated
68 | potential outcomes on covariates. For ife, this could be something
69 | like the first step regression 2sls estimates. This argument is also
70 | potentially useful for debugging.
Aggregate group-time average treatment effects into
53 | overall, group, and dynamic effects. This function is only used
54 | for (i) computing standard errors using the empirical bootstrap,
55 | and (ii) combining distributions at the (g,t) level
56 |
57 |
58 |
59 |
attgt_pte_aggregations(attgt.list, ptep)
60 |
61 |
62 |
63 |
Arguments
64 |
attgt.list
65 |
list of attgt results from compute.pte
66 |
67 |
68 |
ptep
69 |
pte_params object
70 |
71 |
72 |
73 |
Value
74 |
75 |
76 |
pte_emp_boot object
77 |
78 |
79 |
80 |
81 |
83 |
84 |
85 |
86 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/R/subset_functions.R:
--------------------------------------------------------------------------------
1 | #' @title two_by_two_subset
2 | #'
3 | #' @description A function for computing a 2x2 subset of original data.
4 | #' This is the subset with post treatment periods separately for the
5 | #' treated group and comparison group and pre-treatment periods in the period
6 | #' immediately before the treated group became treated.
7 | #'
8 | #' @inheritParams pte_params
9 | #'
10 | #' @param data the full dataset
11 | #' @param g the current group
12 | #' @param tp the current time period
13 | #' @param control_group whether to use "notyettreated" (default) or
14 | #' "nevertreated"
15 | #' @param anticipation the number of periods of anticipation (i.e., number
16 | #' of periods before the treatment happens where the treatment can "already"
17 | #' affect the outcome)
18 | #' @param ... extra arguments to get the subset correct
19 | #'
20 | #' @return list that contains correct subset of data, \code{n1}
21 | #' number of observations
22 | #' in this subset, and \code{disidx} a vector of the correct ids for this
23 | #' subset.
24 | #'
25 | #' @export
26 | two_by_two_subset <- function(data,
27 | g,
28 | tp,
29 | control_group = "notyettreated",
30 | anticipation = 0,
31 | base_period = "varying",
32 | ...) {
33 | # get the correct "base" period for this group
34 | main.base.period <- g - anticipation - 1
35 |
36 | #----------------------------------------------------
37 | if (base_period == "varying") {
38 | # if it's a pre-treatment time period (used for the
39 | # pre-test, we need to adjust the base period)
40 |
41 | # group not treated yet
42 | if (tp < (g - anticipation)) {
43 | # move to earlier period
44 | # not going to include anticipation here
45 | base.period <- tp - 1
46 | } else {
47 | # this is a post-treatment period
48 | base.period <- main.base.period
49 | }
50 | } else {
51 | base.period <- main.base.period
52 | }
53 | #----------------------------------------------------
54 |
55 | #----------------------------------------------------
56 | # collect the right subset of the data
57 |
58 | # get group g and not-yet-treated group
59 | if (control_group == "notyettreated") {
60 | this.data <- subset(data, G == g | G > tp | G == 0)
61 | } else {
62 | # use never treated group
63 | this.data <- subset(data, G == g | G == 0)
64 | }
65 |
66 | # get current period and base period data
67 | this.data <- subset(this.data, period == tp | period == base.period)
68 |
69 | # variable to keep track of pre/post periods
70 | this.data$name <- ifelse(this.data$period == tp, "post", "pre")
71 |
72 | # variable to indicate local treatment status
73 | this.data$D <- 1 * (this.data$G == g)
74 |
75 | # make this.data into gt_data_frame object
76 | this.data <- gt_data_frame(this.data)
77 |
78 | # number of observations used for this (g,t)
79 | n1 <- length(unique(this.data$id))
80 | disidx <- unique(data$id) %in% unique(this.data$id)
81 |
82 | list(gt_data = this.data, n1 = n1, disidx = disidx)
83 | }
84 |
85 |
86 | #' @title keep_all_untreated_subset
87 | #'
88 | #' @description A function that takes an original data set and keeps all
89 | #' pre-treatment data for all groups. For group g, it also includes data
90 | #' for the current period.
91 | #'
92 | #' Also, note that if `tp` is still a pre-treatment period for group g,
93 | #' then periods after `tp` will also be dropped for group g. This is a
94 | #' design choice and is useful especially for estimating placebo
95 | #' group-time average treatment effects in pre-treatment periods.
96 | #'
97 | #' A main use case for this function is to compute ATT(g,t)'s using a global
98 | #' estimation strategy such as imputation in Gardner (2022).
99 | #'
100 | #' @inheritParams two_by_two_subset
101 | #'
102 | #' @return all data but in correct format for computing ATT(g,t)
103 | #'
104 | #' @export
105 | keep_all_untreated_subset <- function(data, g, tp, ...) {
106 | # drop post-treatment observations that are not in group g
107 | # this creates the same sort of unbalanced panel data set
108 | # used in imputation papers.
109 | data$.treat <- 1 * ((data$G <= data$period) & (data$G != 0))
110 | this.data <- subset(data, (.treat == 0) | (G == g))
111 |
112 | # This line drops any periods after the "current" period too (even
113 | # if these are untreated) for group g.
114 | # This is to deal with pre-treatment periods
115 | # where it seems ambiguous/confusing what exactly to do and rules
116 | # out that later periods will be used to estimate the model for untreated
117 | # potential outcomes using group g.
118 | this.data <- subset(this.data, !(G == g & period > tp))
119 |
120 | # variable to keep track of pre/post periods
121 | this.data$name <- ifelse(this.data$period == tp, "post", "pre")
122 |
123 | this.data$D <- 1 * ((this.data$G == g) & this.data$period >= tp)
124 | n1 <- length(unique(this.data$id))
125 | disidx <- unique(data$id) %in% unique(this.data$id)
126 |
127 | list(gt_data = this.data, n1 = n1, disidx = disidx)
128 | }
129 |
130 |
131 | #' @title keep_all_pretreatment_subset
132 | #'
133 | #' @description A function that takes an original data set and keeps all
134 | #' data for all groups that are not-yet-treated by period `tp` as well
135 | #' as for group `g`.
136 | #'
137 | #' In particular, this keeps more data than functions like `two_by_two`
138 | #' subset that use a fixed base period.
139 | #'
140 | #' A main use case for this function is the interactive fixed effects approach
141 | #' proposed in Callaway and Tsyawo (2023).
142 | #'
143 | #' @inheritParams two_by_two_subset
144 | #' @param ... additional arguments
145 | #'
146 | #' @return all data but in correct format for computing ATT(g,t)
147 | #'
148 | #' @export
149 | keep_all_pretreatment_subset <- function(data, g, tp, ...) {
150 | this.data <- subset(data, period <= tp)
151 | # keep group g, not-yet-treated groups, and never-treated group
152 | this.data <- subset(this.data, (G == g) | (G > tp) | (G == 0))
153 |
154 | # variable to keep track of pre/post periods
155 | this.data$name <- ifelse(this.data$period == tp, "post", "pre")
156 |
157 | this.data$D <- 1 * ((this.data$G == g) & this.data$period >= tp)
158 | n1 <- length(unique(this.data$id))
159 | disidx <- unique(data$id) %in% unique(this.data$id)
160 |
161 | list(gt_data = this.data, n1 = n1, disidx = disidx)
162 | }
163 |
--------------------------------------------------------------------------------
/docs/reference/attgt_if.html:
--------------------------------------------------------------------------------
1 |
2 | attgt_if — attgt_if • pte
7 |
8 |
9 |
Class for holding group-time average treatment effects
51 | along with their influence function
52 |
53 |
54 |
55 |
attgt_if(attgt, inf_func, extra_gt_returns =NULL)
56 |
57 |
58 |
59 |
Arguments
60 |
attgt
61 |
group-time average treatment effect
62 |
63 |
64 |
inf_func
65 |
influence function
66 |
67 |
68 |
extra_gt_returns
69 |
A place to return anything extra from particular
70 | group-time average treatment effect calculations. For DID, this might
71 | be something like propensity score estimates, regressions of untreated
72 | potential outcomes on covariates. For ife, this could be something
73 | like the first step regression 2sls estimates. This argument is also
74 | potentially useful for debugging.
A function for computing a 2x2 subset of original data.
53 | This is the subset with post treatment periods separately for the
54 | treated group and comparison group and pre-treatment periods in the period
55 | immediately before the treated group became treated.