├── .DS_Store ├── .Rbuildignore ├── .github ├── .gitignore └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yaml │ ├── recheck.yml │ └── test-coverage.yaml ├── .gitignore ├── CRAN-SUBMISSION ├── DESCRIPTION ├── NAMESPACE ├── NEWS.md ├── R ├── CR-adjustments.R ├── S3-methods.R ├── Wald_test.R ├── clubSandwich.R ├── coef_test.R ├── conf_int.R ├── data-documentation.R ├── geeglm.R ├── get_arrays.R ├── glm.R ├── gls.R ├── ivreg.R ├── lm.R ├── lme.R ├── lmer.R ├── matrix-functions.R ├── mlm.R ├── plm.R ├── rma-mv.R ├── rma-uni.R ├── robu.R └── utilities.R ├── README.md ├── _pkgdown.yml ├── auxilliary ├── 3-level clustering with 2-level model.R ├── AngristLavy_AERdata │ ├── base00.dta │ ├── base01.dta │ ├── base02.dta │ ├── base99.dta │ └── readme.doc ├── BFC-question.R ├── Bediou question.R ├── Clustered IV Simulation Results.Rdata ├── Dropout Dataset for Tipton and Pustejovsky.sav ├── Ezetimibe trial data.csv ├── IV Simulation Results.Rdata ├── Kalaian-Raudenbush-1996.csv ├── Kalaian-Raudenbush-1996.txt ├── Multisite IV Simulation Results.Rdata ├── RB-IV.o463920 ├── STAR SUR example.R ├── Shores_test.R ├── Shores_test.dta ├── absorption issue - unweighted.R ├── absorption issue - weighted.R ├── analyze IV simulations.R ├── cluster-wild-bootstrap.Rmd ├── cluster-wild-bootstrap.html ├── deaths.dta ├── dropoutPrevention.csv ├── equivalence of robumeta and clubSandwich.R ├── es_data.RData ├── example for plm.R ├── harm.txt ├── iv example.R ├── iv simulation - cluster-level non-compliance.R ├── iv simulation - multi-site non-compliance.R ├── mice_pooling_example.R ├── prep Achievement Awards Demonstration data.R ├── prep Kalaian data.R ├── prep Wilson data.R ├── prep motor vehicle crash data.R ├── quasi-experiment example (simulated).R ├── quasi-experiment example.R ├── quasi-experiment.Rdata ├── run_clustered_iv_sim.bash ├── run_multisite_iv_sim.slurm ├── scratch.R ├── simulation_support_code.R ├── test_club_sandwich_and_CR.R ├── testing robumeta.R ├── two-sample-t-test.Rmd └── two-sample-t-test.html ├── clubSandwich.Rproj ├── codecov.yml ├── cran-comments.md ├── data ├── AchievementAwardsRCT.RData ├── MortalityRates.RData ├── SATcoaching.RData └── dropoutPrevention.RData ├── man ├── AchievementAwardsRCT.Rd ├── MortalityRates.Rd ├── SATcoaching.Rd ├── Wald_test.Rd ├── coef_test.Rd ├── conf_int.Rd ├── constraint_matrices.Rd ├── dropoutPrevention.Rd ├── findCluster.rma.mv.Rd ├── impute_covariance_matrix.Rd ├── linear_contrast.Rd ├── pattern_covariance_matrix.Rd ├── vcovCR.Rd ├── vcovCR.geeglm.Rd ├── vcovCR.glm.Rd ├── vcovCR.gls.Rd ├── vcovCR.ivreg.Rd ├── vcovCR.lm.Rd ├── vcovCR.lme.Rd ├── vcovCR.lmerMod.Rd ├── vcovCR.mlm.Rd ├── vcovCR.plm.Rd ├── vcovCR.rma.mv.Rd ├── vcovCR.rma.uni.Rd └── vcovCR.robu.Rd ├── paper_ClusterRobustTesting ├── AHT test.wmf ├── AIR AHT test.wmf ├── AIR standard test.wmf ├── BRL + Satt.wmf ├── CRVE_sims_table.xlsx ├── CRVE_sims_table_full.xlsx ├── CR_fig │ ├── absorption-1.pdf │ ├── absorption_005-1.pdf │ ├── absorption_005-1.png │ ├── absorption_01-1.pdf │ ├── absorption_01-1.png │ ├── absorption_05-1.pdf │ ├── absorption_05-1.png │ ├── absorption_10-1.pdf │ ├── absorption_10-1.png │ ├── balance-1.pdf │ ├── balance_005_15-1.pdf │ ├── balance_005_15-1.png │ ├── balance_005_30-1.pdf │ ├── balance_005_30-1.png │ ├── balance_005_50-1.pdf │ ├── balance_005_50-1.png │ ├── balance_01_15-1.pdf │ ├── balance_01_15-1.png │ ├── balance_01_30-1.pdf │ ├── balance_01_30-1.png │ ├── balance_01_50-1.pdf │ ├── balance_01_50-1.png │ ├── balance_05_15-1.pdf │ ├── balance_05_15-1.png │ ├── balance_05_30-1.pdf │ ├── balance_05_30-1.png │ ├── balance_05_50-1.pdf │ ├── balance_05_50-1.png │ ├── balance_10_15-1.pdf │ ├── balance_10_15-1.png │ ├── balance_10_30-1.pdf │ ├── balance_10_30-1.png │ ├── balance_10_50-1.pdf │ ├── balance_10_50-1.png │ ├── df-1.pdf │ ├── misspecification_005-1.pdf │ ├── misspecification_005-1.png │ ├── misspecification_01-1.pdf │ ├── misspecification_01-1.png │ ├── misspecification_05-1.pdf │ ├── misspecification_05-1.png │ ├── misspecification_10-1.pdf │ ├── misspecification_10-1.png │ ├── overview-1.pdf │ ├── overview_005-1.pdf │ ├── overview_005-1.png │ ├── overview_01-1.pdf │ ├── overview_01-1.png │ ├── overview_10-1.pdf │ └── overview_10-1.png ├── ClusterRobustTesting_FE_models.Rnw ├── ClusterRobustTesting_FE_models.bbl ├── ClusterRobustTesting_FE_models.pdf ├── ClusterRobustTesting_FE_models.tex ├── ClusterRobustTesting_FE_models_correction.Rmd ├── ClusterRobustTesting_FE_models_correction.aux ├── ClusterRobustTesting_FE_models_correction.out ├── ClusterRobustTesting_FE_models_correction.pdf ├── ClusterRobustTesting_FE_models_correction.tex ├── ClusterRobustTesting_FE_models_revised.Rmd ├── ClusterRobustTesting_FE_models_revised.aux ├── ClusterRobustTesting_FE_models_revised.out ├── ClusterRobustTesting_FE_models_revised.pdf ├── ClusterRobustTesting_FE_models_revised.tex ├── ClusterRobustTesting_FE_models_revised_files │ └── figure-latex │ │ └── fig2-1.pdf ├── ClusterRobustTesting_FE_models_revised_proofs.Rmd ├── ClusterRobustTesting_FE_models_revised_simulation_details.Rmd ├── ClusterRobustTesting_notes_and_variations-concordance.tex ├── ClusterRobustTesting_notes_and_variations.Rnw ├── ClusterRobustTesting_notes_and_variations.bbl ├── ClusterRobustTesting_notes_and_variations.log ├── ClusterRobustTesting_notes_and_variations.pdf ├── ClusterRobustTesting_notes_and_variations.synctex.gz ├── ClusterRobustTesting_notes_and_variations.tex ├── ClusterRobustTesting_supplementary_materials-concordance.tex ├── ClusterRobustTesting_supplementary_materials.Rnw ├── ClusterRobustTesting_supplementary_materials.bbl ├── ClusterRobustTesting_supplementary_materials.log ├── ClusterRobustTesting_supplementary_materials.pdf ├── ClusterRobustTesting_supplementary_materials.synctex.gz ├── ClusterRobustTesting_supplementary_materials.tex ├── ClusterRobustTesting_supplementary_materials.toc ├── ClusterRobustTesting_supplementary_materials_revised.Rmd ├── ClusterRobustTesting_supplementary_materials_revised.pdf ├── DID-note-concordance.tex ├── DID-note.Rnw ├── DID-note.bbl ├── DID-note.log ├── DID-note.pdf ├── DID-note.synctex.gz ├── DID-note.tex ├── JSM abstract.txt ├── R │ ├── Achievement-Awards-example.R │ ├── Angrist & Lavy additional analysis.R │ ├── DID example.R │ ├── MLDA-example.R │ ├── Numerical counter-example to Theorem 2.R │ ├── Panel simulation results.Rdata │ ├── STAR example.R │ ├── figures for AIR.R │ ├── figures for PRC.R │ ├── format results for figures.R │ ├── panel simulation analysis.R │ ├── panel simulation.R │ ├── panel_simulation_for_TACC.R │ ├── run_panel_simulation.slurm │ ├── test absorption.R │ └── unbalanced panel example.R ├── STAR example.Rnw ├── STAR_test_results.Rdata ├── Simulation Plan.docx ├── abstract.txt ├── agsm.bst ├── bibliography.bib ├── custom.css ├── data │ ├── AngristLavy_AERdata │ │ ├── base00.dta │ │ ├── base01.dta │ │ ├── base02.dta │ │ ├── base99.dta │ │ └── readme.doc │ ├── TNSTAR │ │ └── STAR_Students.tab │ └── deaths.dta ├── panel simulation notes.Rmd ├── panel_simulation_notes.pdf ├── scraps ├── simulation review.Rnw ├── simulation_table.aux ├── simulation_table.tex ├── standard test.wmf └── summary rejection rates from simulation.csv ├── tests ├── testthat.R └── testthat │ ├── test_AER_ivreg.R │ ├── test_Wald.R │ ├── test_Wald_multiple_comparisons.R │ ├── test_coef.R │ ├── test_conf_int.R │ ├── test_estfun.R │ ├── test_geeglm.R │ ├── test_glm_logit.R │ ├── test_gls.R │ ├── test_ignore_absorption.R │ ├── test_impute_covariance_matrix.R │ ├── test_intercept_formulas.R │ ├── test_ivreg_ivreg.R │ ├── test_linear_contrast.R │ ├── test_linear_contrast_multiple_comparisons.R │ ├── test_lm.R │ ├── test_lm_robust.R │ ├── test_lme_2level.R │ ├── test_lme_3level.R │ ├── test_lme_MVML.R │ ├── test_lmerMod.R │ ├── test_mlm.R │ ├── test_plm-ID-variables.R │ ├── test_plm-first-differences.R │ ├── test_plm-fixed-effects.R │ ├── test_plm-random-effects.R │ ├── test_plm-unbalanced-fixed-effects.R │ ├── test_plm_overspecified_problem.R │ ├── test_rma-ls.R │ ├── test_rma-mv.R │ ├── test_rma-uni.R │ └── test_robu.R └── vignettes ├── Wald-tests-in-clubSandwich.Rmd ├── apa.csl ├── bibliography.bib ├── meta-analysis-with-CRVE.Rmd └── panel-data-CRVE.Rmd /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/.DS_Store -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^CRAN-RELEASE$ 2 | ^.*\.Rproj$ 3 | ^\.Rproj\.user$ 4 | auxilliary 5 | paper_ClusterRobustTesting 6 | ^\.travis\.yml$ 7 | cran-comments.md 8 | README.md 9 | revdep 10 | vignettes/Robust-Variance-Estimation-with-clubSandwich.Rmd 11 | ^\.github$ 12 | ^codecov\.yml$ 13 | ^_pkgdown\.yml$ 14 | ^docs$ 15 | ^pkgdown$ 16 | ^revdep$ 17 | ^CRAN-SUBMISSION$ 18 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | if: "! contains(github.event.head_commit.message, '[skip ci]')" 14 | runs-on: ${{ matrix.config.os }} 15 | 16 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | config: 22 | - {os: macOS-latest, r: 'release'} 23 | - {os: windows-latest, r: 'release'} 24 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 25 | - {os: ubuntu-latest, r: 'release'} 26 | - {os: ubuntu-latest, r: 'oldrel-1'} 27 | 28 | env: 29 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 30 | R_KEEP_PKG_SOURCE: yes 31 | 32 | steps: 33 | - uses: actions/checkout@v2 34 | 35 | - uses: r-lib/actions/setup-pandoc@v2 36 | 37 | - uses: r-lib/actions/setup-r@v2 38 | with: 39 | r-version: ${{ matrix.config.r }} 40 | http-user-agent: ${{ matrix.config.http-user-agent }} 41 | use-public-rspm: true 42 | 43 | - uses: r-lib/actions/setup-r-dependencies@v2 44 | with: 45 | extra-packages: any::rcmdcheck 46 | needs: check 47 | 48 | - uses: r-lib/actions/check-r-package@v2 49 | with: 50 | upload-snapshots: true 51 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | 7 | name: pkgdown 8 | 9 | jobs: 10 | pkgdown: 11 | if: "! contains(github.event.head_commit.message, '[skip ci]')" 12 | runs-on: ubuntu-latest 13 | env: 14 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - uses: r-lib/actions/setup-pandoc@v2 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | with: 22 | use-public-rspm: true 23 | 24 | - uses: r-lib/actions/setup-r-dependencies@v2 25 | with: 26 | extra-packages: any::pkgdown, local::. 27 | needs: website 28 | 29 | - name: Build site 30 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 31 | shell: Rscript {0} 32 | 33 | - name: Deploy to GitHub pages 🚀 34 | if: github.event_name != 'pull_request' 35 | uses: JamesIves/github-pages-deploy-action@4.1.4 36 | with: 37 | clean: false 38 | branch: gh-pages 39 | folder: docs 40 | -------------------------------------------------------------------------------- /.github/workflows/recheck.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | inputs: 4 | which: 5 | type: choice 6 | description: Which dependents to check 7 | options: 8 | - strong 9 | - most 10 | 11 | name: Reverse dependency check 12 | 13 | jobs: 14 | revdep_check: 15 | name: Reverse check ${{ inputs.which }} dependents 16 | uses: r-devel/recheck/.github/workflows/recheck.yml@v1 17 | with: 18 | which: ${{ inputs.which }} -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | if: "! contains(github.event.head_commit.message, '[skip ci]')" 14 | runs-on: ubuntu-latest 15 | env: 16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - uses: r-lib/actions/setup-r@v2 22 | with: 23 | use-public-rspm: true 24 | 25 | - uses: r-lib/actions/setup-r-dependencies@v2 26 | with: 27 | extra-packages: any::covr 28 | needs: coverage 29 | 30 | - name: Test coverage 31 | run: covr::codecov(quiet = FALSE) 32 | shell: Rscript {0} 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | inst/doc 5 | docs 6 | revdep 7 | clubSandwich.Rproj 8 | -------------------------------------------------------------------------------- /CRAN-SUBMISSION: -------------------------------------------------------------------------------- 1 | Version: 0.6.0 2 | Date: 2025-03-31 21:56:47 UTC 3 | SHA: eec1c6cfa5942f95f21ac879929a316ff7b5a7d3 4 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: clubSandwich 2 | Title: Cluster-Robust (Sandwich) Variance Estimators with Small-Sample 3 | Corrections 4 | Version: 0.6.0 5 | Authors@R: c( 6 | person(c("James","E."), "Pustejovsky", email = "jepusto@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0591-9465")), 7 | person("Samuel", "Pekofsky", email = "sampekofsky@gmail.com", role = "ctb"), 8 | person("Jingru", "Zhang", email = "jz26372022@hotmail.com", role = "ctb") 9 | ) 10 | Description: Provides several cluster-robust variance estimators (i.e., 11 | sandwich estimators) for ordinary and weighted least squares linear regression 12 | models, including the bias-reduced linearization estimator introduced by Bell 13 | and McCaffrey (2002) 14 | and 15 | developed further by Pustejovsky and Tipton (2017) 16 | . The package includes functions for estimating 17 | the variance- covariance matrix and for testing single- and multiple- 18 | contrast hypotheses based on Wald test statistics. Tests of single regression 19 | coefficients use Satterthwaite or saddle-point corrections. Tests of multiple- 20 | contrast hypotheses use an approximation to Hotelling's T-squared distribution. 21 | Methods are provided for a variety of fitted models, including lm() and mlm 22 | objects, glm(), geeglm() (from package 'geepack'), ivreg() (from package 'AER'), ivreg() (from package 'ivreg' when 23 | estimated by ordinary least squares), plm() (from package 'plm'), gls() and 24 | lme() (from 'nlme'), lmer() (from `lme4`), robu() (from 'robumeta'), and rma.uni() 25 | and rma.mv() (from 'metafor'). 26 | URL: http://jepusto.github.io/clubSandwich/ 27 | BugReports: https://github.com/jepusto/clubSandwich/issues 28 | Depends: 29 | R (>= 3.0.0) 30 | License: GPL-3 31 | VignetteBuilder: knitr 32 | LazyData: true 33 | Imports: 34 | stats, 35 | sandwich, 36 | lifecycle 37 | Suggests: 38 | Formula, 39 | knitr, 40 | carData, 41 | geepack, 42 | metafor, 43 | metadat, 44 | robumeta, 45 | nlme, 46 | mlmRev, 47 | AER, 48 | plm (>= 1.6-4), 49 | Matrix, 50 | lme4, 51 | zoo, 52 | testthat, 53 | rmarkdown, 54 | covr, 55 | ivreg 56 | RoxygenNote: 7.3.2 57 | Encoding: UTF-8 58 | Language: en-US 59 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(as.matrix,clubSandwich) 4 | S3method(augmented_model_matrix,default) 5 | S3method(augmented_model_matrix,plm) 6 | S3method(bread,geeglm) 7 | S3method(bread,gls) 8 | S3method(bread,lme) 9 | S3method(bread,lmerMod) 10 | S3method(bread,mlm) 11 | S3method(bread,plm) 12 | S3method(bread,rma.mv) 13 | S3method(bread,rma.uni) 14 | S3method(bread,robu) 15 | S3method(coef_CS,default) 16 | S3method(coef_CS,lme) 17 | S3method(coef_CS,lmerMod) 18 | S3method(coef_CS,mlm) 19 | S3method(coef_CS,rma.ls) 20 | S3method(coef_CS,robu) 21 | S3method(model_matrix,default) 22 | S3method(model_matrix,geeglm) 23 | S3method(model_matrix,glm) 24 | S3method(model_matrix,gls) 25 | S3method(model_matrix,ivreg) 26 | S3method(model_matrix,lme) 27 | S3method(model_matrix,lmerMod) 28 | S3method(model_matrix,mlm) 29 | S3method(model_matrix,plm) 30 | S3method(model_matrix,rma.ls) 31 | S3method(model_matrix,robu) 32 | S3method(na.action,rma) 33 | S3method(print,Wald_test_clubSandwich) 34 | S3method(print,clubSandwich) 35 | S3method(print,coef_test_clubSandwich) 36 | S3method(print,conf_int_clubSandwich) 37 | S3method(residuals_CS,default) 38 | S3method(residuals_CS,geeglm) 39 | S3method(residuals_CS,glm) 40 | S3method(residuals_CS,lme) 41 | S3method(residuals_CS,lmerMod) 42 | S3method(residuals_CS,mlm) 43 | S3method(residuals_CS,plm) 44 | S3method(residuals_CS,rma) 45 | S3method(residuals_CS,robu) 46 | S3method(targetVariance,default) 47 | S3method(targetVariance,geeglm) 48 | S3method(targetVariance,glm) 49 | S3method(targetVariance,gls) 50 | S3method(targetVariance,lme) 51 | S3method(targetVariance,lmerMod) 52 | S3method(targetVariance,mlm) 53 | S3method(targetVariance,plm) 54 | S3method(targetVariance,rma.mv) 55 | S3method(targetVariance,rma.uni) 56 | S3method(targetVariance,robu) 57 | S3method(v_scale,default) 58 | S3method(v_scale,geeglm) 59 | S3method(v_scale,glm) 60 | S3method(v_scale,lm) 61 | S3method(v_scale,lme) 62 | S3method(v_scale,lmerMod) 63 | S3method(v_scale,mlm) 64 | S3method(v_scale,plm) 65 | S3method(v_scale,rma.mv) 66 | S3method(v_scale,robu) 67 | S3method(vcovCR,default) 68 | S3method(vcovCR,geeglm) 69 | S3method(vcovCR,glm) 70 | S3method(vcovCR,gls) 71 | S3method(vcovCR,ivreg) 72 | S3method(vcovCR,lm) 73 | S3method(vcovCR,lme) 74 | S3method(vcovCR,lmerMod) 75 | S3method(vcovCR,mlm) 76 | S3method(vcovCR,plm) 77 | S3method(vcovCR,rma.mv) 78 | S3method(vcovCR,rma.uni) 79 | S3method(vcovCR,robu) 80 | S3method(weightMatrix,default) 81 | S3method(weightMatrix,geeglm) 82 | S3method(weightMatrix,glm) 83 | S3method(weightMatrix,gls) 84 | S3method(weightMatrix,lme) 85 | S3method(weightMatrix,lmerMod) 86 | S3method(weightMatrix,mlm) 87 | S3method(weightMatrix,plm) 88 | S3method(weightMatrix,rma.mv) 89 | S3method(weightMatrix,rma.uni) 90 | S3method(weightMatrix,robu) 91 | S3method(weights,robu) 92 | export(Wald_test) 93 | export(coef_test) 94 | export(conf_int) 95 | export(constrain_equal) 96 | export(constrain_pairwise) 97 | export(constrain_zero) 98 | export(findCluster.rma.mv) 99 | export(impute_covariance_matrix) 100 | export(linear_contrast) 101 | export(pattern_covariance_matrix) 102 | export(vcovCR) 103 | import(stats) 104 | importFrom(sandwich,bread) 105 | -------------------------------------------------------------------------------- /R/CR-adjustments.R: -------------------------------------------------------------------------------- 1 | #--------------------------------------------- 2 | # Auxilliary functions for CR* functions 3 | #--------------------------------------------- 4 | 5 | IH_jj_list <- function(M, X_list, XW_list) { 6 | Map(function(x, xw) diag(nrow = nrow(x)) - x %*% M %*% xw, 7 | x = X_list, xw = XW_list) 8 | } 9 | 10 | #--------------------------------------------- 11 | # Estimating function adjustments 12 | #--------------------------------------------- 13 | 14 | CR0 <- function(J) NULL 15 | 16 | CR1 <- function(J) sqrt(J / (J - 1)) 17 | 18 | CR1p <- function(J, p) sqrt(J / (J - p)) 19 | 20 | CR1S <- function(J, N, p) sqrt(J * (N - 1) / ((J - 1) * (N - p))) 21 | 22 | CR2 <- function(M_U, U_list, UW_list, Theta_list, inverse_var = FALSE) { 23 | 24 | Theta_chol <- lapply(Theta_list, chol) 25 | 26 | if (inverse_var) { 27 | IH_jj <- IH_jj_list(M_U, U_list, UW_list) 28 | G_list <- Map(function(a,b,ih) as.matrix(a %*% ih %*% b %*% t(a)), 29 | a = Theta_chol, b = Theta_list, ih = IH_jj) 30 | } else { 31 | H_jj <- Map(function(u, uw) u %*% M_U %*% uw, 32 | u = U_list, uw = UW_list) 33 | uwTwu <- Map(function(uw, th) uw %*% th %*% t(uw), 34 | uw = UW_list, th = Theta_list) 35 | MUWTWUM <- M_U %*% Reduce("+", uwTwu) %*% M_U 36 | G_list <- Map(function(thet, h, u, v) 37 | as.matrix(v %*% (thet - h %*% thet - thet %*% t(h) + u %*% MUWTWUM %*% t(u)) %*% t(v)), 38 | thet = Theta_list, h = H_jj, u = U_list, v = Theta_chol) 39 | } 40 | 41 | Map(function(v, g) as.matrix(t(v) %*% matrix_power(g, -1/2) %*% v), 42 | v = Theta_chol, g = G_list) 43 | } 44 | 45 | CR3 <- function(X_list, XW_list) { 46 | XWX_list <- Map(function(xw, x) xw %*% x, xw = XW_list, x = X_list) 47 | M <- chol2inv(chol(Reduce("+", XWX_list))) 48 | IH_jj <- IH_jj_list(M, X_list, XW_list) 49 | lapply(IH_jj, solve) 50 | } 51 | 52 | CR4 <- function(M_U, U_list, UW_list, X_list, XW_list, Theta_list, inverse_var = FALSE) { 53 | 54 | if (inverse_var) { 55 | F_list <- Map(function(xw, x) xw %*% x, xw = XW_list, x = X_list) 56 | UWX_list <- Map(function(uw, x) uw %*% x, uw = UW_list, x = X_list) 57 | F_chol <- lapply(F_list, chol_psd) 58 | G_list <- Map(function(fc, fm, uwx) fc %*% (fm - t(uwx) %*% M_U %*% uwx) %*% t(fc), 59 | fc = F_chol, fm = F_list, uwx = UWX_list) 60 | } else { 61 | F_list <- Map(function(xw, theta) xw %*% theta %*% t(xw), 62 | xw = XW_list, theta = Theta_list) 63 | F_chol <- lapply(F_list, chol_psd) 64 | UWX_list <- Map(function(uw, x) uw %*% x, uw = UW_list, x = X_list) 65 | UWTWX_list <- Map(function(uw, xw, theta) uw %*% theta %*% t(xw), uw = UW_list, xw = XW_list, theta = Theta_list) 66 | UWTWU_list <- Map(function(uw, theta) uw %*% theta %*% t(uw), uw = UW_list, theta = Theta_list) 67 | MUWTWUM <- M_U %*% Reduce("+", UWTWU_list) %*% M_U 68 | G_list <- Map(function(fc, fm, uwx, uwtwx) 69 | as.matrix(fc %*% (fm - t(uwx) %*% M_U %*% uwtwx - t(uwtwx) %*% M_U %*% uwx + t(uwx) %*% MUWTWUM %*% uwx) %*% t(fc)), 70 | fc = F_chol, fm = F_list, uwx = UWX_list, uwtwx = UWTWX_list) 71 | } 72 | 73 | Map(function(fc, g) as.matrix(t(fc) %*% matrix_power(g, -1/2) %*% fc), 74 | fc = F_chol, g = G_list) 75 | } 76 | -------------------------------------------------------------------------------- /R/S3-methods.R: -------------------------------------------------------------------------------- 1 | #---------------------------------------------- 2 | # get "working" variance-covariance matrix 3 | #---------------------------------------------- 4 | 5 | targetVariance <- function(obj, cluster) UseMethod("targetVariance") 6 | 7 | #' @export 8 | 9 | targetVariance.default <- function(obj, cluster) { 10 | matrix_list(rep(1, length(cluster)), cluster, "both") 11 | } 12 | 13 | #---------------------------------------------- 14 | # get weighting matrix 15 | #---------------------------------------------- 16 | 17 | weightMatrix <- function(obj, cluster) UseMethod("weightMatrix") 18 | 19 | #' @export 20 | 21 | weightMatrix.default <- function(obj, cluster) { 22 | weights <- weights(obj) 23 | if (is.null(weights)) { 24 | weights <- w_scale <- 1 25 | } else { 26 | weights <- weights[weights > 0] 27 | w_scale <- mean(weights) 28 | weights <- weights / w_scale 29 | } 30 | W <- rep(weights, length.out = length(cluster)) 31 | W_list <- matrix_list(W, cluster, "both") 32 | attr(W_list, "w_scale") <- w_scale 33 | W_list 34 | } 35 | 36 | #---------------------------------------------- 37 | # get X matrix 38 | #---------------------------------------------- 39 | 40 | model_matrix <- function(obj) UseMethod("model_matrix") 41 | 42 | #' @export 43 | 44 | model_matrix.default <- function(obj) { 45 | model_matrix <- model.matrix(obj) 46 | 47 | w <- obj$weights 48 | if (is.null(w) || all(pos_wts <- w > 0)) { 49 | return(model_matrix) 50 | } else { 51 | return(model_matrix[pos_wts > 0,,drop=FALSE]) 52 | } 53 | } 54 | 55 | #---------------------------------------------- 56 | # get augmented design matrix 57 | #---------------------------------------------- 58 | 59 | augmented_model_matrix <- function(obj, cluster, inverse_var, ignore_FE) UseMethod("augmented_model_matrix") 60 | 61 | #' @export 62 | 63 | augmented_model_matrix.default <- function(obj, cluster, inverse_var, ignore_FE) { 64 | NULL 65 | } 66 | 67 | #---------------------------------------------- 68 | # get residuals 69 | #---------------------------------------------- 70 | 71 | residuals_CS <- function(obj) UseMethod("residuals_CS") 72 | 73 | #' @export 74 | 75 | residuals_CS.default <- function(obj) { 76 | w <- obj$weights 77 | if (is.null(w) || all(pos_wts <- w > 0)) { 78 | residuals(obj) 79 | } else { 80 | residuals(obj)[pos_wts] 81 | } 82 | } 83 | 84 | #---------------------------------------------- 85 | # get coefficient estimates 86 | #---------------------------------------------- 87 | 88 | coef_CS <- function(obj) UseMethod("coef_CS") 89 | 90 | #' @export 91 | 92 | coef_CS.default <- function(obj) { 93 | coef(obj) 94 | } 95 | 96 | #---------------------------------------------- 97 | # get bread matrix 98 | #---------------------------------------------- 99 | 100 | # bread matrices imported from sandwich package or elsewhere 101 | #' @importFrom sandwich bread 102 | 103 | get_bread <- function(obj) bread(obj) 104 | 105 | v_scale <- function(obj) UseMethod("v_scale") 106 | 107 | #' @export 108 | 109 | v_scale.default <- function(obj) { 110 | nobs(obj) 111 | } 112 | -------------------------------------------------------------------------------- /R/glm.R: -------------------------------------------------------------------------------- 1 | #------------------------------------- 2 | # vcovCR with defaults 3 | #------------------------------------- 4 | 5 | #' Cluster-robust variance-covariance matrix for a glm object. 6 | #' 7 | #' \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 8 | #' of a set of regression coefficient estimates from an \code{\link{glm}} object. 9 | #' 10 | #' @param cluster Expression or vector indicating which observations belong to 11 | #' the same cluster. Required for \code{glm} objects. 12 | #' @param target Optional matrix or vector describing the working 13 | #' variance-covariance model used to calculate the \code{CR2} and \code{CR4} 14 | #' adjustment matrices. If a vector, the target matrix is assumed to be 15 | #' diagonal. If not specified, the target is taken to be the estimated variance function. 16 | #' @inheritParams vcovCR 17 | #' 18 | #' @return An object of class \code{c("vcovCR","clubSandwich")}, which consists 19 | #' of a matrix of the estimated variance of and covariances between the 20 | #' regression coefficient estimates. 21 | #' 22 | #' @seealso \code{\link{vcovCR}} 23 | #' 24 | #' @examples 25 | #' 26 | #' if (requireNamespace("geepack", quietly = TRUE)) { 27 | #' 28 | #' data(dietox, package = "geepack") 29 | #' dietox$Cu <- as.factor(dietox$Cu) 30 | #' weight_fit <- glm(Weight ~ Cu * poly(Time, 3), data=dietox, family = "quasipoisson") 31 | #' V_CR <- vcovCR(weight_fit, cluster = dietox$Pig, type = "CR2") 32 | #' coef_test(weight_fit, vcov = V_CR, test = "Satterthwaite") 33 | #' 34 | #' } 35 | #' 36 | #' @export 37 | 38 | vcovCR.glm <- function(obj, cluster, type, target = NULL, inverse_var = NULL, form = "sandwich", ...) { 39 | if (missing(cluster)) stop("You must specify a clustering variable.") 40 | if (is.null(inverse_var)) inverse_var <- is.null(target) 41 | vcov_CR(obj, cluster = cluster, type = type, 42 | target = target, inverse_var = inverse_var, form = form) 43 | } 44 | 45 | # coef() 46 | # nobs() 47 | 48 | #----------------------------------------------- 49 | # Model matrix 50 | #----------------------------------------------- 51 | 52 | #' @export 53 | 54 | model_matrix.glm <- function(obj) { 55 | X <- model.matrix(obj) 56 | eta <- obj$linear.predictors 57 | dmu_deta <- obj$family$mu.eta 58 | d <- dmu_deta(eta) 59 | d * X 60 | } 61 | 62 | #------------------------------------- 63 | # residuals 64 | #------------------------------------- 65 | 66 | #' @export 67 | 68 | residuals_CS.glm <- function(obj) { 69 | residuals(obj, type = "response") 70 | } 71 | 72 | #----------------------------------------------- 73 | # Get (model-based) working variance matrix 74 | #----------------------------------------------- 75 | 76 | #' @export 77 | 78 | targetVariance.glm <- function(obj, cluster) { 79 | mu <- fitted.values(obj) 80 | var_fun <- obj$family$variance 81 | v <- var_fun(mu) 82 | w <- weights(obj, type = "prior") 83 | matrix_list(v / w, cluster, "both") 84 | } 85 | 86 | #------------------------------------- 87 | # Get weighting matrix 88 | #------------------------------------- 89 | 90 | #' @export 91 | 92 | weightMatrix.glm <- function(obj, cluster) { 93 | mu <- fitted.values(obj) 94 | var_fun <- obj$family$variance 95 | v <- var_fun(mu) 96 | w <- weights(obj, type = "prior") 97 | matrix_list(w / v, cluster, "both") 98 | } 99 | 100 | #--------------------------------------- 101 | # Get bread matrix and scaling constant 102 | #--------------------------------------- 103 | 104 | # bread.glm() is in sandwich package 105 | 106 | #' @export 107 | 108 | v_scale.glm <- function(obj) { 109 | if (substr(obj$family$family, 1, 17) %in% c("poisson", "binomial", "Negative Binomial")) { 110 | dispersion <- 1 111 | } else { 112 | wres <- as.vector(residuals(obj, "working")) * weights(obj, "working") 113 | dispersion <- sum(wres^2)/sum(weights(obj, "working")) 114 | } 115 | as.vector(sum(summary(obj)$df[1:2])) * dispersion 116 | } 117 | -------------------------------------------------------------------------------- /R/ivreg.R: -------------------------------------------------------------------------------- 1 | #------------------------------------- 2 | # vcovCR with defaults 3 | #------------------------------------- 4 | 5 | #' Cluster-robust variance-covariance matrix for an ivreg object. 6 | #' 7 | #' \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 8 | #' of a set of regression coefficient estimates from an ivreg object fitted 9 | #' from the \CRANpkg{AER} package or the \CRANpkg{ivreg} package. 10 | #' 11 | #' @param cluster Expression or vector indicating which observations belong to 12 | #' the same cluster. Required for \code{ivreg} objects. 13 | #' @param target Optional matrix or vector describing the working 14 | #' variance-covariance model used to calculate the \code{CR2} and \code{CR4} 15 | #' adjustment matrices. If a vector, the target matrix is assumed to be 16 | #' diagonal. If not specified, the target is taken to be an identity matrix. 17 | #' @param inverse_var Not used for \code{ivreg} objects. 18 | #' @inheritParams vcovCR 19 | #' 20 | #' @details For any "ivreg" objects fitted via the \code{\link[ivreg]{ivreg}} 21 | #' function from the \CRANpkg{ivreg} package, only traditional 2SLS 22 | #' regression method (method = "OLS") is supported. 23 | #' clubSandwich currently cannot support robust-regression methods such as 24 | #' M-estimation (method = "M") or MM-estimation (method = "MM"). 25 | #' 26 | #' @return An object of class \code{c("vcovCR","clubSandwich")}, which consists 27 | #' of a matrix of the estimated variance of and covariances between the 28 | #' regression coefficient estimates. 29 | #' 30 | #' @seealso \code{\link{vcovCR}} 31 | #' 32 | #' @examples 33 | #' 34 | #' if (requireNamespace("AER", quietly = TRUE)) withAutoprint({ 35 | #' 36 | #' library(AER) 37 | #' data("CigarettesSW") 38 | #' Cigs <- within(CigarettesSW, { 39 | #' rprice <- price/cpi 40 | #' rincome <- income/population/cpi 41 | #' tdiff <- (taxs - tax)/cpi 42 | #' }) 43 | #' 44 | #' iv_fit_AER <- AER::ivreg(log(packs) ~ log(rprice) + log(rincome) | 45 | #' log(rincome) + tdiff + I(tax/cpi), data = Cigs) 46 | #' vcovCR(iv_fit_AER, cluster = Cigs$state, type = "CR2") 47 | #' coef_test(iv_fit_AER, vcov = "CR2", cluster = Cigs$state) 48 | #' 49 | #' }) 50 | #' 51 | #' pkgs_available <- 52 | #' requireNamespace("AER", quietly = TRUE) & 53 | #' requireNamespace("ivreg", quietly = TRUE) 54 | #' 55 | #' if (pkgs_available) withAutoprint ({ 56 | #' 57 | #' data("CigarettesSW") 58 | #' Cigs <- within(CigarettesSW, { 59 | #' rprice <- price/cpi 60 | #' rincome <- income/population/cpi 61 | #' tdiff <- (taxs - tax)/cpi 62 | #' }) 63 | #' iv_fit_ivreg <- ivreg::ivreg(log(packs) ~ log(rprice) + log(rincome) | 64 | #' log(rincome) + tdiff + I(tax/cpi), data = Cigs) 65 | #' vcovCR(iv_fit_ivreg, cluster = Cigs$state, type = "CR2") 66 | #' coef_test(iv_fit_ivreg, vcov = "CR2", cluster = Cigs$state) 67 | #' }) 68 | #' 69 | #' @export 70 | 71 | vcovCR.ivreg <- function(obj, cluster, type, target = NULL, inverse_var = FALSE, form = "sandwich", ...) { 72 | if (missing(cluster)) stop("You must specify a clustering variable.") 73 | if (inverse_var != FALSE) stop("Unfortunately, the inverse_var option is not available for ivreg models.") 74 | if (!is.null(obj$method) && obj$method %in% c("M", "MM")) stop("clubSandwich does not currently support ivreg models estimated using method = 'M' or method = 'MM'.") 75 | vcov_CR(obj, cluster = cluster, type = type, 76 | target = target, inverse_var = inverse_var, form = form) 77 | } 78 | 79 | # residuals_CS() 80 | # coef() 81 | # targetVariance() 82 | # weightMatrix() 83 | # v_scale() 84 | 85 | #---------------------------------------------- 86 | # get X matrix 87 | #---------------------------------------------- 88 | 89 | #' @export 90 | 91 | model_matrix.ivreg <- function(obj) { 92 | model_matrix <- model.matrix(obj, component = "projected") 93 | 94 | w <- obj$weights 95 | if (is.null(w) || all(pos_wts <- w > 0)) { 96 | return(model_matrix) 97 | } else { 98 | return(model_matrix[pos_wts > 0,,drop=FALSE]) 99 | } 100 | 101 | } 102 | 103 | #--------------------------------------- 104 | # Get bread matrix and scaling constant 105 | #--------------------------------------- 106 | 107 | # bread.ivreg() is in AER package 108 | # use default v_scale() -------------------------------------------------------------------------------- /R/lm.R: -------------------------------------------------------------------------------- 1 | #------------------------------------- 2 | # vcovCR with defaults 3 | #------------------------------------- 4 | 5 | #' Cluster-robust variance-covariance matrix for an lm object. 6 | #' 7 | #' \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 8 | #' of a set of regression coefficient estimates from an \code{\link{lm}} object. 9 | #' 10 | #' @param cluster Expression or vector indicating which observations belong to 11 | #' the same cluster. Required for \code{lm} objects. 12 | #' @param target Optional matrix or vector describing the working 13 | #' variance-covariance model used to calculate the \code{CR2} and \code{CR4} 14 | #' adjustment matrices. If a vector, the target matrix is assumed to be 15 | #' diagonal. If not specified, the target is taken to be an identity matrix. 16 | #' @inheritParams vcovCR 17 | #' 18 | #' @return An object of class \code{c("vcovCR","clubSandwich")}, which consists 19 | #' of a matrix of the estimated variance of and covariances between the 20 | #' regression coefficient estimates. 21 | #' 22 | #' @seealso \code{\link{vcovCR}} 23 | #' 24 | #' @examples 25 | #' 26 | #' data("ChickWeight", package = "datasets") 27 | #' lm_fit <- lm(weight ~ Time + Diet:Time, data = ChickWeight) 28 | #' vcovCR(lm_fit, cluster = ChickWeight$Chick, type = "CR2") 29 | #' 30 | #' if (requireNamespace("plm", quietly = TRUE)) withAutoprint({ 31 | #' 32 | #' data("Produc", package = "plm") 33 | #' lm_individual <- lm(log(gsp) ~ 0 + state + log(pcap) + log(pc) + log(emp) + unemp, data = Produc) 34 | #' individual_index <- !grepl("state", names(coef(lm_individual))) 35 | #' vcovCR(lm_individual, cluster = Produc$state, type = "CR2")[individual_index,individual_index] 36 | #' 37 | #' # compare to plm() 38 | #' plm_FE <- plm::plm(log(gsp) ~ log(pcap) + log(pc) + log(emp) + unemp, 39 | #' data = Produc, index = c("state","year"), 40 | #' effect = "individual", model = "within") 41 | #' vcovCR(plm_FE, type="CR2") 42 | #' 43 | #' }) 44 | #' 45 | #' @export 46 | 47 | vcovCR.lm <- function(obj, cluster, type, target = NULL, inverse_var = NULL, form = "sandwich", ...) { 48 | if (missing(cluster)) stop("You must specify a clustering variable.") 49 | if (is.null(inverse_var)) inverse_var <- is.null(weights(obj)) & is.null(target) 50 | vcov_CR(obj, cluster = cluster, type = type, 51 | target = target, inverse_var = inverse_var, form = form) 52 | } 53 | 54 | # model_matrix() 55 | # residuals_CS() 56 | # coef() 57 | # nobs() 58 | # targetVariance() 59 | # weightMatrix() 60 | 61 | 62 | #--------------------------------------- 63 | # Get bread matrix and scaling constant 64 | #--------------------------------------- 65 | 66 | # bread.lm() is in sandwich package 67 | 68 | #' @export 69 | 70 | v_scale.lm <- function(obj) { 71 | as.vector(sum(summary(obj)$df[1:2])) 72 | } 73 | -------------------------------------------------------------------------------- /R/matrix-functions.R: -------------------------------------------------------------------------------- 1 | 2 | #--------------------------------------------- 3 | # matrix manipulation functions 4 | #--------------------------------------------- 5 | 6 | sub_f <- function(x, fac, dim) { 7 | function(f) switch(dim, 8 | row = x[fac==f, ,drop=FALSE], 9 | col = x[ ,fac==f, drop=FALSE], 10 | both = x[fac==f, fac==f, drop=FALSE]) 11 | } 12 | 13 | matrix_list <- function(x, fac, dim) { 14 | if (is.vector(x)) { 15 | if (dim != "both") stop(paste0("Object must be a matrix in order to subset by ",dim,".")) 16 | x_list <- split(x, fac) 17 | lapply(x_list, function(x) diag(x, nrow = length(x))) 18 | } else { 19 | lapply(levels(fac), sub_f(x, fac, dim)) 20 | } 21 | } 22 | 23 | # turn block-diagonal into regular matrix 24 | 25 | unblock <- function(A, block = attr(A, "groups")) { 26 | 27 | if (is.null(block)) block <- factor(rep(names(A), times = sapply(A, function(x) dim(x)[1]))) 28 | n <- length(block) 29 | mat <- matrix(0, n, n) 30 | for (i in levels(block)) { 31 | index <- i == block 32 | mat[index,index] <- A[[i]] 33 | } 34 | return(mat) 35 | } 36 | 37 | matrix_power <- function(x, p, symmetric = TRUE, tol = -12) { 38 | eig <- eigen(x, symmetric = symmetric) 39 | val_p <- with(eig, ifelse(values > 10^tol, values^p, 0)) 40 | with(eig, vectors %*% (val_p * t(vectors))) 41 | } 42 | 43 | chol_psd <- function(x) with(eigen(x, symmetric=TRUE), sqrt(pmax(values,0)) * t(vectors)) 44 | 45 | 46 | add_submatrices <- function(indices, small_mat, big_mat) { 47 | levs <- levels(indices) 48 | for (i in 1:length(levs)) { 49 | ind <- levs[i] == indices 50 | big_mat[ind,ind] <- small_mat[[i]] + big_mat[ind,ind] 51 | } 52 | big_mat 53 | } 54 | 55 | add_bdiag <- function(small_mats, big_mats, crosswalk) { 56 | small_indices <- lapply(split(crosswalk[[1]], crosswalk[[2]]), droplevels) 57 | big_indices <- unique(crosswalk) 58 | big_indices <- big_indices[[2]][order(big_indices[[1]])] 59 | small_mats <- split(small_mats, big_indices) 60 | Map(add_submatrices, indices = small_indices, small_mat = small_mats, big_mat = big_mats) 61 | } 62 | 63 | nest_bdiag <- function(mats, crosswalk) { 64 | small_indices <- lapply(split(crosswalk[[1]], crosswalk[[2]]), droplevels) 65 | big_indices <- unique(crosswalk) 66 | big_indices <- big_indices[[2]][order(big_indices[[1]])] 67 | mat_groups <- split(mats, big_indices) 68 | Map(unblock, A = mat_groups) 69 | } 70 | 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![R-CMD-check](https://github.com/jepusto/clubSandwich/workflows/R-CMD-check/badge.svg)](https://github.com/jepusto/clubSandwich/actions) 3 | [![Codecov Status](https://codecov.io/gh/jepusto/clubSandwich/branch/main/graph/badge.svg)](https://codecov.io/gh/jepusto/clubSandwich?branch=main) 4 | [![CRAN status](https://www.r-pkg.org/badges/version/clubSandwich)](https://CRAN.R-project.org/package=clubSandwich) 5 | [![](https://cranlogs.r-pkg.org/badges/grand-total/clubSandwich)](https://CRAN.R-project.org/package=clubSandwich) 6 | [![](https://cranlogs.r-pkg.org/badges/last-month/clubSandwich)](https://CRAN.R-project.org/package=clubSandwich) 7 | 8 | 9 | # clubSandwich 10 | 11 | `clubSandwich` provides several cluster-robust variance estimators 12 | (i.e., sandwich estimators) for ordinary and weighted least squares linear regression models, two-stage least squares regression models, and generalized linear models. 13 | Several adjustments are incorporated to improve small-sample performance. 14 | The package includes functions for estimating the variance-covariance matrix and 15 | for testing single- and multiple-contrast hypotheses based on Wald test statistics. 16 | Tests of single regression coefficients use Satterthwaite or saddlepoint corrections. 17 | Tests of multiple-contrast hypotheses use an approximation to Hotelling's T-squared distribution. 18 | Methods are provided for a variety of fitted models, including: 19 | 20 | - `lm()` 21 | - `mlm()` 22 | - `glm()` 23 | - `geeglm()` (from package `geepack`) 24 | - `ivreg()` (from package `ivreg`, when estimated using `method = "OLS"`) 25 | - `ivreg()` (from package `AER`) 26 | - `plm()` (from package `plm`), 27 | - `gls()` and `lme()` (from package `nlme`) 28 | - `lmer()` (from package `lme4`) 29 | - `robu()` (from package `robumeta`) 30 | - `rma.uni()` and `rma.mv()` (from package `metafor`) 31 | 32 | # Installing clubSandwich 33 | 34 | The package is available on the Comprehensive R Archive Network. To install it, type 35 | ```{r} 36 | install.packages("clubSandwich") 37 | ``` 38 | 39 | To install the latest development version directly from Github, type: 40 | ```{r} 41 | install.packages("remotes") 42 | remotes::install_github("jepusto/clubSandwich") 43 | ``` 44 | 45 | Once installed, have a look at the available vignettes by typing: 46 | ```{r} 47 | browseVignettes(package="clubSandwich") 48 | ``` 49 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: http://jepusto.github.io/clubSandwich/ 2 | template: 3 | bootstrap: 5 4 | bootswatch: spacelab 5 | 6 | authors: 7 | James E. Pustejovsky: 8 | href: "https://www.jepusto.com/" 9 | 10 | news: 11 | one_page: true 12 | cran_dates: true 13 | 14 | reference: 15 | - title: "Cluster-robust variance covariance estimation" 16 | desc: > 17 | S3 methods for calculating cluster-robust variance-covariance matrices 18 | for various fitted model objects. 19 | contents: 20 | - vcovCR 21 | - starts_with("vcovCR") 22 | - title: "Inference functions" 23 | desc: > 24 | Functions for inference based on cluster-robust variance-covariance matrices. 25 | contents: 26 | - coef_test 27 | - conf_int 28 | - linear_contrast 29 | - Wald_test 30 | - starts_with("constrain_") 31 | - title: "Helper functions for multivariate meta-analysis" 32 | desc: > 33 | Helper functions for use in estimating multivariate meta-analysis models 34 | with `metafor::rma.mv()`. 35 | contents: 36 | - ends_with("covariance_matrix") 37 | - findCluster.rma.mv 38 | - title: "Data" 39 | desc: "Example datasets" 40 | contents: 41 | - AchievementAwardsRCT 42 | - dropoutPrevention 43 | - MortalityRates 44 | - SATcoaching 45 | 46 | 47 | -------------------------------------------------------------------------------- /auxilliary/3-level clustering with 2-level model.R: -------------------------------------------------------------------------------- 1 | library(clubSandwich) 2 | library(nlme) 3 | 4 | set.seed(20170802) 5 | 6 | # sample sizes at each level 7 | n_districts <- 10 8 | n_schools_per <- rnbinom(n_districts, size = 4, prob = 0.3) 9 | n_schools <- sum(n_schools_per) 10 | n_students_per <- 10 11 | n_students <- n_schools * n_students_per 12 | 13 | # identifiers for each level 14 | district_id <- factor(rep(1:n_districts, n_schools_per * n_students_per)) 15 | school_id <- factor(rep(1:sum(n_schools_per), each = n_students_per)) 16 | student_id <- 1:n_students 17 | 18 | # simulated outcome 19 | Y_ijk <- rnorm(n_districts)[district_id] + rnorm(n_schools)[school_id] + rnorm(n_students) 20 | dat <- data.frame(district_id, school_id, student_id, Y = Y_ijk) 21 | head(dat) 22 | 23 | #---------------------------------- 24 | # fit three-level model 25 | #---------------------------------- 26 | 27 | lme_3level <- lme(Y ~ 1, random = ~ 1 | district_id / school_id, data = dat) 28 | summary(lme_3level) 29 | 30 | # clustering variable is assumed to be at highest level 31 | coef_test(lme_3level, vcov = "CR2") 32 | 33 | # specifying the clustering variable manually returns the same result 34 | coef_test(lme_3level, vcov = "CR2", cluster = dat$district_id) 35 | 36 | #---------------------------------- 37 | # fit two-level model 38 | #---------------------------------- 39 | 40 | lme_2level <- lme(Y ~ 1, random = ~ 1 | school_id, data = dat) 41 | summary(lme_2level) # note that SE is too small! 42 | 43 | # now clustering variable is assumed to be at school level 44 | coef_test(lme_2level, vcov = "CR2") # SE is still too small! 45 | 46 | # specifying the clustering variable manually returns the same result 47 | coef_test(lme_2level, vcov = "CR2", cluster = dat$school_id) 48 | 49 | # specifying the clustering variable at the district level 50 | coef_test(lme_2level, vcov = "CR2", cluster = dat$district_id) 51 | -------------------------------------------------------------------------------- /auxilliary/AngristLavy_AERdata/base00.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/AngristLavy_AERdata/base00.dta -------------------------------------------------------------------------------- /auxilliary/AngristLavy_AERdata/base01.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/AngristLavy_AERdata/base01.dta -------------------------------------------------------------------------------- /auxilliary/AngristLavy_AERdata/base02.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/AngristLavy_AERdata/base02.dta -------------------------------------------------------------------------------- /auxilliary/AngristLavy_AERdata/base99.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/AngristLavy_AERdata/base99.dta -------------------------------------------------------------------------------- /auxilliary/AngristLavy_AERdata/readme.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/AngristLavy_AERdata/readme.doc -------------------------------------------------------------------------------- /auxilliary/BFC-question.R: -------------------------------------------------------------------------------- 1 | library(metafor) 2 | library(multcomp) 3 | library(clubSandwich) 4 | 5 | harm <- read.table(file="auxilliary/harm.txt") 6 | 7 | meta_res <-rma.mv(y=r, V=var, mods= ~ sampletype1 - 1, random = ~ 1 | study/outcome, data=harm) 8 | 9 | rob_er_meta <- conf_int(meta_res, vcov="CR2", level = 0.95, test = "Satterthwaite") 10 | 11 | summary(glht(meta_res, linfct=cbind(contrMat(rep(1,4), type="Tukey")))) 12 | 13 | constraint_mat <- cbind(rep(-1, 3), diag(1, 3)) 14 | Wald_test(meta_res, constraints = constraint_mat, vcov = "CR2") 15 | -------------------------------------------------------------------------------- /auxilliary/Bediou question.R: -------------------------------------------------------------------------------- 1 | load("auxilliary/es_data.RData") 2 | 3 | ## Multilevel model 4 | vcov_mat <- impute_covariance_matrix(es_data$g_var, 5 | cluster = es_data$Paper, 6 | r = 0.8) 7 | 8 | mlma_model<- metafor::rma.mv(g ~ 1, # Intercept only MLMA model 9 | V = vcov_mat, 10 | random = ~ 1 | Paper / ES_ID, 11 | sparse = TRUE, 12 | data = es_data, 13 | test="t") 14 | 15 | ## Add RVE using clubSandwich 16 | CHE_model <- coef_test(mlma_model, vcov = "CR2") 17 | -------------------------------------------------------------------------------- /auxilliary/Clustered IV Simulation Results.Rdata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/Clustered IV Simulation Results.Rdata -------------------------------------------------------------------------------- /auxilliary/Dropout Dataset for Tipton and Pustejovsky.sav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/Dropout Dataset for Tipton and Pustejovsky.sav -------------------------------------------------------------------------------- /auxilliary/IV Simulation Results.Rdata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/IV Simulation Results.Rdata -------------------------------------------------------------------------------- /auxilliary/Kalaian-Raudenbush-1996.csv: -------------------------------------------------------------------------------- 1 | study,year,nT,nC,SATV,SATM,hrs,ETS,study_type,homework 2 | Alderman & Powers (A),1980,28,22,0.22,,7,1,Randomized,1 3 | Alderman & Powers (B),1980,39,40,0.09,,10,1,Randomized,1 4 | Alderman & Powers (C),1980,22,17,0.14,,10.5,1,Randomized,1 5 | Alderman & Powers (D),1980,48,43,0.14,,10,1,Randomized,1 6 | Alderman & Powers (E),1980,25,74,-0.01,,6,1,Randomized,1 7 | Alderman & Powers (F),1980,37,35,0.14,,5,1,Randomized,1 8 | Alderman & Powers (G),1980,24,70,0.18,,11,1,Randomized,1 9 | Alderman & Powers (H),1980,16,19,0.01,,45,1,Randomized,1 10 | Evans & Pike (A),1973,145,129,0.13,0.12,21,1,Randomized,1 11 | Evans & Pike (B),1973,72,129,0.25,0.06,21,1,Randomized,1 12 | Evans & Pike (C),1973,71,129,0.31,0.09,21,1,Randomized,1 13 | Laschewer,1986,13,14,0,0.07,8.9,0,Randomized,0 14 | Roberts & Oppenheim (A),1966,43,37,0.01,,7.5,1,Randomized,0 15 | Roberts & Oppenheim (B),1966,19,13,0.67,,7.5,1,Randomized,0 16 | Roberts & Oppenheim (D),1966,16,11,-0.38,,7.5,1,Randomized,0 17 | Roberts & Oppenheim (E),1966,20,12,-0.24,,7.5,1,Randomized,0 18 | Roberts & Oppenheim (F),1966,39,28,0.29,,7.5,1,Randomized,0 19 | Roberts & Oppenheim (G),1966,38,25,,0.26,7.5,1,Randomized,0 20 | Roberts & Oppenheim (H),1966,18,13,,-0.41,7.5,1,Randomized,0 21 | Roberts & Oppenheim (I),1966,19,13,,0.08,7.5,1,Randomized,0 22 | Roberts & Oppenheim (J),1966,37,22,,0.3,7.5,1,Randomized,0 23 | Roberts & Oppenheim (K),1966,19,11,,-0.53,7.5,1,Randomized,0 24 | Roberts & Oppenheim (L),1966,17,13,,0.13,7.5,1,Randomized,0 25 | Roberts & Oppenheim (M),1966,20,12,,0.26,7.5,1,Randomized,0 26 | Roberts & Oppenheim (N),1966,20,13,,0.47,7.5,1,Randomized,0 27 | Zuman (B),1988,16,17,0.13,0.48,24,0,Randomized,1 28 | Burke (A),1986,25,25,0.5,,50,0,Matched,1 29 | Burke (B),1986,25,25,0.74,,50,0,Matched,1 30 | Coffin,1987,8,8,-0.23,0.33,18,0,Matched,0 31 | Davis,1985,22,21,0.13,0.13,15,0,Matched,0 32 | Frankel,1960,45,45,0.13,0.34,30,0,Matched,0 33 | Kintisch,1979,38,38,0.06,,20,0,Matched,1 34 | Whitla,1962,52,52,0.09,-0.11,10,1,Matched,1 35 | Curran (A),1988,21,17,-0.1,-0.08,6,0,Nonequivalent,0 36 | Curran (B),1988,24,17,-0.14,-0.29,6,0,Nonequivalent,0 37 | Curran (C),1988,20,17,-0.16,-0.34,6,0,Nonequivalent,0 38 | Curran (D),1988,20,17,-0.07,-0.06,6,0,Nonequivalent,0 39 | Dear,1958,60,526,-0.02,0.21,15,1,Nonequivalent,1 40 | Dyer,1953,225,193,0.06,0.17,15,1,Nonequivalent,1 41 | French (B),1955,110,158,0.06,,4.5,1,Nonequivalent,1 42 | French (C),1955,161,158,,0.2,15,1,Nonequivalent,1 43 | FTC,1978,192,684,0.15,0.03,40,0,Nonequivalent,0 44 | Keefauver,1976,16,25,0.17,-0.19,14,0,Nonequivalent,0 45 | Lass,1961,38,82,0.02,0.1,,1,Nonequivalent,1 46 | Reynolds & Oberman,1987,93,47,-0.04,0.6,63,0,Nonequivalent,1 47 | Teague,1992,10,15,0.4,,18,0,Nonequivalent,0 48 | Zuman (A),1988,21,34,0.54,0.57,27,0,Nonequivalent,1 49 | -------------------------------------------------------------------------------- /auxilliary/Kalaian-Raudenbush-1996.txt: -------------------------------------------------------------------------------- 1 | Study nT nC T x V 2 | 1 28 22 0.22 0 0.0817 3 | 2 39 40 0.09 0 0.0507 4 | 3 22 17 0.14 0 0.1045 5 | 4 48 43 0.14 0 0.0442 6 | 5 25 74 -0.01 0 0.0535 7 | 6 37 35 0.14 0 0.0557 8 | 7 24 70 0.18 0 0.0561 9 | 8 16 19 0.01 0 0.1151 10 | 9 43 37 0.01 0 0.0503 11 | 10 19 13 0.67 0 0.1366 12 | 11 16 11 -0.38 0 0.1561 13 | 12 20 12 -0.24 0 0.1342 14 | 13 39 28 0.29 0 0.0620 15 | 14 38 25 0.26 1 0.0669 16 | 15 18 13 -0.41 1 0.1352 17 | 16 19 13 0.08 1 0.1297 18 | 17 37 22 0.30 1 0.0732 19 | 18 19 11 -0.53 1 0.1482 20 | 19 17 13 0.13 1 0.1360 21 | 20 20 12 0.26 1 0.1344 22 | 21 20 13 0.47 1 0.1303 23 | 22 145 129 0.13 0 0.0147 24 | 22 145 129 0.12 1 0.0147 25 | 23 72 129 0.25 0 0.0218 26 | 23 72 129 0.06 1 0.0216 27 | 24 71 129 0.31 0 0.0221 28 | 24 71 129 0.09 1 0.0219 29 | 25 13 14 0.00 0 0.1484 30 | 25 13 14 0.07 1 0.1484 31 | 26 16 17 0.13 0 0.1216 32 | 26 16 17 0.48 1 0.1248 -------------------------------------------------------------------------------- /auxilliary/Multisite IV Simulation Results.Rdata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/Multisite IV Simulation Results.Rdata -------------------------------------------------------------------------------- /auxilliary/STAR SUR example.R: -------------------------------------------------------------------------------- 1 | 2 | data(STAR, package = "AER") 3 | 4 | library(clubSandwich) 5 | library(dplyr) 6 | library(tidyr) 7 | 8 | # pull out first grade information 9 | 10 | STAR_1st_urban <- 11 | STAR %>% 12 | select(gender, ethnicity, birth, ends_with("1")) %>% 13 | filter(!is.na(star1)) %>% 14 | mutate(student_id = row_number(), 15 | schoolid1 = factor(schoolid1)) %>% 16 | 17 | # limit to urban schools 18 | filter(school1=="urban") %>% 19 | 20 | # re-shape to long format 21 | gather(key = "test", value = "score", read1, math1) 22 | 23 | # seemingly unrelated regression 24 | 25 | lm_STAR <- lm(score ~ test:(0 + schoolid1 + gender + ethnicity + birth + lunch1 + star1), data = STAR_1st_urban) 26 | 27 | # joint test for small class effects on reading and math 28 | 29 | small_class_coefs <- which(grepl("star1small", names(coef(lm_STAR)))) 30 | 31 | 32 | # clustering by student 33 | 34 | Wald_test(lm_STAR, constraints = small_class_coefs, 35 | vcov = "CR2", cluster = STAR_1st_urban$student_id, 36 | test = "HTZ") 37 | 38 | # clustering by school 39 | 40 | Wald_test(lm_STAR, constraints = small_class_coefs, 41 | vcov = "CR2", cluster = STAR_1st_urban$schoolid1, 42 | test = "HTZ") 43 | 44 | -------------------------------------------------------------------------------- /auxilliary/Shores_test.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(haven) 3 | library(plm) 4 | library(clubSandwich) 5 | 6 | Shores <- 7 | read_dta("auxilliary/Shores_test.dta") %>% 8 | rename(W = `_W_Weight`) 9 | 10 | Shores_fit <- plm(delta ~ treat + factor(year), data = Shores, 11 | weights = W, 12 | index = c("fips","year"), 13 | effect = "individual") 14 | summary(Shores_fit) 15 | coef_test(Shores_fit, vcov = "CR2") 16 | -------------------------------------------------------------------------------- /auxilliary/Shores_test.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/Shores_test.dta -------------------------------------------------------------------------------- /auxilliary/absorption issue - unweighted.R: -------------------------------------------------------------------------------- 1 | set.seed(20220926) 2 | m <- 4 # number of clusters 3 | ni <- 2 + rpois(m, 3.5) # cluster sizes 4 | N <- sum(ni) # total sample size 5 | id <- factor(rep(LETTERS[1:m], ni)) # cluster ID 6 | R <- rnorm(N) # focal predictor 7 | dat <- data.frame(R, id) # create raw data frame 8 | X <- model.matrix(~ R + id + 0, data = dat) # full predictor matrix 9 | Ui <- tapply(R, id, \(x) x - mean(x)) # absorbed version of R 10 | U <- unsplit(Ui, id) 11 | matrix_power <- function(x, p) { 12 | eig <- eigen(x, symmetric = TRUE) 13 | val_p <- with(eig, ifelse(values > 10^-12, values^p, 0)) 14 | with(eig, vectors %*% (val_p * t(vectors))) 15 | } 16 | 17 | MX <- solve(crossprod(X)) 18 | B <- 19 | by(X, id, as.matrix) |> 20 | lapply(\(x) diag(nrow(x)) - x %*% MX %*% t(x)) 21 | A <- lapply(B, matrix_power, p = -1/2) 22 | 23 | MU <- 1 / crossprod(U) 24 | Btilde <- lapply(Ui, \(x) diag(length(x)) - x %*% MU %*% t(x)) 25 | Atilde <- lapply(Btilde, matrix_power, p = -1/2) 26 | 27 | all.equal(A, Atilde) 28 | 29 | UiAtilde <- mapply(\(u, a) t(u) %*% a, u = Ui, a = Atilde, SIMPLIFY = FALSE) 30 | UiA <- mapply(\(u, a) t(u) %*% a, u = Ui, a = A, SIMPLIFY = FALSE) 31 | all.equal(UiAtilde, UiA) 32 | 33 | Tmat <- model.matrix(~ 0 + id) 34 | Ti <- by(Tmat, id, as.matrix) 35 | MT <- solve(crossprod(Tmat)) 36 | tiMTtit <- lapply(Ti, \(x) x %*% MT %*% t(x)) 37 | B_alt <- mapply(`-`, Btilde, tiMTtit) 38 | all.equal(B, B_alt) 39 | 40 | mapply(\(a, t) a %*% t, a = Atilde, t = Ti) 41 | -------------------------------------------------------------------------------- /auxilliary/absorption issue - weighted.R: -------------------------------------------------------------------------------- 1 | library(lme4) 2 | set.seed(20221007) 3 | J <- 5 4 | nj <- 2 + rpois(J, 3) 5 | N <- sum(nj) 6 | 7 | id <- factor(rep(LETTERS[1:J], nj)) 8 | tm <- unsplit(lapply(nj, \(x) 1:x), id) 9 | bU <- rnorm(J, mean = 1)[id] + rnorm(J, mean = 0.25, sd = 0.25)[id] * tm 10 | vU <- cbind(rnorm(J, mean = 0.25)[id], rnorm(J, mean = 0.4)[id]) 11 | Umat <- matrix(rnorm(2 * N, mean = bU), N, 2) 12 | U_list <- matrix_list(Umat, id, "row") 13 | T_list <- matrix_list(cbind(1, tm), id, "row") 14 | T_full <- matrix_list(model.matrix(~ 0 + id + id:tm), id, "row") 15 | 16 | bT <- rnorm(J, mean = 1)[id] + rnorm(J, mean = 0.25, sd = 0.25)[id] * tm 17 | y <- rowSums(Umat) + bT + rowSums(Umat * vU) + rnorm(N) 18 | y_list <- matrix_list(as.matrix(y), id, "row") 19 | 20 | dat <- cbind(data.frame(y, id, tm), U = Umat) 21 | 22 | lme_dummy <- lmer(y ~ 0 + id + id:tm + U.1 + U.2 + (0 + U.1 + U.2 || id), data = dat) 23 | summary(lme_dummy) 24 | r_list <- split(residuals_CS(lme_dummy), id) 25 | W_list <- weightMatrix(lme_dummy) 26 | Phi_list <- targetVariance(lme_dummy, cluster = id) 27 | D_list <- lapply(Phi_list, chol) 28 | D_inv <- lapply(D_list, solve) 29 | 30 | # Absorbed matrices 31 | reg_by <- function(x, w, y) { 32 | lhs <- t(x) %*% w %*% x 33 | rhs <- t(x) %*% w %*% y 34 | beta <- solve(lhs, rhs) 35 | y - x %*% beta 36 | } 37 | U_dot <- mapply(reg_by, x = T_list, w = W_list, y = U_list) 38 | y_dot <- mapply(reg_by, x = T_list, w = W_list, y = y_list) 39 | dat_absorb <- data.frame(U = do.call(rbind, U_dot), y = do.call(rbind, y_dot), id) 40 | 41 | # Should be 2X2 matrices of zeros 42 | mapply(function(x, w, y) round(t(x) %*% w %*% y, 8), 43 | x = T_list, w = W_list, y = U_dot, SIMPLIFY = FALSE) 44 | 45 | # Calculate absorbed beta coefficients 46 | UtWU <- 47 | Map(function(x, w) t(x) %*% w %*% x, x = U_dot, w = W_list) %>% 48 | Reduce("+", .) 49 | 50 | MUd <- chol2inv(chol(UtWU)) 51 | 52 | beta <- 53 | Map(function(x, w, y) t(x) %*% w %*% y, x = U_dot, w = W_list, y = y_dot) %>% 54 | Reduce("+", .) %>% 55 | solve(UtWU, .) 56 | 57 | as.vector(beta) 58 | fixef(lme_dummy)[c("U.1","U.2")] 59 | 60 | # Calculate adjustment matrices by hand 61 | 62 | TtWT_list <- Map(function(x, w) t(x) %*% w %*% x, x = T_full, w = W_list) 63 | TtWT <- Reduce("+", TtWT_list) 64 | MT <- chol2inv(chol(TtWT)) 65 | TMTTt <- Map(\(x) x %*% MT %*% t(x), x = T_full) 66 | 67 | # Omit the D matrices 68 | B_list <- Map(function(phi, u, tmat) (phi - u %*% MUd %*% t(u) - tmat %*% MT %*% t(tmat)), 69 | phi = Phi_list, u = U_dot, tmat = T_full) 70 | B_ginv <- Map(matrix_power, B_list, p = -1) 71 | 72 | Btilde_list <- Map(function(phi, u) (phi - u %*% MUd %*% t(u)), 73 | phi = Phi_list, u = U_dot) 74 | Btilde_ginv <- Map(matrix_power, Btilde_list, p = -1) 75 | 76 | WTMTTtW <- Map(\(w, t) w %*% t %*% w, w = W_list, t = TMTTt) 77 | B2_ginv <- Map(`-`, Btilde_ginv, WTMTTtW) 78 | all.equal(B_ginv, B2_ginv) # should be equal? 79 | B_ginv[[2]] 80 | B2_ginv[[2]] 81 | B_ginv[[2]] - B2_ginv[[2]] 82 | 83 | # Now with the D matrices 84 | B_list <- Map(function(d, phi, u, tmat) d %*% (phi - u %*% MUd %*% t(u) - tmat %*% MT %*% t(tmat)) %*% t(d), 85 | d = D_list, phi = Phi_list, u = U_dot, tmat = T_full) 86 | B_ginv <- Map(matrix_power, B_list, p = -1) 87 | 88 | Btilde_list <- Map(function(d, phi, u, tmat) d %*% (phi - u %*% MUd %*% t(u)) %*% t(d), 89 | d = D_list, phi = Phi_list, u = U_dot, tmat = T_full) 90 | Btilde_ginv <- Map(matrix_power, Btilde_list, p = -1) 91 | 92 | 93 | A_list <- Map(\(b, d) t(d) %*% matrix_power(b, p = -1/2) %*% d, b = B_list, d = D_list) 94 | club_A <- attr(vcovCR(lme_dummy, type = "CR2"), "adjustments") 95 | all.equal(A_list, club_A, check.attributes = FALSE) # Adjustment matrices agree with clubSandwich 96 | 97 | Atilde_list <- Map(\(b, d) t(d) %*% matrix_power(b, p = -1/2) %*% d, b = Btilde_list, d = D_list) 98 | all.equal(A_list, Atilde_list) # A should not be equal to Atilde 99 | 100 | UtWA <- Map(\(u,w,a) t(u) %*% w %*% a, u = U_dot, w = W_list, a = A_list) 101 | UtWAtilde <- Map(\(u,w,a) t(u) %*% w %*% a, u = U_dot, w = W_list, a = Atilde_list) 102 | all.equal(UtWA, UtWAtilde) 103 | UtWA[[4]] 104 | UtWAtilde[[4]] 105 | 106 | E_list <- Map(\(uwa, r) as.vector(uwa %*% r), uwa = UtWA, r = r_list) 107 | Etilde <- Map(\(uwa, r) as.vector(uwa %*% r), uwa = UtWAtilde, r = r_list) 108 | -------------------------------------------------------------------------------- /auxilliary/cluster-wild-bootstrap.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Algorithm for cluster wild bootstrap" 3 | author: "James E. Pustejovsky" 4 | date: "March 16, 2017" 5 | output: html_document 6 | --- 7 | 8 | Consider the model 9 | $$ 10 | \mathbf{y}_j = \mathbf{T}_j \boldsymbol\alpha + \mathbf{U}_j \boldsymbol\beta + \mathbf{e}_j, \quad \text{where} \quad \mathbf{e}_j \sim N(\mathbf{0}, \boldsymbol\Sigma) 11 | $$ 12 | for $j = 1,...,m$, and where $\mathbf{e}_j$ is independent of $\mathbf{e}_k$ for $j \neq k$. We will estimate the model using weighted least squares with fixed weight matrices $\mathbf{W}_1,...,\mathbf{W}_m$. 13 | Suppose that we want to test the hypothesis that $\boldsymbol\beta = \mathbf{0}$. We will use the wild bootstrap, generating bootstrap samples under the null hypothesis. Begin by calculating 14 | $$ 15 | \boldsymbol{\tilde\alpha} = \mathbf{M_T} \mathbf{T}'\mathbf{W}\mathbf{y}, 16 | $$ 17 | where $\mathbf{M_T} = \left(\mathbf{T}'\mathbf{W}\mathbf{T}\right)^{-1}$. The residuals under the null model are 18 | $$ 19 | \mathbf{\tilde{e}} = \mathbf{y} - \mathbf{T}\boldsymbol{\tilde\alpha} = \left(\mathbf{I} - \mathbf{H_T}\right) \mathbf{y}. 20 | $$ 21 | where $\mathbf{H_T} = \mathbf{T} \mathbf{M_T} \mathbf{T}' \mathbf{W}$. 22 | 23 | # Wald test statistic 24 | 25 | Now to the hypothesis test. We'll first need to get the WLS estimate of $\boldsymbol\beta$ and the residuals from the full regression. This can be done efficiently as follows. Let $\mathbf{\ddot{U}}$ be the residuals from the WLS regression of $\mathbf{U}$ on $\mathbf{T}$, i.e., 26 | $$ 27 | \mathbf{\ddot{U}} = \left(\mathbf{I} - \mathbf{H_T}\right)\mathbf{U}. 28 | $$ 29 | The WLS estimate of $\boldsymbol\beta$ can be calculated by taking the WLS regression of $\mathbf{\tilde{e}}$ on $\mathbf{\ddot{U}}$: 30 | $$ 31 | \boldsymbol{\hat\beta} = \mathbf{M_{\ddot{U}}} \mathbf{\ddot{U}}' \mathbf{W} \mathbf{\tilde{e}}, 32 | $$ 33 | where $\mathbf{M_{\ddot{U}}} = \left(\mathbf{\ddot{U}}' \mathbf{W} \mathbf{\ddot{U}}\right)^{-1}$. The residuals can also be calculated as 34 | $$ 35 | \mathbf{\hat{e}} = \mathbf{\tilde{e}} - \mathbf{\ddot{U}}\boldsymbol{\hat\beta}. 36 | $$ 37 | With these quantities, calculate the robust variance-covariance matrix 38 | $$ 39 | \mathbf{V} = \mathbf{M_{\ddot{U}}}\left(\sum_{j=1}^m \mathbf{\ddot{U}}_j' \mathbf{W}_j \mathbf{A}_j \mathbf{\hat{e}}_j \mathbf{\hat{e}}_j' \mathbf{A}_j \mathbf{W}_j \mathbf{\ddot{U}}_j \right)\mathbf{M_{\ddot{U}}}, 40 | $$ 41 | where $\mathbf{A}_1,...,\mathbf{A}_m$ are some adjustment matrices (these could be identity matrices or the BRL adjustment matrices). Then calculate the Wald test statistic 42 | $$ 43 | Q = \boldsymbol{\hat\beta}' \mathbf{V}^{-1} \boldsymbol{\hat\beta}. 44 | $$ 45 | 46 | # Bootstrap 47 | 48 | We will use the cluster wild bootstrap to approximate the null sampling distribution of $Q$. This entails repeatedly generating new data 49 | $$ 50 | \mathbf{y}_j^* = \mathbf{T}_j \boldsymbol{\tilde\alpha} + \eta_j \mathbf{B}_j \boldsymbol{\tilde{e}}_j, 51 | $$ 52 | where $\eta_1,...,\eta_m$ are sampled from some auxilliary distribution (i.e., the Rademacher distribution or Webb's 6-point distribution) and $\mathbf{B}_1,...,\mathbf{B}_m$ are some adjustment matrices calculated based on the null model (these could be identity matrices, the BRL adjustment matrices, the approximate jackknife adjustment, etc.). We then re-calculate $\boldsymbol{\hat\beta}$, $\mathbf{V}^{CR}$, and $Q$ based on the bootstrapped $\mathbf{y}^*$. 53 | 54 | This can be done efficiently as follows: 55 | 56 | 1. When first calculating $\boldsymbol{\hat\beta}$, save the matrices $\mathbf{M_{\ddot{U}}}$, $\mathbf{E}_j' = \mathbf{\ddot{U}}_j'\mathbf{W}_j$, and $\mathbf{G}_j' = \mathbf{E}_j' \mathbf{A}_j$ for later use. 57 | 2. Calculate $\mathbf{f}_j = \mathbf{B}_j \boldsymbol{\tilde{e}}_j$ 58 | 3. For $b = 1,...,B$: 59 | a. Calculate $\mathbf{e}_j^{(b)} = \eta_j \mathbf{f}_j$. 60 | b. Calculate $\boldsymbol{\hat\beta}^{(b)} = \mathbf{M_{\ddot{U}}} \sum_{j=1}^m \mathbf{E}_j \mathbf{e}_j^{(b)}$. 61 | c. Calculate $\mathbf{\hat{e}}_j^{(b)} = \mathbf{e}_j^{(b)} - \mathbf{\ddot{U}}_j \boldsymbol{\hat\beta}^{(b)}$. 62 | d. Calculate $\mathbf{V}^{(b)} = \mathbf{M_{\ddot{U}}}\left(\sum_{j=1}^m \mathbf{G}_j'\mathbf{\hat{e}}_j^{(b)} \left(\mathbf{\hat{e}}_j^{(b)}\right)' \mathbf{G}_j\right)\mathbf{M_{\ddot{U}}}$ 63 | e. Calculate $Q^{(b)} = \left(\boldsymbol{\hat\beta}^{(b)}\right)' \left(\mathbf{V}^{(b)}\right)^{-1} \boldsymbol{\hat\beta}^{(b)}$. 64 | 4. Calculate the p-value corresponding to $H_0$ as 65 | $$ 66 | p = \frac{1}{B} \sum_{b = 1}^B I\left(Q > Q^{(b)}\right) 67 | $$ 68 | 69 | -------------------------------------------------------------------------------- /auxilliary/deaths.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/deaths.dta -------------------------------------------------------------------------------- /auxilliary/equivalence of robumeta and clubSandwich.R: -------------------------------------------------------------------------------- 1 | library(robumeta) 2 | library(metafor) 3 | library(clubSandwich) 4 | 5 | # fit a simple meta-analysis model using robumeta 6 | 7 | data(corrdat) 8 | corrdat$studyid <- factor(corrdat$studyid) 9 | 10 | robu_fit <- robu(effectsize ~ 1, data = corrdat, 11 | modelweights = "CORR", studynum = studyid, 12 | var.eff.size = var) 13 | robu_fit 14 | 15 | # note value of tau^2 16 | tau_sq_robu <- as.numeric(robu_fit$mod_info$tau.sq) 17 | 18 | # fit the same specification using rma.uni 19 | rma_uni_fit <- rma.uni(yi = effectsize, vi = var, data = corrdat) 20 | 21 | # different estimate of tau^2 22 | rma_uni_fit$tau2 23 | 24 | # robust standard error from metafor 25 | robust(rma_uni_fit, cluster = corrdat$studyid, adjust = TRUE) 26 | 27 | # you can get the same robust SE from clubSandwich using vcov = "CR1" 28 | coef_test(rma_uni_fit, cluster = corrdat$studyid, vcov = "CR1") 29 | 30 | # Using the more accurate small-sample approximation vcov = "CR2" 31 | # leads to slightly larger SE 32 | coef_test(rma_uni_fit, cluster = corrdat$studyid, vcov = "CR2") 33 | 34 | # calculate the inverse of the weight used by robumeta 35 | corrdat$k <- with(corrdat, table(studyid)[studyid]) 36 | corrdat$Vbar <- with(corrdat, tapply(var, studyid, mean)[studyid]) 37 | corrdat$Vij <- with(corrdat, as.numeric(k * (Vbar + tau_sq_robu))) 38 | 39 | # use the robumeta weights in rma.uni 40 | rma_uni_robu <- rma.uni(yi = effectsize, vi = Vij, data = corrdat, method = "FE") 41 | 42 | # average effect size estimates now agree 43 | rma_uni_robu$beta 44 | robu_fit$reg_table$b.r 45 | 46 | # have to use "CR2" to get the standard errors to agree 47 | coef_test(rma_uni_robu, cluster = corrdat$studyid, vcov = "CR2") 48 | sqrt(vcovCR(rma_uni_robu, cluster = corrdat$studyid, type = "CR2")) 49 | robu_fit$reg_table$SE 50 | 51 | # the robumeta model is closer to the following multivariate model 52 | V_mat <- with(corrdat, impute_covariance_matrix(vi = var, cluster = studyid, r = 0.7)) 53 | rma_mv_fit <- rma.mv(yi = effectsize, V = V_mat, data = corrdat, 54 | random = ~ studyid) 55 | coef_test(rma_mv_fit, cluster = corrdat$studyid, vcov = "CR2") 56 | -------------------------------------------------------------------------------- /auxilliary/es_data.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/es_data.RData -------------------------------------------------------------------------------- /auxilliary/example for plm.R: -------------------------------------------------------------------------------- 1 | library(plm) 2 | data("Produc") 3 | 4 | plm_individual <- plm(log(gsp) ~ log(pcap) + log(pc) + log(emp) + unemp, 5 | data = Produc, index = c("state","year","region"), 6 | effect = "individual", model = "random") 7 | 8 | plm_vcov <- vcovHC(plm_individual, method="arellano", type = "HC0", cluster = "group") 9 | club_vcov <- vcovCR(plm_individual, cluster = "individual", type = "CR0") 10 | all.equal(plm_vcov, as.matrix(club_vcov), check.attributes = FALSE) 11 | 12 | plm_nested <- plm(log(gsp) ~ log(pcap) + log(pc) + log(emp) + unemp, 13 | data = Produc, index = c("state","year","region"), 14 | effect = "nested", model = "random") 15 | 16 | plm_vcov <- vcovHC(plm_nested, method="arellano", type = "HC0", cluster = "group") 17 | club_vcov <- vcovCR(plm_nested, cluster = "group", type = "CR0") 18 | all.equal(plm_vcov, as.matrix(club_vcov), check.attributes = FALSE) 19 | -------------------------------------------------------------------------------- /auxilliary/iv example.R: -------------------------------------------------------------------------------- 1 | library(AER) 2 | data("CigarettesSW") 3 | Cigs <- within(CigarettesSW, { 4 | packs_log <- log(packs) 5 | rprice_log <- log(price/cpi) 6 | rincome_log <- log(income/population/cpi) 7 | tdiff <- (taxs - tax)/cpi 8 | }) 9 | 10 | iv_fit <- ivreg(packs_log ~ rprice_log + rincome_log | 11 | rincome_log + tdiff, data = Cigs) 12 | vcovCR(iv_fit, cluster = Cigs$state, type = "CR2") 13 | coef_test(iv_fit, vcov = "CR2", cluster = Cigs$state) 14 | 15 | sur_fit <- lm(cbind(packs_log, rprice_log) ~ rincome_log + tdiff, data = Cigs) 16 | (V_sur <- vcovCR(sur_fit, cluster = Cigs$state, type = "CR2")) 17 | coef_test(sur_fit, vcov = "CR2", cluster = Cigs$state) 18 | 19 | (a <- coef_CS(sur_fit)[["rprice_log:tdiff"]]) 20 | (b <- coef_CS(sur_fit)[["packs_log:tdiff"]]) 21 | (d <- coef_CS(iv_fit)[["rprice_log"]]) 22 | b / a 23 | all.equal(d, b / a) 24 | 25 | (V_iv <- vcovCR(iv_fit, cluster = Cigs$state, type = "CR2")["rprice_log","rprice_log"]) 26 | (V_delta <- (V_sur["packs_log:tdiff","packs_log:tdiff"] + 27 | d^2 * V_sur["rprice_log:tdiff","rprice_log:tdiff"] - 28 | 2 * d * V_sur["rprice_log:tdiff","packs_log:tdiff"]) / a^2) 29 | all.equal(V_iv, V_delta) 30 | -------------------------------------------------------------------------------- /auxilliary/mice_pooling_example.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(clubSandwich) 3 | library(mice) 4 | library(mlmRev) 5 | rm(list=ls()) 6 | 7 | data(bdf) 8 | 9 | # create missing values to impute 10 | 11 | bdf$langPRET[sample(1:nrow(bdf),75)] = NA 12 | bdf_subset = bdf[,c("schoolNR", "IQ.verb", "IQ.perf", "sex", "Minority", "langPRET", "langPOST")] 13 | 14 | 15 | # impute missing values 16 | 17 | Impute_bdf <- mice(bdf_subset, m=28, meth="norm.nob", seed=24) 18 | 19 | 20 | # fit and pool results based on homoskedastic variance-covariance estimates 21 | 22 | models_fragile <- with(data = Impute_bdf, lm(langPOST ~ langPRET + Minority + sex + IQ.perf + IQ.verb)) 23 | 24 | models_fragile %>% 25 | pool() %>% 26 | summary() 27 | 28 | 29 | # fit results with clubSandwich standard errors 30 | 31 | models_robust <- with(data=Impute_bdf, 32 | lm(langPOST ~ langPRET + Minority + sex + IQ.perf + IQ.verb) %>% 33 | coef_test(cluster=bdf_subset$schoolNR, vcov="CR2", test="Satterthwaite") 34 | ) 35 | 36 | 37 | # pool results with clubSandwich standard errors 38 | 39 | models_robust$analyses %>% 40 | 41 | # add coefficient names as a column 42 | lapply(function(x) { 43 | x$coef <- row.names(x) 44 | x 45 | }) %>% 46 | bind_rows() %>% 47 | as.data.frame() %>% 48 | 49 | # summarize by coefficient 50 | group_by(coef) %>% 51 | summarise( 52 | m = n(), 53 | V_betw = var(beta), 54 | est = mean(beta), 55 | V_com = mean(SE^2), 56 | df_com = mean(df) 57 | ) %>% 58 | 59 | mutate( 60 | 61 | # calculate intermediate quantities to get df 62 | V_total = V_com + (1 + 1 / m) * V_betw, 63 | fmi = (1 + 1 / m) * V_betw / V_total, 64 | df_m = (m - 1) / fmi^2, 65 | lambda = (df_com + 1) / (df_com + 3), 66 | df_obs = lambda * df_com * (1 - fmi), 67 | df = 1 / (1 / df_m + 1 / df_obs), 68 | 69 | # calculate summary quantities for output 70 | se = sqrt(V_total), 71 | t = est / se, 72 | p_val = 2 * pt(abs(t), df = df, lower.tail = FALSE), 73 | crit = qt(0.975, df = df), 74 | lo95 = est - se * crit, 75 | hi95 = est + se * crit 76 | ) %>% 77 | select(coef, est, t, df_com, df, p_val, lo95, hi95, fmi) 78 | 79 | # note I left df_com (average of the complete data degrees of freedom) in there for comparison purposes -------------------------------------------------------------------------------- /auxilliary/prep Achievement Awards Demonstration data.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(tidyr) 3 | library(foreign) 4 | 5 | filenames <- paste0("auxilliary/AngristLavy_AERdata/base",c("99","00","01","02"), ".dta") 6 | 7 | possible_units <- c(0,18,20,22,24) 8 | 9 | qntl <- function(x, groups = 4) { 10 | qtl <- quantile(x, (0:groups) / groups) 11 | if (length(unique(qtl)) == (groups + 1)) { 12 | print(paste(qtl, collapse = " ")) 13 | cut(x, breaks = qtl, labels = 1:groups, include.lowest = TRUE, right = FALSE, ordered_result = TRUE) 14 | } else { 15 | NA 16 | } 17 | } 18 | 19 | AchievementAwardsRCT <- 20 | lapply(filenames, read.dta) %>% 21 | bind_rows() %>% 22 | mutate(year = factor(year, levels = c(99,0,1,2), labels = 1999:2002), 23 | school_type = factor(ifelse(semrel, "Religious", ifelse(semarab, "Arab","Secular"))), 24 | student_id = paste0(year,"-",student_id), 25 | sex = ifelse(boy==1, "Boy","Girl"), 26 | attempted = possible_units[1 + att18 + att20 + att22 + att24], 27 | awarded = possible_units[1 + awr18 + awr20 + awr22 + awr24]) %>% 28 | select(school_id, school_type, pair, treated, year, student_id, pair, 29 | sex, siblings = m_ahim, immigrant = ole5, father_ed = educav, mother_ed = educem, 30 | Bagrut_status = zakaibag, attempted, awarded , achv_math, achv_english = achv_eng, achv_hebrew = achv_hib, 31 | lagscore) %>% 32 | group_by(year, sex) %>% 33 | mutate(qrtl = qntl(lagscore, groups = 4), 34 | half = qntl(lagscore, groups = 2)) %>% 35 | ungroup() 36 | 37 | with(AchievementAwardsRCT, table(year, sex)) 38 | with(AchievementAwardsRCT, table(year, qrtl, sex)) 39 | with(AchievementAwardsRCT, table(year, half, sex)) 40 | 41 | save(AchievementAwardsRCT, file = "data/AchievementAwardsRCT.RData", compress = "xz") 42 | head(AchievementAwardsRCT) 43 | -------------------------------------------------------------------------------- /auxilliary/prep Kalaian data.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(tidyr) 3 | library(readr) 4 | 5 | SATcoaching <- 6 | read_csv("auxilliary/Kalaian-Raudenbush-1996.csv") %>% 7 | gather("test","d", SATV, SATM) %>% 8 | mutate(test = ifelse(test == "SATV", "Verbal", "Math")) %>% 9 | filter(!is.na(d)) %>% 10 | arrange(study_type, study, test) %>% 11 | mutate(nT = ifelse(study=="Whitla" & test=="Math", 50, nT), 12 | nC = ifelse(study=="Whitla" & test=="Math", 50, nC), 13 | V = round(1 / nT + 1 / nC + d^2 / (2 * (nC + nT)), 4)) %>% 14 | select(study, year, test, d, V, nT, nC, study_type, hrs, ETS, homework) %>% 15 | as.data.frame() 16 | 17 | save(SATcoaching, file = "data/SATcoaching.RData", compress = "xz") 18 | head(SATcoaching) 19 | dim(SATcoaching) 20 | -------------------------------------------------------------------------------- /auxilliary/prep Wilson data.R: -------------------------------------------------------------------------------- 1 | library(plyr) 2 | library(foreign) 3 | library(robumeta) 4 | rm(list=ls()) 5 | 6 | Wilson <- droplevels(read.spss("auxilliary/Dropout Dataset for Tipton and Pustejovsky.sav", to.data.frame = TRUE)) 7 | Wilson <- rename(Wilson, replace = 8 | c("attritionimp" = "attrition", "LGEimp" = "group_equivalence", 9 | "es50r" = "adjusted","g10i" = "evaluator_independence", 10 | "g42_TXimp" = "male_pct", "g43a_TXimp" = "white_pct", 11 | "g46_TXimp" = "average_age", "g30" = "implementation_quality", 12 | "g20imp" = "duration", "g24imp" = "service_hrs", 13 | "g6r" = "Program_type")) 14 | 15 | Wilson <- within(Wilson, { 16 | levels(implementation_quality) <- c("Clear problems","Possible problems","No apparent problems") 17 | levels(evaluator_independence) <- c("Independent","Indirect, influential","Planning","Delivery") 18 | program_site <- factor(ifelse(class == 1, "school classroom", 19 | ifelse(outclass == 1, "school, outside of classroom", 20 | ifelse(mixed == 1, "mixed", "community")))) 21 | outcome <- factor(ifelse(dropout == 1 , "dropout", 22 | ifelse(grad == 1, "graduation", 23 | ifelse(gradged == 1, "graduation/ged", "enrolled")))) 24 | study_design <- factor(ifelse(random==1, "Randomized", 25 | ifelse(matched == 1, "Matched", "Non-random, non-matched"))) 26 | studyID <- factor(studyid) 27 | studySample <- factor(StudyGroup) 28 | }) 29 | 30 | Wilson <- arrange(Wilson, studyID, studySample) 31 | Wilson <- subset(Wilson, select = c(LOR1, varLOR, studyID, studySample, 32 | study_design, outcome, evaluator_independence, implementation_quality, 33 | program_site, attrition, group_equivalence, adjusted, 34 | male_pct, white_pct, average_age, duration, service_hrs)) 35 | 36 | ES_per_sample <- ddply(Wilson, .(studyID, studySample), nrow) 37 | table(table(ES_per_sample$studyID)) 38 | ES_per_study <- ddply(Wilson, .(studyID), nrow) 39 | table(ES_per_study$V1) 40 | big_studies <- subset(ES_per_study, V1 > 2)$studyID 41 | Wilson$big_study <- Wilson$studyID %in% big_studies 42 | 43 | dropoutPrevention <- Wilson 44 | save(dropoutPrevention, file = "data/dropoutPrevention.RData", compress = "xz") 45 | write.csv(dropoutPrevention, file = "auxilliary/dropoutPrevention.csv") 46 | 47 | names(dropoutPrevention) 48 | table(dropoutPrevention$study_design) 49 | table(dropoutPrevention$outcome) 50 | table(dropoutPrevention$evaluator_independence) 51 | table(dropoutPrevention$implementation_quality) 52 | table(dropoutPrevention$program_format) 53 | summary(dropoutPrevention$attrition) 54 | summary(dropoutPrevention$group_equivalence) 55 | table(dropoutPrevention$adjusted) 56 | summary(dropoutPrevention$male_pct) 57 | summary(dropoutPrevention$white_pct) 58 | summary(dropoutPrevention$average_age) 59 | summary(dropoutPrevention$duration) 60 | summary(dropoutPrevention$service_hrs) 61 | table(dropoutPrevention$big_study) 62 | 63 | 64 | -------------------------------------------------------------------------------- /auxilliary/prep motor vehicle crash data.R: -------------------------------------------------------------------------------- 1 | library(foreign) 2 | library(dplyr) 3 | 4 | MortalityRates <- 5 | read.dta("http://masteringmetrics.com/wp-content/uploads/2015/01/deaths.dta", 6 | convert.factors=FALSE) %>% 7 | filter(dtype %in% c(1,2,3,6) & agegr==2) %>% 8 | mutate(cause = factor(dtype, labels = c("All","Motor Vehicle","Suicide","Internal"))) %>% 9 | select(-dtype, -agegr, -age, -legal1820) 10 | 11 | save(MortalityRates, file = "data/MortalityRates.RData", compress = "xz") 12 | dim(MortalityRates) 13 | head(MortalityRates) -------------------------------------------------------------------------------- /auxilliary/quasi-experiment example.R: -------------------------------------------------------------------------------- 1 | library(plm) 2 | # library(clubSandwich) 3 | devtools::load_all() 4 | 5 | rm(list=ls()) 6 | load("auxilliary/quasi-experiment.Rdata") 7 | 8 | d_p <- plm.data(d, indexes=c("sgrp")) 9 | 10 | p <- plm(y ~ treat + frl, data = d_p, effect="individual", model="within", index="sgrp") 11 | 12 | system.time(CR1_t <- coef_test(p, vcov = "CR1", cluster = d_p$cid, test = "naive-t")) 13 | system.time(CR1a_Satt <- coef_test(p, vcov = "CR1", cluster = d_p$cid, test = "Satterthwaite")) 14 | system.time(CR1b_Satt <- coef_test(p, vcov = "CR1", cluster = d_p$cid, test = "Satterthwaite", ignore_FE = TRUE)) 15 | # system.time(CR1_Satt_old <- coef_test_old(p, vcov = "CR1", cluster = d$cid, test = "Satterthwaite")) 16 | CR1_t 17 | CR1a_Satt 18 | CR1b_Satt 19 | 20 | system.time(CR2_t <- coef_test(p, vcov = "CR2", cluster = d_p$cid, test = "naive-t")) 21 | system.time(CR2a_Satt <- coef_test(p, vcov = "CR2", cluster = d_p$cid, test = "Satterthwaite")) 22 | system.time(CR2b_Satt <- coef_test(p, vcov = "CR2", cluster = d_p$cid, test = "Satterthwaite", ignore_FE = TRUE)) 23 | # system.time(CR2_Satt_old <- coef_test_old(p, vcov = "CR2", cluster = d$cid, test = "Satterthwaite")) 24 | CR2_t 25 | CR2a_Satt 26 | CR2b_Satt 27 | 28 | library(dplyr) 29 | d %>% 30 | group_by(cid) %>% 31 | summarise(n = n(), trtd = mean(treat)) %>% 32 | group_by(trtd) %>% 33 | summarise(schools = n(), students = sum(n)) 34 | -------------------------------------------------------------------------------- /auxilliary/quasi-experiment.Rdata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/auxilliary/quasi-experiment.Rdata -------------------------------------------------------------------------------- /auxilliary/run_clustered_iv_sim.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #SBATCH -J CRVE # Job name 3 | #SBATCH -o CRT-IV.o%j # Name of stdout output file (%j expands to jobId) 4 | #SBATCH -e CRT-IV.o%j # Name of stderr output file(%j expands to jobId) 5 | #SBATCH -p development # Submit to the 'normal' or 'development' queue 6 | #SBATCH -N 3 # Total number of nodes 7 | #SBATCH -n 180 # Total number of mpi tasks requested 8 | #SBATCH -t 1:00:00 # Run time (hh:mm:ss) 9 | #SBATCH --mail-user=jepusto@gmail.com 10 | #SBATCH --mail-type=begin 11 | #SBATCH --mail-type=end 12 | 13 | # load R module 14 | module load Rstats 15 | 16 | # call R code from RMPISNOW 17 | ibrun RMPISNOW < "./iv simulation - cluster-level non-compliance.R" 18 | -------------------------------------------------------------------------------- /auxilliary/run_multisite_iv_sim.slurm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #SBATCH -J CRVE # Job name 3 | #SBATCH -o RB-IV.o%j # Name of stdout output file (%j expands to jobId) 4 | #SBATCH -e RB-IV.o%j # Name of stderr output file(%j expands to jobId) 5 | #SBATCH -p normal # Submit to the 'normal' or 'development' queue 6 | #SBATCH -N 4 # Total number of nodes 7 | #SBATCH -n 256 # Total number of mpi tasks requested 8 | #SBATCH -t 5:00:00 # Run time (hh:mm:ss) 9 | #SBATCH --mail-user=jepusto@gmail.com 10 | #SBATCH --mail-type=begin 11 | #SBATCH --mail-type=end 12 | 13 | # load R module 14 | module load Rstats 15 | 16 | # call R code from RMPISNOW 17 | ibrun RMPISNOW < "./iv simulation - multi-site non-compliance.R" 18 | -------------------------------------------------------------------------------- /auxilliary/scratch.R: -------------------------------------------------------------------------------- 1 | 2 | impute_covariance_matrix <- function(vi, cluster, r, return_list = identical(as.factor(cluster), sort(as.factor(cluster)))) { 3 | 4 | vi_list <- split(vi, cluster) 5 | r_list <- rep_len(r, length(vi_list)) 6 | vcov_list <- Map(function(V, rho) (rho + diag(1 - rho, nrow = length(V))) * tcrossprod(sqrt(V)), V = vi_list, rho = r_list) 7 | 8 | if (return_list) { 9 | return(vcov_list) 10 | } else { 11 | vcov_mat <- metafor::bldiag(vcov_list) 12 | cluster_index <- order(order(cluster)) 13 | return(vcov_mat[cluster_index, cluster_index]) 14 | } 15 | } 16 | 17 | library(dplyr) 18 | data(SATcoaching, package = "clubSandwich") 19 | 20 | mean_hrs_ln <- 21 | SATcoaching %>% 22 | group_by(study) %>% 23 | summarise(hrs_ln = mean(log(hrs))) %>% 24 | summarise(hrs_ln = mean(hrs_ln, na.rm = TRUE)) 25 | 26 | SATcoaching <- 27 | SATcoaching %>% 28 | # clean variables 29 | mutate( 30 | study = as.factor(study), 31 | hrs_ln = log(hrs) - mean_hrs_ln$hrs_ln 32 | ) %>% 33 | # sort by study ID 34 | arrange(study, test) 35 | 36 | V_list <- with(SATcoaching, impute_covariance_matrix(vi = V, cluster = study, r = 0.66)) 37 | MVFE_hrs <- rma.mv(d ~ 0 + test + test:hrs_ln, V = V_list, 38 | data = SATcoaching) 39 | coef_test(MVFE_hrs, vcov = "CR2", cluster = SATcoaching$study) 40 | 41 | lm_fit <- lm(d ~ 0 + test + test:hrs_ln, data = SATcoaching) 42 | coef_test(lm_fit, vcov = "CR2", cluster = SATcoaching$study) 43 | rma_fit <- rma.uni(d ~ 0 + test + test:hrs_ln, data = SATcoaching, vi = V) 44 | coef_test(rma_fit, vcov = "CR2", cluster = SATcoaching$study) 45 | 46 | 47 | MVRE_hrs <- rma.mv(d ~ 0 + test + test:hrs_ln, V = V_list, 48 | data = SATcoaching, 49 | random = ~ test | study, struct = "UN") 50 | 51 | V_mat <- with(SATcoaching, impute_covariance_matrix(vi = V, cluster = study, r = 0.66, return_list = FALSE)) 52 | has_hrs <- !is.na(SATcoaching$hrs_ln) 53 | V_mat <- V_mat[has_hrs, has_hrs] 54 | MVRE_hrs_filtered <- rma.mv(d ~ 0 + test + test:hrs_ln, V = V_mat, 55 | data = filter(SATcoaching, !is.na(hrs_ln)), 56 | random = ~ test | study, struct = "UN") 57 | coef_test(MVRE_hrs, vcov = "CR2") 58 | coef_test(MVRE_hrs_filtered, vcov = "CR2") 59 | -------------------------------------------------------------------------------- /auxilliary/test_club_sandwich_and_CR.R: -------------------------------------------------------------------------------- 1 | ## 2 | ## Code from tracking down bugs with clubsandwich and cluster robust SEs 3 | ## 4 | 5 | library( tidyverse ) 6 | library( blkvar ) 7 | 8 | # Mini sim study to look at club sandwich and the cluster robust SE stuff 9 | source("auxilliary/simulation_support_code.R" ) 10 | 11 | set.seed(20190530) 12 | 13 | lmsim = run.scenario( 14 | J = 10, 15 | n.bar = 100, 16 | tau=0.2^2, 17 | dependence = 0, 18 | proptx.dependence = 0, 19 | variable.n = TRUE, 20 | variable.p = FALSE, 21 | include.MLM=FALSE, 22 | include.block=FALSE, 23 | n.runs=1, 24 | R = 1000, 25 | .progress="text") 26 | 27 | table( lmsim$method ) 28 | 29 | clubsim = filter( lmsim, method %in% c( "FE-CR", "FE-Club" ) ) 30 | head( clubsim ) 31 | 32 | # Look at club sandwich 33 | rst = clubsim %>% 34 | group_by( method ) %>% 35 | summarise( 36 | SE = sd( ATE.hat ), 37 | V = var(ATE.hat), 38 | E.SE.hat = mean( SE.hat ), 39 | E.V.hat = mean(SE.hat^2), 40 | med.SE.hat = median(SE.hat), 41 | sd.SE.hat = sd(SE.hat), 42 | rat_SE = E.SE.hat / SE, 43 | rat_V = E.V.hat / V 44 | ) 45 | rst 46 | 47 | 48 | 49 | 50 | # Quick simulation check: 51 | # 52 | # Does hand-rolled code give same results as the clubsandwich package code? 53 | # Aside: major time difference in running! 54 | 55 | library(clubSandwich) 56 | library(plm) 57 | 58 | check = replicate( 10, { 59 | df = gen.dat.no.cov( n.bar=400, J=20, 60 | tau.11.star = 0, 61 | ICC = 0.20, 62 | p = 0.70, 63 | variable.n = TRUE, 64 | variable.p = TRUE, 65 | size.impact.correlate = TRUE, 66 | proptx.impact.correlate = TRUE, 67 | finite.model = FALSE ) 68 | head( df ) 69 | 70 | cm = compare_methods( Yobs, Z, sid, data=df, include.MLM = FALSE, include.block = FALSE, include.DB = FALSE ) 71 | cm 72 | 73 | M0 = lm( Yobs ~ 0 + Z + sid, data=df ) 74 | system.time(ct <- coef_test( M0, vcov="CR2", cluster = df$sid, coefs=c("Z" ) )) 75 | ct 76 | 77 | PLM0 = plm(Yobs ~ Z, data = df, effect = "individual", model = "within", index = "sid") 78 | system.time(plm_ct <- coef_test(PLM0, vcov = "CR2", ignore_FE = TRUE)) 79 | plm_ct 80 | 81 | SEs = c( hand = filter( cm, method=="FE-Club" )$SE, 82 | package_lm = ct$SE, 83 | package_plm = plm_ct$SE) 84 | if ( diff( range( SEs ) ) > 0.05 ) { 85 | browser() 86 | } 87 | SEs 88 | } ) 89 | 90 | check 91 | check[1,] - check[2,] 92 | 93 | 94 | -------------------------------------------------------------------------------- /auxilliary/testing robumeta.R: -------------------------------------------------------------------------------- 1 | library(robumeta) 2 | library(clubSandwich) 3 | data(dropoutPrevention) 4 | 5 | dp_subset <- subset(dropoutPrevention, big_study==TRUE) 6 | 7 | m3_corr_small <- robu(LOR1 ~ study_design + attrition + group_equivalence + adjusted 8 | + outcome + evaluator_independence 9 | + male_pct + white_pct + average_age 10 | + implementation_quality + program_site + duration + service_hrs, 11 | data = dp_subset, studynum = studyID, var.eff.size = varLOR, modelweights = "CORR") 12 | 13 | m3_corr_small 14 | coef_test(m3_corr_small, vcov = "CR2") 15 | 16 | 17 | m3_hier_small <- robu(LOR1 ~ study_design + attrition + group_equivalence + adjusted 18 | + outcome + evaluator_independence 19 | + male_pct + white_pct + average_age 20 | + implementation_quality + program_site + duration + service_hrs, 21 | data = dp_subset, studynum = studyID, var.eff.size = varLOR, modelweights = "HIER") 22 | 23 | m3_hier_small 24 | 25 | ord <- order(order(m3_hier_small$study_orig_id)) 26 | 27 | dp_subset$user_wts <- m3_hier_small$data.full$r.weights[ord] 28 | 29 | m3_user_small <- robu(LOR1 ~ study_design + attrition + group_equivalence + adjusted 30 | + outcome + evaluator_independence 31 | + male_pct + white_pct + average_age 32 | + implementation_quality + program_site + duration + service_hrs, 33 | data = dp_subset, studynum = studyID, var.eff.size = varLOR, userweights = user_wts) 34 | 35 | m3_user_small 36 | coef_test(m3_user_small, vcov = "CR2") 37 | -------------------------------------------------------------------------------- /auxilliary/two-sample-t-test.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Two-sample t-test on a between-cluster factor" 3 | author: "James E. Pustejovsky" 4 | date: "November 22, 2016" 5 | output: html_document 6 | --- 7 | 8 | Consider a study design with $T$ treated clusters of size $m_1,...,m_T$ and $C$ untreated clusters of size $n_1,...,n_C$. We observe an outcome $Y$ for every observation in every cluster and seek to test the hypothesis that the mean of the treated population is equal to the mean of the control population, while allowing for the possibility of dependence among the observations within a cluster. 9 | 10 | Let $M = \sum_{i=1}^T m_i$, $f_i = m_i / M$, $N = \sum_{i=1}^C n_i$, and $g_i = n_i / N$. Let $\bar{y}^T_i = \frac{1}{m_i} \sum_{j=1}^{m_i} y^T_{ij}$ and $\bar{y}^C_i = \frac{1}{n_i} \sum_{j=1}^{n_i} y^C_{ij}$. Let $\bar{\bar{y}}^T = \frac{1}{M} \sum_{i=1}^T \sum_{j=1}^{m_i} y^T_{ij}$ and $\bar{\bar{y}}^C = \frac{1}{N} \sum_{i=1}^C \sum_{j=1}^{n_i} y^C_{ij}$. The estimated difference in means is simply 11 | $$ 12 | \hat\delta = \bar{\bar{y}}^T - \bar{\bar{y}}^C = \sum_{i=1}^T f_i \bar{y}^T_i - \sum_{i=1}^C g_i \bar{y}^C_i. 13 | $$ 14 | The cluster-robust variance estimator of $\text{Var}\left(\hat\delta\right)$, without small sample correction, is 15 | $$ 16 | V^{CR0} = \sum_{i=1}^T f_i^2 \left(\bar{y}^T_i - \bar{\bar{y}}^T\right)^2 + \sum_{i=1}^C g_i^2 \left(\bar{y}^C_i - \bar{\bar{y}}^C\right)^2. 17 | $$ 18 | 19 | If we instead use the bias-reduced linearization variance estimator (CR2), then we have 20 | $$ 21 | V^{CR2} = \sum_{i=1}^T \left(\frac{M}{M - m_i}\right)f_i^2 \left(\bar{y}^T_i - \bar{\bar{y}}^T\right)^2 + \sum_{i=1}^C \left(\frac{N}{N - n_i}\right) g_i^2 \left(\bar{y}^C_i - \bar{\bar{y}}^C\right)^2 22 | $$ 23 | The degrees of freedom corresponding to the CR2 variance estimator (assuming an identity working model) are 24 | $$ 25 | \nu_{CR2} = \left(\frac{1}{M} + \frac{1}{N}\right)^2 \left[\sum_{i=1}^T \frac{f_i^2(1 - f_i)^2}{(M - m_i)^2} + \sum_{i=1}^T \sum_{j \neq i} \frac{f_i^2 f_j^2}{(M - m_i)(M - m_j)} + \sum_{i=1}^C \frac{g_i^2(1 - g_i)^2}{(N - n_i)^2} + \sum_{i=1}^C \sum_{j \neq i} \frac{g_i^2 g_j^2}{(N - n_i)(N - n_j)}\right]^{-1}. 26 | $$ 27 | If the cluster sizes are equal within each group (i.e., $f_1 = \cdots = f_T$ and $g_1 = \cdots = g_C$), then the degrees of freedom simplify to 28 | $$ 29 | \begin{aligned} 30 | \nu_{CR2} &= \left(\frac{1}{M} + \frac{1}{N}\right)^2 \left[\frac{1}{M^2 (T - 1)} + \frac{1}{N^2 (C - 1)}\right]^{-1} \\ 31 | &= \frac{(M + N)^2}{\displaystyle{\frac{N^2}{T - 1} + \frac{M^2}{C - 1}}}. 32 | \end{aligned} 33 | $$ 34 | -------------------------------------------------------------------------------- /clubSandwich.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: 97af4ef4-8c89-4770-833d-a27618b6a0ac 3 | 4 | RestoreWorkspace: Default 5 | SaveWorkspace: Default 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: knitr 14 | LaTeX: pdfLaTeX 15 | 16 | BuildType: Package 17 | PackageUseDevtools: Yes 18 | PackageInstallArgs: --no-multiarch --with-keep.source 19 | PackageRoxygenize: rd,collate,namespace 20 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Resubmission 2 | 3 | This release provides enhanced options for hypothesis testing within the existing functions Wald_test(), coef_test(), and linear_contrast(). 4 | 5 | Please note that the DESCRIPTION file includes a citation to Bell and McCaffrey (2002), but unfortunately that article does not have a DOI; I have included a URL instead. 6 | 7 | ## Test environments 8 | 9 | * local Windows 11 Pro, R 4.4.3 10 | * ubuntu 20.04.3 LTS (on Github), R devel, release, oldrelease 11 | * macOS-latest (on Github), R release 12 | * windows-latest (on Github), R release 13 | * win-builder (devel, release, oldrelease) 14 | * mac-builder (release) 15 | 16 | ## R CMD check results 17 | 18 | There were no ERRORs or WARNINGs. There was one NOTE: 19 | 20 | New maintainer: 21 | James E. Pustejovsky 22 | Old maintainer(s): 23 | James Pustejovsky 24 | 25 | This is correct. I would like to add my middle initial to the listing of my name. 26 | 27 | 28 | ## recheck results 29 | 30 | We checked 18 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 31 | 32 | * We saw 0 new problems 33 | * We failed to check 0 packages 34 | 35 | -------------------------------------------------------------------------------- /data/AchievementAwardsRCT.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/data/AchievementAwardsRCT.RData -------------------------------------------------------------------------------- /data/MortalityRates.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/data/MortalityRates.RData -------------------------------------------------------------------------------- /data/SATcoaching.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/data/SATcoaching.RData -------------------------------------------------------------------------------- /data/dropoutPrevention.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/data/dropoutPrevention.RData -------------------------------------------------------------------------------- /man/AchievementAwardsRCT.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data-documentation.R 3 | \docType{data} 4 | \name{AchievementAwardsRCT} 5 | \alias{AchievementAwardsRCT} 6 | \title{Achievement Awards Demonstration program} 7 | \format{ 8 | A data frame with 16526 rows and 21 variables: \describe{ 9 | \item{school_id}{Fictitious school identification number} 10 | \item{school_type}{Factor identifying the school type (Arab religious, Jewish religious, Jewish secular)} 11 | \item{pair}{Number of treatment pair. Note that 7 is a triple.} 12 | \item{treated}{Indicator for whether school was in treatment group} 13 | \item{year}{Cohort year} 14 | \item{student_id}{Fictitious student identification number} 15 | \item{sex}{Factor identifying student sex} 16 | \item{siblings}{Number of siblings} 17 | \item{immigrant}{Indicator for immigrant status} 18 | \item{father_ed}{Father's level of education} 19 | \item{mother_ed}{Mother's level of education} 20 | \item{Bagrut_status}{Indicator for Bagrut attainment} 21 | \item{attempted}{Number of Bagrut units attempted} 22 | \item{awarded}{Number of Bagrut units awarded} 23 | \item{achv_math}{Indicator for satisfaction of math requirement} 24 | \item{achv_english}{Indicator for satisfaction of English requirement} 25 | \item{achv_hebrew}{Indicator for satisfaction of Hebrew requirement} 26 | \item{lagscore}{Lagged Bagrut score} 27 | \item{qrtl}{Quartile within distribution of lagscore, calculated by cohort and sex} 28 | \item{half}{Lower or upper half within distribution of lagscore, calculated by cohort and sex} 29 | } 30 | } 31 | \source{ 32 | \href{https://economics.mit.edu/people/faculty/josh-angrist/angrist-data-archive}{Angrist Data Archive} 33 | } 34 | \usage{ 35 | AchievementAwardsRCT 36 | } 37 | \description{ 38 | Data from a randomized trial of the Achievement Awards 39 | Demonstration program, reported in Angrist & Lavy (2009). 40 | } 41 | \references{ 42 | Angrist, J. D., & Lavy, V. (2009). The effects of high stakes 43 | high school achievement awards : Evidence from a randomized trial. 44 | \emph{American Economic Review, 99}(4), 1384-1414. 45 | \doi{10.1257/aer.99.4.1384} 46 | } 47 | \keyword{datasets} 48 | -------------------------------------------------------------------------------- /man/MortalityRates.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data-documentation.R 3 | \docType{data} 4 | \name{MortalityRates} 5 | \alias{MortalityRates} 6 | \title{State-level annual mortality rates by cause among 18-20 year-olds} 7 | \format{ 8 | A data frame with 5508 rows and 12 variables: \describe{ 9 | \item{year}{Year of observation} 10 | \item{state}{identifier for state} 11 | \item{count}{Number of deaths} 12 | \item{pop}{Population size} 13 | \item{legal}{Proportion of 18-20 year-old population that is legally allowed to drink} 14 | \item{beertaxa}{Beer taxation rate} 15 | \item{beerpercap}{Beer consumption per capita} 16 | \item{winepercap}{Wine consumption per capita} 17 | \item{spiritpercap}{Spirits consumption per capita} 18 | \item{totpercap}{Total alcohol consumption per capita} 19 | \item{mrate}{Mortality rate per 10,000} 20 | \item{cause}{Cause of death} 21 | } 22 | } 23 | \source{ 24 | \href{https://masteringmetrics.com/wp-content/uploads/2015/01/deaths.dta}{Mastering 25 | 'Metrics data archive} 26 | } 27 | \usage{ 28 | MortalityRates 29 | } 30 | \description{ 31 | A dataset containing state-level annual mortality rates for select causes of 32 | death, as well as data related to the minimum legal drinking age and alcohol 33 | consumption. 34 | } 35 | \references{ 36 | Angrist, J. D., and Pischke, J. S. (2014). _Mastering'metrics: the path from 37 | cause to effect_. Princeton University Press, 2014. 38 | 39 | Carpenter, C., & Dobkin, C. (2011). The minimum legal drinking age and public 40 | health. _Journal of Economic Perspectives, 25_(2), 133-156. 41 | \doi{10.1257/jep.25.2.133} 42 | } 43 | \keyword{datasets} 44 | -------------------------------------------------------------------------------- /man/SATcoaching.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data-documentation.R 3 | \docType{data} 4 | \name{SATcoaching} 5 | \alias{SATcoaching} 6 | \title{Randomized experiments on SAT coaching} 7 | \format{ 8 | A data frame with 67 rows and 11 variables: 9 | \describe{ 10 | \item{study}{Study identifier} 11 | \item{year}{Year of publication} 12 | \item{test}{Character string indicating whether effect size corresponds to outcome on verbal (SATV) or math (SATM) test} 13 | \item{d}{Effect size estimate (Standardized mean difference)} 14 | \item{V}{Variance of effect size estimate} 15 | \item{nT}{Sample size in treatment condition} 16 | \item{nC}{Sample size in control condition} 17 | \item{study_type}{Character string indicating whether study design used a matched, non-equivalent, or randomized control group} 18 | \item{hrs}{Hours of coaching} 19 | \item{ETS}{Indicator variable for Educational Testing Service} 20 | \item{homework}{Indicator variable for homework} 21 | } 22 | } 23 | \usage{ 24 | SATcoaching 25 | } 26 | \description{ 27 | Effect sizes from studies on the effects of SAT coaching, 28 | reported in Kalaian and Raudenbush (1996) 29 | } 30 | \references{ 31 | Kalaian, H. A. & Raudenbush, S. W. (1996). A multivariate mixed 32 | linear model for meta-analysis. \emph{Psychological Methods, 1}(3), 33 | 227-235. 34 | \doi{10.1037/1082-989X.1.3.227} 35 | } 36 | \keyword{datasets} 37 | -------------------------------------------------------------------------------- /man/coef_test.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/coef_test.R 3 | \name{coef_test} 4 | \alias{coef_test} 5 | \title{Test all or selected regression coefficients in a fitted model} 6 | \usage{ 7 | coef_test( 8 | obj, 9 | vcov, 10 | test = "Satterthwaite", 11 | alternative = c("two-sided", "greater", "less"), 12 | coefs = "All", 13 | null_constants = 0, 14 | p_values = TRUE, 15 | ... 16 | ) 17 | } 18 | \arguments{ 19 | \item{obj}{Fitted model for which to calculate t-tests.} 20 | 21 | \item{vcov}{Variance covariance matrix estimated using \code{vcovCR} or a 22 | character string specifying which small-sample adjustment should be used to 23 | calculate the variance-covariance.} 24 | 25 | \item{test}{Character vector specifying which small-sample corrections to 26 | calculate. \code{"z"} returns a z test (i.e., using a standard normal 27 | reference distribution). \code{"naive-t"} returns a t test with \code{m - 28 | 1} degrees of freedom, where \code{m} is the number of unique clusters. 29 | \code{"naive-tp"} returns a t test with \code{m - p} degrees of freedom, 30 | where \code{p} is the number of regression coefficients in \code{obj}. 31 | \code{"Satterthwaite"} returns a Satterthwaite correction. 32 | \code{"saddlepoint"} returns a saddlepoint correction. Default is 33 | \code{"Satterthwaite"}.} 34 | 35 | \item{alternative}{Character string specifying the alternative hypothesis, 36 | with options "two-sided" (the default), "greater" or "less".} 37 | 38 | \item{coefs}{Character, integer, or logical vector specifying which 39 | coefficients should be tested. The default value \code{"All"} will test all 40 | estimated coefficients.} 41 | 42 | \item{null_constants}{vector of null values for each coefficient to test. 43 | Must have length equal to the number of coefficients specified in 44 | \code{coefs}. Default is \code{0}, in which case the null values are taken 45 | to be zero.} 46 | 47 | \item{p_values}{Logical indicating whether to report p-values. The default 48 | value is \code{TRUE}.} 49 | 50 | \item{...}{Further arguments passed to \code{\link{vcovCR}}, which are only 51 | needed if \code{vcov} is a character string.} 52 | } 53 | \value{ 54 | A data frame containing estimated regression coefficients, standard 55 | errors, specified values of null hypotheses, and test results. For the 56 | Satterthwaite approximation, degrees of freedom and a p-value are reported. 57 | For the saddlepoint approximation, the saddlepoint and a p-value are 58 | reported. 59 | } 60 | \description{ 61 | \code{coef_test} reports one- or two-sided t-tests for each coefficient 62 | estimate in a fitted linear regression model, using a sandwich estimator for 63 | the standard errors and (optionally) a small sample correction for the 64 | p-value. Available small-sample corrections include Satterthwaite 65 | approximation or a saddlepoint approximation. Coefficients can be tested 66 | against non-zero null values by specifying \code{null_constants}. 67 | } 68 | \examples{ 69 | 70 | data("ChickWeight", package = "datasets") 71 | lm_fit <- lm(weight ~ Diet * Time, data = ChickWeight) 72 | diet_index <- grepl("Diet.:Time", names(coef(lm_fit))) 73 | coef_test(lm_fit, vcov = "CR2", cluster = ChickWeight$Chick, coefs = diet_index) 74 | 75 | V_CR2 <- vcovCR(lm_fit, cluster = ChickWeight$Chick, type = "CR2") 76 | coef_test(lm_fit, vcov = V_CR2, coefs = diet_index) 77 | 78 | # non-inferiority test whether time-by-diet interaction effects are 2 or greater 79 | coef_test(lm_fit, vcov = V_CR2, coefs = diet_index, null_constants = 2, alternative = "greater") 80 | 81 | } 82 | \seealso{ 83 | \code{\link{vcovCR}} 84 | } 85 | -------------------------------------------------------------------------------- /man/conf_int.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/conf_int.R 3 | \name{conf_int} 4 | \alias{conf_int} 5 | \title{Calculate confidence intervals for all or selected regression coefficients in 6 | a fitted model} 7 | \usage{ 8 | conf_int( 9 | obj, 10 | vcov, 11 | level = 0.95, 12 | test = "Satterthwaite", 13 | coefs = "All", 14 | ..., 15 | p_values = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{obj}{Fitted model for which to calculate confidence intervals.} 20 | 21 | \item{vcov}{Variance covariance matrix estimated using \code{vcovCR} or a 22 | character string specifying which small-sample adjustment should be used to 23 | calculate the variance-covariance.} 24 | 25 | \item{level}{Desired coverage level for confidence intervals.} 26 | 27 | \item{test}{Character vector specifying which small-sample corrections to 28 | calculate. \code{"z"} returns a z test (i.e., using a standard normal 29 | reference distribution). \code{"naive-t"} returns a t test with \code{m - 30 | 1} degrees of freedom, where \code{m} is the number of unique clusters. 31 | \code{"naive-tp"} returns a t test with \code{m - p} degrees of freedom, 32 | where \code{p} is the number of regression coefficients in \code{obj}. 33 | \code{"Satterthwaite"} returns a Satterthwaite correction. Unlike in 34 | \code{coef_test()}, \code{"saddlepoint"} is not currently supported in 35 | \code{conf_int()} because saddlepoint confidence intervals do not have a 36 | closed-form solution.} 37 | 38 | \item{coefs}{Character, integer, or logical vector specifying which 39 | coefficients should be tested. The default value \code{"All"} will test all 40 | estimated coefficients.} 41 | 42 | \item{...}{Further arguments passed to \code{\link{vcovCR}}, which are only 43 | needed if \code{vcov} is a character string.} 44 | 45 | \item{p_values}{Logical indicating whether to report p-values. The default 46 | value is \code{TRUE}.} 47 | } 48 | \value{ 49 | A data frame containing estimated regression coefficients, standard 50 | errors, confidence intervals, and (optionally) p-values. 51 | } 52 | \description{ 53 | \code{conf_int} reports confidence intervals for each coefficient estimate in 54 | a fitted linear regression model, using a sandwich estimator for the standard 55 | errors and a small sample correction for the critical values. The 56 | small-sample correction is based on a Satterthwaite approximation. 57 | } 58 | \examples{ 59 | 60 | data("ChickWeight", package = "datasets") 61 | lm_fit <- lm(weight ~ Diet * Time, data = ChickWeight) 62 | diet_index <- grepl("Diet.:Time", names(coef(lm_fit))) 63 | conf_int(lm_fit, vcov = "CR2", cluster = ChickWeight$Chick, coefs = diet_index) 64 | 65 | V_CR2 <- vcovCR(lm_fit, cluster = ChickWeight$Chick, type = "CR2") 66 | conf_int(lm_fit, vcov = V_CR2, level = .99, coefs = diet_index) 67 | 68 | } 69 | \seealso{ 70 | \code{\link{vcovCR}} 71 | } 72 | -------------------------------------------------------------------------------- /man/constraint_matrices.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Wald_test.R 3 | \name{constraint_matrices} 4 | \alias{constraint_matrices} 5 | \alias{constrain_zero} 6 | \alias{constrain_equal} 7 | \alias{constrain_pairwise} 8 | \title{Create constraint matrices} 9 | \usage{ 10 | constrain_zero(constraints, coefs, reg_ex = FALSE) 11 | 12 | constrain_equal(constraints, coefs, reg_ex = FALSE) 13 | 14 | constrain_pairwise(constraints, coefs, reg_ex = FALSE, with_zero = FALSE) 15 | } 16 | \arguments{ 17 | \item{constraints}{Set of constraints to test. Can be logical (using 18 | \code{TRUE} to specify which coefficients to constrain), integer (specify 19 | the index of coefficients to constrain), character (specify the names of 20 | the coefficients to constrain), or a regular expression.} 21 | 22 | \item{coefs}{Vector of coefficient estimates, used to determine the column 23 | dimension of the constraint matrix. Can be omitted if the function is 24 | called inside \code{Wald_test()}.} 25 | 26 | \item{reg_ex}{Logical indicating whether \code{constraints} should be 27 | interpreted as a regular expression. Defaults to \code{FALSE}.} 28 | 29 | \item{with_zero}{Logical indicating whether coefficients should also be 30 | compared to zero. Defaults to \code{FALSE}.} 31 | } 32 | \value{ 33 | A matrix or list of matrices encoding the specified set of 34 | constraints. 35 | } 36 | \description{ 37 | Helper functions to create common types of constraint matrices, 38 | for use with \code{\link{Wald_test}} to conduct Wald-type tests of linear 39 | contrasts from a fitted regression model. 40 | } 41 | \details{ 42 | Constraints can be specified as character vectors, regular 43 | expressions (with \code{reg_ex = TRUE}), integer vectors, or logical 44 | vectors. 45 | 46 | \code{constrain_zero()} Creates a matrix that constrains a specified set of 47 | coefficients to all be equal to zero. 48 | 49 | \code{constrain_equal()} Creates a matrix that constrains a specified set 50 | of coefficients to all be equal. 51 | 52 | \code{constrain_pairwise()} Creates a list of constraint matrices 53 | consisting of all pairwise comparisons between a specified set of 54 | coefficients. If \code{with_zero = TRUE}, then the list will also include a 55 | set of constraint matrices comparing each coefficient to zero. 56 | } 57 | \examples{ 58 | 59 | if (requireNamespace("carData", quietly = TRUE)) withAutoprint({ 60 | 61 | data(Duncan, package = "carData") 62 | Duncan$cluster <- sample(LETTERS[1:8], size = nrow(Duncan), replace = TRUE) 63 | 64 | Duncan_fit <- lm(prestige ~ 0 + type + income + type:income + type:education, data=Duncan) 65 | # Note that type:income terms are interactions because main effect of income is included 66 | # but type:education terms are separate slopes for each unique level of type 67 | 68 | Duncan_coefs <- coef(Duncan_fit) 69 | 70 | # The following are all equivalent 71 | constrain_zero(constraints = c("typeprof:income","typewc:income"), 72 | coefs = Duncan_coefs) 73 | constrain_zero(constraints = ":income", coefs = Duncan_coefs, 74 | reg_ex = TRUE) 75 | constrain_zero(constraints = 5:6, coefs = Duncan_coefs) 76 | constrain_zero(constraints = c(FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE), 77 | coefs = Duncan_coefs) 78 | 79 | # The following are all equivalent 80 | constrain_equal(c("typebc:education","typeprof:education","typewc:education"), 81 | Duncan_coefs) 82 | constrain_equal(":education", Duncan_coefs, reg_ex = TRUE) 83 | constrain_equal(7:9, Duncan_coefs) 84 | constrain_equal(c(FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE), 85 | Duncan_coefs) 86 | 87 | # Test pairwise equality of the education slopes 88 | constrain_pairwise(":education", Duncan_coefs, 89 | reg_ex = TRUE) 90 | 91 | # Test pairwise equality of the income slopes, plus compare against zero 92 | constrain_pairwise(":income", Duncan_coefs, 93 | reg_ex = TRUE, with_zero = TRUE) 94 | 95 | }) 96 | 97 | } 98 | \seealso{ 99 | \code{\link{Wald_test}} 100 | } 101 | -------------------------------------------------------------------------------- /man/dropoutPrevention.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data-documentation.R 3 | \docType{data} 4 | \name{dropoutPrevention} 5 | \alias{dropoutPrevention} 6 | \title{Dropout prevention/intervention program effects} 7 | \format{ 8 | A data frame with 385 rows and 18 variables: \describe{ 9 | \item{LOR1}{log-odds ratio measuring the intervention effect} 10 | \item{varLOR}{estimated sampling variance of the log-odds ratio} 11 | \item{studyID}{unique identifier for each study} \item{studySample}{unique 12 | identifier for each sample within a study} \item{study_design}{study design 13 | (randomized, matched, or non-randomized and unmatched)} 14 | \item{outcome}{outcome measure for the intervention effect is estimated 15 | (school dropout, school enrollment, graduation, graduation or GED receipt)} 16 | \item{evaluator_independence}{degree of evaluator independence 17 | (independent, indirect but influential, involved in planning but not 18 | delivery, involved in delivery)} \item{implementation_quality}{level of 19 | implementation quality (clear problems, possible problems, no apparent 20 | problems)} \item{program_site}{Program delivery site (community, mixed, 21 | school classroom, school but outside of classroom)} 22 | \item{attrition}{Overall attrition (proportion)} 23 | \item{group_equivalence}{pretest group-equivalence log-odds ratio} 24 | \item{adjusted}{adjusted or unadjusted data used to calculate intervention 25 | effect} \item{male_pct}{proportion of the sample that is male} 26 | \item{white_pct}{proportion of the sample that is white} 27 | \item{average_age}{average age of the sample} \item{duration}{program 28 | duration (in weeks)} \item{service_hrs}{program contact hours per week} 29 | \item{big_study}{indicator for the 32 studies with 3 or more effect sizes} 30 | } 31 | } 32 | \source{ 33 | Wilson, S. J., Lipsey, M. W., Tanner-Smith, E., Huang, C. H., & 34 | Steinka-Fry, K. T. (2011). Dropout prevention and intervention programs: 35 | Effects on school completion and dropout Among school-aged children and 36 | youth: A systematic review. _Campbell Systematic Reviews, 7_(1), 1-61. 37 | \doi{10.4073/csr.2011.8} 38 | } 39 | \usage{ 40 | dropoutPrevention 41 | } 42 | \description{ 43 | A dataset containing estimated effect sizes, variances, and covariates from a 44 | meta-analysis of dropout prevention/intervention program effects, conducted 45 | by Wilson et al. (2011). Missing observations were imputed. 46 | } 47 | \references{ 48 | Wilson, S. J., Lipsey, M. W., Tanner-Smith, E., Huang, C. H., & 49 | Steinka-Fry, K. T. (2011). Dropout prevention and intervention programs: 50 | Effects on school completion and dropout Among school-aged children and 51 | youth: A systematic review. _Campbell Systematic Reviews, 7_(1), 1-61. 52 | \doi{10.4073/csr.2011.8} 53 | 54 | Tipton, E., & Pustejovsky, J. E. (2015). Small-sample adjustments for tests 55 | of moderators and model fit using robust variance estimation in 56 | meta-regression. _Journal of Educational and Behavioral Statistics, 40_(6), 604-634. 57 | \doi{10.3102/1076998615606099} 58 | } 59 | \keyword{datasets} 60 | -------------------------------------------------------------------------------- /man/findCluster.rma.mv.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rma-mv.R 3 | \name{findCluster.rma.mv} 4 | \alias{findCluster.rma.mv} 5 | \title{Detect cluster structure of an rma.mv object} 6 | \usage{ 7 | findCluster.rma.mv(obj) 8 | } 9 | \arguments{ 10 | \item{obj}{A fitted \code{rma.mv} object.} 11 | } 12 | \value{ 13 | A a vector of ID variables for the highest level of clustering in \code{obj}. 14 | } 15 | \description{ 16 | \code{findCluster.rma.mv} returns a vector of ID variables for the highest level of clustering in a fitted \code{rma.mv} model. 17 | } 18 | \examples{ 19 | 20 | if (requireNamespace("metafor", quietly = TRUE)) { 21 | 22 | library(metafor) 23 | data(dat.assink2016, package = "metadat") 24 | 25 | mfor_fit <- rma.mv(yi ~ year + deltype, 26 | V = vi, random = ~ 1 | study / esid, 27 | data = dat.assink2016) 28 | 29 | findCluster.rma.mv(mfor_fit) 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /man/vcovCR.geeglm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geeglm.R 3 | \name{vcovCR.geeglm} 4 | \alias{vcovCR.geeglm} 5 | \title{Cluster-robust variance-covariance matrix for a geeglm object.} 6 | \usage{ 7 | \method{vcovCR}{geeglm}( 8 | obj, 9 | cluster, 10 | type, 11 | target = NULL, 12 | inverse_var = NULL, 13 | form = "sandwich", 14 | ... 15 | ) 16 | } 17 | \arguments{ 18 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 19 | 20 | \item{cluster}{Expression or vector indicating which observations belong to 21 | the same cluster. Required for \code{geeglm} objects.} 22 | 23 | \item{type}{Character string specifying which small-sample adjustment should 24 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 25 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 26 | \code{\link{vcovCR}} for further information.} 27 | 28 | \item{target}{Optional matrix or vector describing the working 29 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 30 | adjustment matrices. If a vector, the target matrix is assumed to be 31 | diagonal. If not specified, the target is taken to be the estimated variance function.} 32 | 33 | \item{inverse_var}{Optional logical indicating whether the weights used in 34 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 35 | will attempt to infer a value.} 36 | 37 | \item{form}{Controls the form of the returned matrix. The default 38 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 39 | Alternately, setting \code{form = "meat"} will return only the meat of the 40 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 41 | appropriate dimension, will return the sandwich variance-covariance matrix 42 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 43 | (appropriately scaled) estimating function, the transposed crossproduct of 44 | which is equal to the sandwich variance-covariance matrix.} 45 | 46 | \item{...}{Additional arguments available for some classes of objects.} 47 | } 48 | \value{ 49 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 50 | of a matrix of the estimated variance of and covariances between the 51 | regression coefficient estimates. 52 | } 53 | \description{ 54 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 55 | of a set of regression coefficient estimates from an \code{\link[geepack]{geeglm}} object. 56 | } 57 | \examples{ 58 | 59 | if (requireNamespace("geepack", quietly = TRUE)) { 60 | 61 | library(geepack) 62 | data(dietox, package = "geepack") 63 | dietox$Cu <- as.factor(dietox$Cu) 64 | mf <- formula(Weight ~ Cu * (Time + I(Time^2) + I(Time^3))) 65 | gee1 <- geeglm(mf, data=dietox, id=Pig, family=poisson("identity"), corstr="ar1") 66 | V_CR <- vcovCR(gee1, cluster = dietox$Pig, type = "CR2") 67 | coef_test(gee1, vcov = V_CR, test = "Satterthwaite") 68 | 69 | } 70 | 71 | } 72 | \seealso{ 73 | \code{\link{vcovCR}} 74 | } 75 | -------------------------------------------------------------------------------- /man/vcovCR.glm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/glm.R 3 | \name{vcovCR.glm} 4 | \alias{vcovCR.glm} 5 | \title{Cluster-robust variance-covariance matrix for a glm object.} 6 | \usage{ 7 | \method{vcovCR}{glm}( 8 | obj, 9 | cluster, 10 | type, 11 | target = NULL, 12 | inverse_var = NULL, 13 | form = "sandwich", 14 | ... 15 | ) 16 | } 17 | \arguments{ 18 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 19 | 20 | \item{cluster}{Expression or vector indicating which observations belong to 21 | the same cluster. Required for \code{glm} objects.} 22 | 23 | \item{type}{Character string specifying which small-sample adjustment should 24 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 25 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 26 | \code{\link{vcovCR}} for further information.} 27 | 28 | \item{target}{Optional matrix or vector describing the working 29 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 30 | adjustment matrices. If a vector, the target matrix is assumed to be 31 | diagonal. If not specified, the target is taken to be the estimated variance function.} 32 | 33 | \item{inverse_var}{Optional logical indicating whether the weights used in 34 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 35 | will attempt to infer a value.} 36 | 37 | \item{form}{Controls the form of the returned matrix. The default 38 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 39 | Alternately, setting \code{form = "meat"} will return only the meat of the 40 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 41 | appropriate dimension, will return the sandwich variance-covariance matrix 42 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 43 | (appropriately scaled) estimating function, the transposed crossproduct of 44 | which is equal to the sandwich variance-covariance matrix.} 45 | 46 | \item{...}{Additional arguments available for some classes of objects.} 47 | } 48 | \value{ 49 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 50 | of a matrix of the estimated variance of and covariances between the 51 | regression coefficient estimates. 52 | } 53 | \description{ 54 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 55 | of a set of regression coefficient estimates from an \code{\link{glm}} object. 56 | } 57 | \examples{ 58 | 59 | if (requireNamespace("geepack", quietly = TRUE)) { 60 | 61 | data(dietox, package = "geepack") 62 | dietox$Cu <- as.factor(dietox$Cu) 63 | weight_fit <- glm(Weight ~ Cu * poly(Time, 3), data=dietox, family = "quasipoisson") 64 | V_CR <- vcovCR(weight_fit, cluster = dietox$Pig, type = "CR2") 65 | coef_test(weight_fit, vcov = V_CR, test = "Satterthwaite") 66 | 67 | } 68 | 69 | } 70 | \seealso{ 71 | \code{\link{vcovCR}} 72 | } 73 | -------------------------------------------------------------------------------- /man/vcovCR.gls.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/gls.R 3 | \name{vcovCR.gls} 4 | \alias{vcovCR.gls} 5 | \title{Cluster-robust variance-covariance matrix for a gls object.} 6 | \usage{ 7 | \method{vcovCR}{gls}(obj, cluster, type, target, inverse_var, form = "sandwich", ...) 8 | } 9 | \arguments{ 10 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 11 | 12 | \item{cluster}{Optional expression or vector indicating which observations 13 | belong to the same cluster. If not specified, will be set to 14 | \code{getGroups(obj)}.} 15 | 16 | \item{type}{Character string specifying which small-sample adjustment should 17 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 18 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 19 | \code{\link{vcovCR}} for further information.} 20 | 21 | \item{target}{Optional matrix or vector describing the working 22 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 23 | adjustment matrices. If not specified, the target is taken to be the 24 | estimated variance-covariance structure of the \code{gls} object.} 25 | 26 | \item{inverse_var}{Optional logical indicating whether the weights used in 27 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 28 | will attempt to infer a value.} 29 | 30 | \item{form}{Controls the form of the returned matrix. The default 31 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 32 | Alternately, setting \code{form = "meat"} will return only the meat of the 33 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 34 | appropriate dimension, will return the sandwich variance-covariance matrix 35 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 36 | (appropriately scaled) estimating function, the transposed crossproduct of 37 | which is equal to the sandwich variance-covariance matrix.} 38 | 39 | \item{...}{Additional arguments available for some classes of objects.} 40 | } 41 | \value{ 42 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 43 | of a matrix of the estimated variance of and covariances between the 44 | regression coefficient estimates. 45 | } 46 | \description{ 47 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 48 | of a set of regression coefficient estimates from a \code{\link[nlme]{gls}} object. 49 | } 50 | \examples{ 51 | 52 | if (requireNamespace("nlme", quietly = TRUE)) { 53 | 54 | library(nlme) 55 | data(Ovary, package = "nlme") 56 | Ovary$time_int <- 1:nrow(Ovary) 57 | lm_AR1 <- gls(follicles ~ sin(2*pi*Time) + cos(2*pi*Time), data = Ovary, 58 | correlation = corAR1(form = ~ time_int | Mare)) 59 | vcovCR(lm_AR1, type = "CR2") 60 | 61 | } 62 | 63 | } 64 | \seealso{ 65 | \code{\link{vcovCR}} 66 | } 67 | -------------------------------------------------------------------------------- /man/vcovCR.ivreg.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ivreg.R 3 | \name{vcovCR.ivreg} 4 | \alias{vcovCR.ivreg} 5 | \title{Cluster-robust variance-covariance matrix for an ivreg object.} 6 | \usage{ 7 | \method{vcovCR}{ivreg}( 8 | obj, 9 | cluster, 10 | type, 11 | target = NULL, 12 | inverse_var = FALSE, 13 | form = "sandwich", 14 | ... 15 | ) 16 | } 17 | \arguments{ 18 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 19 | 20 | \item{cluster}{Expression or vector indicating which observations belong to 21 | the same cluster. Required for \code{ivreg} objects.} 22 | 23 | \item{type}{Character string specifying which small-sample adjustment should 24 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 25 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 26 | \code{\link{vcovCR}} for further information.} 27 | 28 | \item{target}{Optional matrix or vector describing the working 29 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 30 | adjustment matrices. If a vector, the target matrix is assumed to be 31 | diagonal. If not specified, the target is taken to be an identity matrix.} 32 | 33 | \item{inverse_var}{Not used for \code{ivreg} objects.} 34 | 35 | \item{form}{Controls the form of the returned matrix. The default 36 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 37 | Alternately, setting \code{form = "meat"} will return only the meat of the 38 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 39 | appropriate dimension, will return the sandwich variance-covariance matrix 40 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 41 | (appropriately scaled) estimating function, the transposed crossproduct of 42 | which is equal to the sandwich variance-covariance matrix.} 43 | 44 | \item{...}{Additional arguments available for some classes of objects.} 45 | } 46 | \value{ 47 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 48 | of a matrix of the estimated variance of and covariances between the 49 | regression coefficient estimates. 50 | } 51 | \description{ 52 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 53 | of a set of regression coefficient estimates from an ivreg object fitted 54 | from the \CRANpkg{AER} package or the \CRANpkg{ivreg} package. 55 | } 56 | \details{ 57 | For any "ivreg" objects fitted via the \code{\link[ivreg]{ivreg}} 58 | function from the \CRANpkg{ivreg} package, only traditional 2SLS 59 | regression method (method = "OLS") is supported. 60 | clubSandwich currently cannot support robust-regression methods such as 61 | M-estimation (method = "M") or MM-estimation (method = "MM"). 62 | } 63 | \examples{ 64 | 65 | if (requireNamespace("AER", quietly = TRUE)) withAutoprint({ 66 | 67 | library(AER) 68 | data("CigarettesSW") 69 | Cigs <- within(CigarettesSW, { 70 | rprice <- price/cpi 71 | rincome <- income/population/cpi 72 | tdiff <- (taxs - tax)/cpi 73 | }) 74 | 75 | iv_fit_AER <- AER::ivreg(log(packs) ~ log(rprice) + log(rincome) | 76 | log(rincome) + tdiff + I(tax/cpi), data = Cigs) 77 | vcovCR(iv_fit_AER, cluster = Cigs$state, type = "CR2") 78 | coef_test(iv_fit_AER, vcov = "CR2", cluster = Cigs$state) 79 | 80 | }) 81 | 82 | pkgs_available <- 83 | requireNamespace("AER", quietly = TRUE) & 84 | requireNamespace("ivreg", quietly = TRUE) 85 | 86 | if (pkgs_available) withAutoprint ({ 87 | 88 | data("CigarettesSW") 89 | Cigs <- within(CigarettesSW, { 90 | rprice <- price/cpi 91 | rincome <- income/population/cpi 92 | tdiff <- (taxs - tax)/cpi 93 | }) 94 | iv_fit_ivreg <- ivreg::ivreg(log(packs) ~ log(rprice) + log(rincome) | 95 | log(rincome) + tdiff + I(tax/cpi), data = Cigs) 96 | vcovCR(iv_fit_ivreg, cluster = Cigs$state, type = "CR2") 97 | coef_test(iv_fit_ivreg, vcov = "CR2", cluster = Cigs$state) 98 | }) 99 | 100 | } 101 | \seealso{ 102 | \code{\link{vcovCR}} 103 | } 104 | -------------------------------------------------------------------------------- /man/vcovCR.lm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/lm.R 3 | \name{vcovCR.lm} 4 | \alias{vcovCR.lm} 5 | \title{Cluster-robust variance-covariance matrix for an lm object.} 6 | \usage{ 7 | \method{vcovCR}{lm}( 8 | obj, 9 | cluster, 10 | type, 11 | target = NULL, 12 | inverse_var = NULL, 13 | form = "sandwich", 14 | ... 15 | ) 16 | } 17 | \arguments{ 18 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 19 | 20 | \item{cluster}{Expression or vector indicating which observations belong to 21 | the same cluster. Required for \code{lm} objects.} 22 | 23 | \item{type}{Character string specifying which small-sample adjustment should 24 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 25 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 26 | \code{\link{vcovCR}} for further information.} 27 | 28 | \item{target}{Optional matrix or vector describing the working 29 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 30 | adjustment matrices. If a vector, the target matrix is assumed to be 31 | diagonal. If not specified, the target is taken to be an identity matrix.} 32 | 33 | \item{inverse_var}{Optional logical indicating whether the weights used in 34 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 35 | will attempt to infer a value.} 36 | 37 | \item{form}{Controls the form of the returned matrix. The default 38 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 39 | Alternately, setting \code{form = "meat"} will return only the meat of the 40 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 41 | appropriate dimension, will return the sandwich variance-covariance matrix 42 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 43 | (appropriately scaled) estimating function, the transposed crossproduct of 44 | which is equal to the sandwich variance-covariance matrix.} 45 | 46 | \item{...}{Additional arguments available for some classes of objects.} 47 | } 48 | \value{ 49 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 50 | of a matrix of the estimated variance of and covariances between the 51 | regression coefficient estimates. 52 | } 53 | \description{ 54 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 55 | of a set of regression coefficient estimates from an \code{\link{lm}} object. 56 | } 57 | \examples{ 58 | 59 | data("ChickWeight", package = "datasets") 60 | lm_fit <- lm(weight ~ Time + Diet:Time, data = ChickWeight) 61 | vcovCR(lm_fit, cluster = ChickWeight$Chick, type = "CR2") 62 | 63 | if (requireNamespace("plm", quietly = TRUE)) withAutoprint({ 64 | 65 | data("Produc", package = "plm") 66 | lm_individual <- lm(log(gsp) ~ 0 + state + log(pcap) + log(pc) + log(emp) + unemp, data = Produc) 67 | individual_index <- !grepl("state", names(coef(lm_individual))) 68 | vcovCR(lm_individual, cluster = Produc$state, type = "CR2")[individual_index,individual_index] 69 | 70 | # compare to plm() 71 | plm_FE <- plm::plm(log(gsp) ~ log(pcap) + log(pc) + log(emp) + unemp, 72 | data = Produc, index = c("state","year"), 73 | effect = "individual", model = "within") 74 | vcovCR(plm_FE, type="CR2") 75 | 76 | }) 77 | 78 | } 79 | \seealso{ 80 | \code{\link{vcovCR}} 81 | } 82 | -------------------------------------------------------------------------------- /man/vcovCR.lme.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/lme.R 3 | \name{vcovCR.lme} 4 | \alias{vcovCR.lme} 5 | \title{Cluster-robust variance-covariance matrix for an lme object.} 6 | \usage{ 7 | \method{vcovCR}{lme}(obj, cluster, type, target, inverse_var, form = "sandwich", ...) 8 | } 9 | \arguments{ 10 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 11 | 12 | \item{cluster}{Optional expression or vector indicating which observations 13 | belong to the same cluster. If not specified, will be set to 14 | \code{getGroups(obj)}.} 15 | 16 | \item{type}{Character string specifying which small-sample adjustment should 17 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 18 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 19 | \code{\link{vcovCR}} for further information.} 20 | 21 | \item{target}{Optional matrix or vector describing the working 22 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 23 | adjustment matrices. If not specified, the target is taken to be the 24 | estimated variance-covariance structure of the \code{lme} object.} 25 | 26 | \item{inverse_var}{Optional logical indicating whether the weights used in 27 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 28 | will attempt to infer a value.} 29 | 30 | \item{form}{Controls the form of the returned matrix. The default 31 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 32 | Alternately, setting \code{form = "meat"} will return only the meat of the 33 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 34 | appropriate dimension, will return the sandwich variance-covariance matrix 35 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 36 | (appropriately scaled) estimating function, the transposed crossproduct of 37 | which is equal to the sandwich variance-covariance matrix.} 38 | 39 | \item{...}{Additional arguments available for some classes of objects.} 40 | } 41 | \value{ 42 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 43 | of a matrix of the estimated variance of and covariances between the 44 | regression coefficient estimates. 45 | } 46 | \description{ 47 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 48 | of a set of regression coefficient estimates from a \code{\link[nlme]{lme}} object. 49 | } 50 | \examples{ 51 | 52 | if (requireNamespace("nlme", quietly = TRUE)) { 53 | 54 | library(nlme) 55 | rat_weight <- lme(weight ~ Time * Diet, data=BodyWeight, ~ Time | Rat) 56 | vcovCR(rat_weight, type = "CR2") 57 | 58 | } 59 | 60 | pkgs_available <- 61 | requireNamespace("nlme", quietly = TRUE) & 62 | requireNamespace("mlmRev", quietly = TRUE) 63 | 64 | if (pkgs_available) { 65 | 66 | data(egsingle, package = "mlmRev") 67 | subset_ids <- levels(egsingle$schoolid)[1:10] 68 | egsingle_subset <- subset(egsingle, schoolid \%in\% subset_ids) 69 | 70 | math_model <- lme(math ~ year * size + female + black + hispanic, 71 | random = list(~ year | schoolid, ~ 1 | childid), 72 | data = egsingle_subset) 73 | 74 | vcovCR(math_model, type = "CR2") 75 | 76 | } 77 | 78 | } 79 | \seealso{ 80 | \code{\link{vcovCR}} 81 | } 82 | -------------------------------------------------------------------------------- /man/vcovCR.lmerMod.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/lmer.R 3 | \name{vcovCR.lmerMod} 4 | \alias{vcovCR.lmerMod} 5 | \title{Cluster-robust variance-covariance matrix for an lmerMod object.} 6 | \usage{ 7 | \method{vcovCR}{lmerMod}(obj, cluster, type, target, inverse_var, form = "sandwich", ...) 8 | } 9 | \arguments{ 10 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 11 | 12 | \item{cluster}{Optional expression or vector indicating which observations 13 | belong to the same cluster. If not specified, will be set to 14 | \code{getGroups(obj)}.} 15 | 16 | \item{type}{Character string specifying which small-sample adjustment should 17 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 18 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 19 | \code{\link{vcovCR}} for further information.} 20 | 21 | \item{target}{Optional matrix or vector describing the working 22 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 23 | adjustment matrices. If not specified, the target is taken to be the 24 | estimated variance-covariance structure of the \code{lmerMod} object.} 25 | 26 | \item{inverse_var}{Optional logical indicating whether the weights used in 27 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 28 | will attempt to infer a value.} 29 | 30 | \item{form}{Controls the form of the returned matrix. The default 31 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 32 | Alternately, setting \code{form = "meat"} will return only the meat of the 33 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 34 | appropriate dimension, will return the sandwich variance-covariance matrix 35 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 36 | (appropriately scaled) estimating function, the transposed crossproduct of 37 | which is equal to the sandwich variance-covariance matrix.} 38 | 39 | \item{...}{Additional arguments available for some classes of objects.} 40 | } 41 | \value{ 42 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 43 | of a matrix of the estimated variance of and covariances between the 44 | regression coefficient estimates. 45 | } 46 | \description{ 47 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 48 | of a set of regression coefficient estimates from \code{\link[lme4:merMod-class]{merMod}} object. 49 | } 50 | \examples{ 51 | 52 | if (requireNamespace("lme4", quietly = TRUE)) { 53 | 54 | library(lme4) 55 | sleep_fit <- lmer(Reaction ~ Days + (Days | Subject), sleepstudy) 56 | vcovCR(sleep_fit, type = "CR2") 57 | 58 | } 59 | 60 | pkgs_available <- 61 | requireNamespace("lme4", quietly = TRUE) & 62 | requireNamespace("mlmRev", quietly = TRUE) 63 | 64 | if (pkgs_available) { 65 | 66 | data(egsingle, package = "mlmRev") 67 | subset_ids <- levels(egsingle$schoolid)[1:10] 68 | math_model <- lmer(math ~ year * size + female + black + hispanic 69 | + (1 | schoolid) + (1 | childid), 70 | data = egsingle, subset = schoolid \%in\% subset_ids) 71 | vcovCR(math_model, type = "CR2") 72 | } 73 | 74 | } 75 | \seealso{ 76 | \code{\link{vcovCR}} 77 | } 78 | -------------------------------------------------------------------------------- /man/vcovCR.mlm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mlm.R 3 | \name{vcovCR.mlm} 4 | \alias{vcovCR.mlm} 5 | \title{Cluster-robust variance-covariance matrix for an mlm object.} 6 | \usage{ 7 | \method{vcovCR}{mlm}(obj, cluster, type, target, inverse_var, form = "sandwich", ...) 8 | } 9 | \arguments{ 10 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 11 | 12 | \item{cluster}{Optional expression or vector indicating which observations 13 | belong to the same cluster. If not specified, each row of the data will be 14 | treated as a separate cluster.} 15 | 16 | \item{type}{Character string specifying which small-sample adjustment should 17 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 18 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 19 | \code{\link{vcovCR}} for further information.} 20 | 21 | \item{target}{Optional matrix or vector describing the working 22 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 23 | adjustment matrices. If not specified, the target is taken to be an 24 | identity matrix.} 25 | 26 | \item{inverse_var}{Optional logical indicating whether the weights used in 27 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 28 | will attempt to infer a value.} 29 | 30 | \item{form}{Controls the form of the returned matrix. The default 31 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 32 | Alternately, setting \code{form = "meat"} will return only the meat of the 33 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 34 | appropriate dimension, will return the sandwich variance-covariance matrix 35 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 36 | (appropriately scaled) estimating function, the transposed crossproduct of 37 | which is equal to the sandwich variance-covariance matrix.} 38 | 39 | \item{...}{Additional arguments available for some classes of objects.} 40 | } 41 | \value{ 42 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 43 | of a matrix of the estimated variance of and covariances between the 44 | regression coefficient estimates. 45 | } 46 | \description{ 47 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 48 | of a set of regression coefficient estimates from an \code{mlm} object. 49 | } 50 | \examples{ 51 | iris_fit <- lm(cbind(Sepal.Length, Sepal.Width) ~ Species + 52 | Petal.Length + Petal.Width, data = iris) 53 | Vcluster <- vcovCR(iris_fit, type = "CR2") 54 | Vcluster 55 | 56 | } 57 | \seealso{ 58 | \code{\link{vcovCR}} 59 | } 60 | -------------------------------------------------------------------------------- /man/vcovCR.rma.mv.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rma-mv.R 3 | \name{vcovCR.rma.mv} 4 | \alias{vcovCR.rma.mv} 5 | \title{Cluster-robust variance-covariance matrix for a rma.mv object.} 6 | \usage{ 7 | \method{vcovCR}{rma.mv}(obj, cluster, type, target, inverse_var, form = "sandwich", ...) 8 | } 9 | \arguments{ 10 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 11 | 12 | \item{cluster}{Optional expression or vector indicating which observations 13 | belong to the same cluster. If not specified, will be set to the factor in 14 | the random-effects structure with the fewest distinct levels. Caveat 15 | emptor: the function does not check that the random effects are nested.} 16 | 17 | \item{type}{Character string specifying which small-sample adjustment should 18 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 19 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 20 | \code{\link{vcovCR}} for further information.} 21 | 22 | \item{target}{Optional matrix or vector describing the working 23 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 24 | adjustment matrices. If not specified, the target is taken to be the 25 | estimated variance-covariance structure of the \code{rma.mv} object.} 26 | 27 | \item{inverse_var}{Optional logical indicating whether the weights used in 28 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 29 | will attempt to infer a value.} 30 | 31 | \item{form}{Controls the form of the returned matrix. The default 32 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 33 | Alternately, setting \code{form = "meat"} will return only the meat of the 34 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 35 | appropriate dimension, will return the sandwich variance-covariance matrix 36 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 37 | (appropriately scaled) estimating function, the transposed crossproduct of 38 | which is equal to the sandwich variance-covariance matrix.} 39 | 40 | \item{...}{Additional arguments available for some classes of objects.} 41 | } 42 | \value{ 43 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 44 | of a matrix of the estimated variance of and covariances between the 45 | regression coefficient estimates. 46 | } 47 | \description{ 48 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 49 | of a set of regression coefficient estimates from a 50 | \code{\link[metafor]{rma.mv}} object. 51 | } 52 | \examples{ 53 | 54 | pkgs_available <- 55 | requireNamespace("metafor", quietly = TRUE) & 56 | requireNamespace("metadat", quietly = TRUE) 57 | 58 | if (pkgs_available) withAutoprint({ 59 | 60 | library(metafor) 61 | data(dat.assink2016, package = "metadat") 62 | 63 | mfor_fit <- rma.mv(yi ~ year + deltype, 64 | V = vi, random = ~ 1 | study / esid, 65 | data = dat.assink2016) 66 | mfor_fit 67 | 68 | mfor_CR2 <- vcovCR(mfor_fit, type = "CR2") 69 | mfor_CR2 70 | 71 | coef_test(mfor_fit, vcov = mfor_CR2, test = c("Satterthwaite", "saddlepoint")) 72 | Wald_test(mfor_fit, constraints = constrain_zero(3:4), vcov = mfor_CR2) 73 | 74 | }) 75 | 76 | } 77 | \seealso{ 78 | \code{\link{vcovCR}} 79 | } 80 | -------------------------------------------------------------------------------- /man/vcovCR.rma.uni.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rma-uni.R 3 | \name{vcovCR.rma.uni} 4 | \alias{vcovCR.rma.uni} 5 | \title{Cluster-robust variance-covariance matrix for a rma.uni object.} 6 | \usage{ 7 | \method{vcovCR}{rma.uni}(obj, cluster, type, target, inverse_var, form = "sandwich", ...) 8 | } 9 | \arguments{ 10 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 11 | 12 | \item{cluster}{Expression or vector indicating which observations 13 | belong to the same cluster. Required for \code{rma.uni} objects.} 14 | 15 | \item{type}{Character string specifying which small-sample adjustment should 16 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 17 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 18 | \code{\link{vcovCR}} for further information.} 19 | 20 | \item{target}{Optional matrix or vector describing the working 21 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 22 | adjustment matrices. If not specified, the target is taken to be diagonal 23 | with entries equal to the estimated marginal variance of the effect sizes.} 24 | 25 | \item{inverse_var}{Optional logical indicating whether the weights used in 26 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 27 | will attempt to infer a value.} 28 | 29 | \item{form}{Controls the form of the returned matrix. The default 30 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 31 | Alternately, setting \code{form = "meat"} will return only the meat of the 32 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 33 | appropriate dimension, will return the sandwich variance-covariance matrix 34 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 35 | (appropriately scaled) estimating function, the transposed crossproduct of 36 | which is equal to the sandwich variance-covariance matrix.} 37 | 38 | \item{...}{Additional arguments available for some classes of objects.} 39 | } 40 | \value{ 41 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 42 | of a matrix of the estimated variance of and covariances between the 43 | regression coefficient estimates. 44 | } 45 | \description{ 46 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 47 | of a set of regression coefficient estimates from a 48 | \code{\link[metafor]{rma.uni}} object. 49 | } 50 | \examples{ 51 | 52 | pkgs_available <- 53 | requireNamespace("metafor", quietly = TRUE) & 54 | requireNamespace("metadat", quietly = TRUE) 55 | 56 | if (pkgs_available) withAutoprint({ 57 | 58 | library(metafor) 59 | data(dat.assink2016, package = "metadat") 60 | 61 | mfor_fit <- rma.uni(yi ~ year + deltype, vi = vi, 62 | data = dat.assink2016) 63 | mfor_fit 64 | 65 | mfor_CR2 <- vcovCR(mfor_fit, type = "CR2", cluster = dat.assink2016$study) 66 | mfor_CR2 67 | coef_test(mfor_fit, vcov = mfor_CR2, test = c("Satterthwaite", "saddlepoint")) 68 | Wald_test(mfor_fit, constraints = constrain_zero(2:4), vcov = mfor_CR2) 69 | 70 | }) 71 | 72 | } 73 | \seealso{ 74 | \code{\link{vcovCR}} 75 | } 76 | -------------------------------------------------------------------------------- /man/vcovCR.robu.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/robu.R 3 | \name{vcovCR.robu} 4 | \alias{vcovCR.robu} 5 | \title{Cluster-robust variance-covariance matrix for a robu object.} 6 | \usage{ 7 | \method{vcovCR}{robu}(obj, cluster, type, target, inverse_var, form = "sandwich", ...) 8 | } 9 | \arguments{ 10 | \item{obj}{Fitted model for which to calculate the variance-covariance matrix} 11 | 12 | \item{cluster}{Optional expression or vector indicating which observations 13 | belong to the same cluster. If not specified, will be set to the 14 | \code{studynum} used in fitting the \code{\link[robumeta]{robu}} object.} 15 | 16 | \item{type}{Character string specifying which small-sample adjustment should 17 | be used, with available options \code{"CR0"}, \code{"CR1"}, \code{"CR1p"}, 18 | \code{"CR1S"}, \code{"CR2"}, or \code{"CR3"}. See "Details" section of 19 | \code{\link{vcovCR}} for further information.} 20 | 21 | \item{target}{Optional matrix or vector describing the working 22 | variance-covariance model used to calculate the \code{CR2} and \code{CR4} 23 | adjustment matrices. If not specified, the target is taken to be the 24 | inverse of the estimated weights used in fitting the 25 | \code{\link[robumeta]{robu}} object.} 26 | 27 | \item{inverse_var}{Optional logical indicating whether the weights used in 28 | fitting the model are inverse-variance. If not specified, \code{vcovCR} 29 | will attempt to infer a value.} 30 | 31 | \item{form}{Controls the form of the returned matrix. The default 32 | \code{"sandwich"} will return the sandwich variance-covariance matrix. 33 | Alternately, setting \code{form = "meat"} will return only the meat of the 34 | sandwich and setting \code{form = B}, where \code{B} is a matrix of 35 | appropriate dimension, will return the sandwich variance-covariance matrix 36 | calculated using \code{B} as the bread. \code{form = "estfun"} will return the 37 | (appropriately scaled) estimating function, the transposed crossproduct of 38 | which is equal to the sandwich variance-covariance matrix.} 39 | 40 | \item{...}{Additional arguments available for some classes of objects.} 41 | } 42 | \value{ 43 | An object of class \code{c("vcovCR","clubSandwich")}, which consists 44 | of a matrix of the estimated variance of and covariances between the 45 | regression coefficient estimates. 46 | } 47 | \description{ 48 | \code{vcovCR} returns a sandwich estimate of the variance-covariance matrix 49 | of a set of regression coefficient estimates from a 50 | \code{\link[robumeta]{robu}} object. 51 | } 52 | \examples{ 53 | 54 | if (requireNamespace("robumeta", quietly = TRUE)) withAutoprint({ 55 | library(robumeta) 56 | data(hierdat) 57 | 58 | robu_fit <- robu(effectsize ~ binge + followup + sreport + age, 59 | data = hierdat, studynum = studyid, 60 | var.eff.size = var, modelweights = "HIER") 61 | robu_fit 62 | 63 | robu_CR2 <- vcovCR(robu_fit, type = "CR2") 64 | robu_CR2 65 | coef_test(robu_fit, vcov = robu_CR2, test = c("Satterthwaite", "saddlepoint")) 66 | 67 | Wald_test(robu_fit, constraints = constrain_zero(c(2,4)), vcov = robu_CR2) 68 | Wald_test(robu_fit, constraints = constrain_zero(2:5), vcov = robu_CR2) 69 | 70 | }) 71 | 72 | } 73 | \seealso{ 74 | \code{\link{vcovCR}} 75 | } 76 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/AHT test.wmf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/AHT test.wmf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/AIR AHT test.wmf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/AIR AHT test.wmf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/AIR standard test.wmf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/AIR standard test.wmf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/BRL + Satt.wmf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/BRL + Satt.wmf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CRVE_sims_table.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CRVE_sims_table.xlsx -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CRVE_sims_table_full.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CRVE_sims_table_full.xlsx -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption_005-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption_005-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption_005-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption_005-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption_01-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption_01-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption_01-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption_01-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption_05-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption_05-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption_05-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption_05-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption_10-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption_10-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/absorption_10-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/absorption_10-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_005_15-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_005_15-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_005_15-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_005_15-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_005_30-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_005_30-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_005_30-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_005_30-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_005_50-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_005_50-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_005_50-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_005_50-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_01_15-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_01_15-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_01_15-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_01_15-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_01_30-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_01_30-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_01_30-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_01_30-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_01_50-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_01_50-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_01_50-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_01_50-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_05_15-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_05_15-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_05_15-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_05_15-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_05_30-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_05_30-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_05_30-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_05_30-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_05_50-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_05_50-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_05_50-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_05_50-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_10_15-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_10_15-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_10_15-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_10_15-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_10_30-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_10_30-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_10_30-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_10_30-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_10_50-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_10_50-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/balance_10_50-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/balance_10_50-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/df-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/df-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/misspecification_005-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/misspecification_005-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/misspecification_005-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/misspecification_005-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/misspecification_01-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/misspecification_01-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/misspecification_01-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/misspecification_01-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/misspecification_05-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/misspecification_05-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/misspecification_05-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/misspecification_05-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/misspecification_10-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/misspecification_10-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/misspecification_10-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/misspecification_10-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/overview-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/overview-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/overview_005-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/overview_005-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/overview_005-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/overview_005-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/overview_01-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/overview_01-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/overview_01-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/overview_01-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/overview_10-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/overview_10-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/CR_fig/overview_10-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/CR_fig/overview_10-1.png -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_FE_models.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_FE_models.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_FE_models_correction.aux: -------------------------------------------------------------------------------- 1 | \relax 2 | \providecommand\hyper@newdestlabel[2]{} 3 | \providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} 4 | \HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined 5 | \global\let\oldnewlabel\newlabel 6 | \gdef\newlabel#1#2{\newlabelxx{#1}#2} 7 | \gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} 8 | \AtEndDocument{\ifx\hyper@anchor\@undefined 9 | \let\newlabel\oldnewlabel 10 | \fi} 11 | \fi} 12 | \global\let\hyper@last\relax 13 | \gdef\HyperFirstAtBeginDocument#1{#1} 14 | \providecommand\HyField@AuxAddToFields[1]{} 15 | \providecommand\HyField@AuxAddToCoFields[2]{} 16 | \@writefile{toc}{\contentsline {section}{\numberline {1}A fixed effects model}{2}{section.1}\protected@file@percent } 17 | \newlabel{a-fixed-effects-model}{{1}{2}{A fixed effects model}{section.1}{}} 18 | \newlabel{eq:regression}{{1}{2}{A fixed effects model}{equation.1.1}{}} 19 | \@writefile{toc}{\contentsline {section}{\numberline {2}The CR2 variance estimator}{2}{section.2}\protected@file@percent } 20 | \newlabel{the-cr2-variance-estimator}{{2}{2}{The CR2 variance estimator}{section.2}{}} 21 | \newlabel{eq:B-matrix}{{3}{3}{The CR2 variance estimator}{equation.2.3}{}} 22 | \newlabel{eq:A-matrix}{{4}{3}{The CR2 variance estimator}{equation.2.4}{}} 23 | \@writefile{toc}{\contentsline {section}{\numberline {3}The original statement of Theorem 2}{3}{section.3}\protected@file@percent } 24 | \newlabel{original}{{3}{3}{The original statement of Theorem 2}{section.3}{}} 25 | \newlabel{eq:B-modified}{{5}{4}{The original statement of Theorem 2}{equation.3.5}{}} 26 | \newlabel{eq:A-modified}{{6}{4}{The original statement of Theorem 2}{equation.3.6}{}} 27 | \@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces Adjustment matrices based on weighted or unweighted least squares, calculated with or without absorbing fixed effects\relax }}{5}{table.caption.1}\protected@file@percent } 28 | \providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}} 29 | \newlabel{tab:example}{{1}{5}{Adjustment matrices based on weighted or unweighted least squares, calculated with or without absorbing fixed effects\relax }{table.caption.1}{}} 30 | \@writefile{toc}{\contentsline {section}{\numberline {4}A revised Theorem 2}{6}{section.4}\protected@file@percent } 31 | \newlabel{revised}{{4}{6}{A revised Theorem 2}{section.4}{}} 32 | \newlabel{thm:absorb}{{4}{6}{}{section.4}{}} 33 | \@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Remarks}{6}{subsection.4.1}\protected@file@percent } 34 | \newlabel{remarks}{{4.1}{6}{Remarks}{subsection.4.1}{}} 35 | \@writefile{toc}{\contentsline {subsection}{\numberline {4.2}Proof}{7}{subsection.4.2}\protected@file@percent } 36 | \newlabel{proof}{{4.2}{7}{Proof}{subsection.4.2}{}} 37 | \newlabel{eq:B_i}{{7}{7}{Proof}{equation.4.7}{}} 38 | \newlabel{eq:Btilde_i}{{8}{7}{Proof}{equation.4.8}{}} 39 | \newlabel{acknowledgements}{{4.2}{8}{Acknowledgements}{section*.2}{}} 40 | \@writefile{toc}{\contentsline {section}{Acknowledgements}{8}{section*.2}\protected@file@percent } 41 | \newlabel{supplementary-materials}{{4.2}{8}{Supplementary materials}{section*.3}{}} 42 | \@writefile{toc}{\contentsline {section}{Supplementary materials}{8}{section*.3}\protected@file@percent } 43 | \newlabel{references}{{4.2}{8}{References}{section*.4}{}} 44 | \@writefile{toc}{\contentsline {section}{References}{8}{section*.4}\protected@file@percent } 45 | \bibstyle{agsm} 46 | \bibdata{bibliography.bib} 47 | \gdef \@abspage@last{9} 48 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_FE_models_correction.out: -------------------------------------------------------------------------------- 1 | \BOOKMARK [1][-]{section.1}{\376\377\000A\000\040\000f\000i\000x\000e\000d\000\040\000e\000f\000f\000e\000c\000t\000s\000\040\000m\000o\000d\000e\000l}{}% 1 2 | \BOOKMARK [1][-]{section.2}{\376\377\000T\000h\000e\000\040\000C\000R\0002\000\040\000v\000a\000r\000i\000a\000n\000c\000e\000\040\000e\000s\000t\000i\000m\000a\000t\000o\000r}{}% 2 3 | \BOOKMARK [1][-]{section.3}{\376\377\000T\000h\000e\000\040\000o\000r\000i\000g\000i\000n\000a\000l\000\040\000s\000t\000a\000t\000e\000m\000e\000n\000t\000\040\000o\000f\000\040\000T\000h\000e\000o\000r\000e\000m\000\040\0002}{}% 3 4 | \BOOKMARK [1][-]{section.4}{\376\377\000A\000\040\000r\000e\000v\000i\000s\000e\000d\000\040\000T\000h\000e\000o\000r\000e\000m\000\040\0002}{}% 4 5 | \BOOKMARK [2][-]{subsection.4.1}{\376\377\000R\000e\000m\000a\000r\000k\000s}{section.4}% 5 6 | \BOOKMARK [2][-]{subsection.4.2}{\376\377\000P\000r\000o\000o\000f}{section.4}% 6 7 | \BOOKMARK [1][-]{section*.2}{\376\377\000A\000c\000k\000n\000o\000w\000l\000e\000d\000g\000e\000m\000e\000n\000t\000s}{}% 7 8 | \BOOKMARK [1][-]{section*.3}{\376\377\000S\000u\000p\000p\000l\000e\000m\000e\000n\000t\000a\000r\000y\000\040\000m\000a\000t\000e\000r\000i\000a\000l\000s}{}% 8 9 | \BOOKMARK [1][-]{section*.4}{\376\377\000R\000e\000f\000e\000r\000e\000n\000c\000e\000s}{}% 9 10 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_FE_models_correction.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_FE_models_correction.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_FE_models_revised.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_FE_models_revised.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_FE_models_revised_files/figure-latex/fig2-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_FE_models_revised_files/figure-latex/fig2-1.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_notes_and_variations-concordance.tex: -------------------------------------------------------------------------------- 1 | \Sconcordance{concordance:ClusterRobustTesting_notes_and_variations.tex:ClusterRobustTesting_notes_and_variations.Rnw:% 2 | 1 78 1 49 0 1 7 440 1} 3 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_notes_and_variations.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_notes_and_variations.log -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_notes_and_variations.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_notes_and_variations.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_notes_and_variations.synctex.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_notes_and_variations.synctex.gz -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials-concordance.tex: -------------------------------------------------------------------------------- 1 | \Sconcordance{concordance:ClusterRobustTesting_supplementary_materials.tex:ClusterRobustTesting_supplementary_materials.Rnw:% 2 | 1 170 1 50 0 1 15 14 1 1 3 12 1 1 3 12 1 1 2 15 1 1 7 12 1 1 7 12 % 3 | 1 1 7 12 1 1 7 12 1 1 7 12 1 1 8 12 1 1 7 12 1 1 7 12 1 1 7 12 1 1 % 4 | 7 12 1 1 7 12 1 1 7 15 1 1 13 12 1 1 5 12 1 1 5 12 1 1 5 15 1 1 4 % 5 | 12 1 1 4 12 1 1 4 12 1 1 4 6 1} 6 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials.bbl: -------------------------------------------------------------------------------- 1 | \begin{thebibliography}{xx} 2 | 3 | \harvarditem{Henderson \harvardand\ Searle}{1981}{Henderson1981on} 4 | Henderson, H.~V. \harvardand\ Searle, S.~R. \harvardyearleft 5 | 1981\harvardyearright , `{On deriving the inverse of a sum of matrices}', 6 | {\em Siam Review} {\bf 23}(1),~53--60. 7 | 8 | \end{thebibliography} 9 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials.synctex.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials.synctex.gz -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials.toc: -------------------------------------------------------------------------------- 1 | \contentsline {section}{\numberline {S1}Proof of Theorem 1}{2} 2 | \contentsline {section}{\numberline {S2}Proof of Theorem 2}{3} 3 | \contentsline {section}{\numberline {S3}Details of simulation study}{4} 4 | \contentsline {section}{\numberline {S4}Additional simulation results}{6} 5 | \contentsline {subsection}{\numberline {S4.1}Rejection rates of AHT and standard tests}{6} 6 | \contentsline {subsection}{\numberline {S4.2}Rejection rates of AHT and standard tests by study design}{9} 7 | \contentsline {subsection}{\numberline {S4.3}Rejection rates of AHT test using CR1 or CR2, with and without accounting for absorption}{21} 8 | \contentsline {subsection}{\numberline {S4.4}Rejection rates of AHT test by degree of working model misspecification}{25} 9 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials_revised.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/ClusterRobustTesting_supplementary_materials_revised.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/DID-note-concordance.tex: -------------------------------------------------------------------------------- 1 | \Sconcordance{concordance:DID-note.tex:DID-note.Rnw:% 2 | 1 83 1 50 0} 3 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/DID-note.bbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/DID-note.bbl -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/DID-note.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/DID-note.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/DID-note.synctex.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/DID-note.synctex.gz -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/JSM abstract.txt: -------------------------------------------------------------------------------- 1 | In longitudinal panel models with unobserved effects, fixed effects estimation is often paired with cluster-robust variance estimation (CRVE) in order to account for un-modeled dependence among the errors for each unit. CRVE is asymptotically consistent as the number of cross-sectional units increases, but can be biased downward for sample sizes often found in applied work, leading to hypothesis tests with overly liberal rejection rates. One solution is to use bias-reduced linearization (BRL), which corrects the CRVE so that it is unbiased under a working model, and t-tests with Satterthwaite degrees of freedom. We propose a generalization of BRL that can be applied in panel models with arbitrary sets of fixed effects, where the original BRL method is undefined, and describe how to apply the method when the regression is estimated after absorbing the fixed effects. We also propose a small-sample test for multiple-parameter hypotheses, which generalizes the Satterthwaite approximation for t-tests. In simulations covering a variety of study designs that occur in economic applications, we find that the small-sample test has Type I error very close to nominal levels. -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/R/Achievement-Awards-example.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(plm) 3 | library(clubSandwich) 4 | 5 | # load and clean data 6 | 7 | data("AchievementAwardsRCT") 8 | 9 | AA_RCT_females <- 10 | AchievementAwardsRCT %>% 11 | dplyr::filter(sex=="Girl" & year != "1999") %>% 12 | select(-sex) %>% 13 | mutate(sibs_4 = siblings >= 4, 14 | treated2001 = treated * (year=="2001")) 15 | 16 | #------------------------- 17 | # ATE model 18 | #------------------------- 19 | 20 | ATE_mod <- plm(Bagrut_status ~ year * school_type + 21 | father_ed + mother_ed + immigrant + sibs_4 + 22 | qrtl + treated2001:half, 23 | data = AA_RCT_females, 24 | index = c("school_id","student_id"), effect = "individual") 25 | 26 | trt_effects <- grepl("treated2001", names(coef(ATE_mod))) 27 | 28 | ATE_constraints <- list( 29 | "ATE - upper half (q = 1)" = constrain_zero(which(trt_effects)[2]), 30 | "ATE - joint (q = 2)" = constrain_zero(which(trt_effects)) 31 | ) 32 | 33 | # standard CRVE (CR1) 34 | ATE_CR1 <- Wald_test(ATE_mod, constraints = ATE_constraints, 35 | vcov = "CR1", test = "Naive-F") 36 | 37 | # AHT tests (CR2) 38 | ATE_CR2 <- Wald_test(ATE_mod, constraints = ATE_constraints, 39 | vcov = "CR2", test = "HTZ") 40 | 41 | #--------------------------------------------- 42 | # Model with school-by-sector interactions 43 | #--------------------------------------------- 44 | 45 | school_mod <- plm(Bagrut_status ~ year * school_type + 46 | father_ed + mother_ed + immigrant + sibs_4 + 47 | qrtl + treated2001:half + treated2001:half:school_type, 48 | data = AA_RCT_females, 49 | index = c("school_id","student_id"), effect = "individual") 50 | 51 | school_effects <- grepl("school_type.*treated2001", names(coef(school_mod))) 52 | 53 | school_constraints <- list( 54 | "Moderation - upper half (q = 2)" = constrain_zero(which(school_effects)[3:4]), 55 | "Moderation - joint (q = 4)" = constrain_zero(which(school_effects)) 56 | ) 57 | 58 | # standard CRVE (CR1) 59 | mod_CR1 <- Wald_test(school_mod, constraints = school_constraints, 60 | vcov = "CR1", test = "Naive-F") 61 | 62 | # AHT tests (CR2) 63 | mod_CR2 <- Wald_test(school_mod, constraints = school_constraints, 64 | vcov = "CR2", test = "HTZ") 65 | 66 | #--------------------------------------- 67 | # Arrange test results in a table 68 | #--------------------------------------- 69 | 70 | ATE_CR1 <- bind_rows(ATE_CR1, .id = "Hypothesis") %>% as.data.frame() 71 | ATE_CR2 <- bind_rows(ATE_CR2, .id = "Hypothesis") %>% as.data.frame() 72 | ATEs <- 73 | bind_rows( 74 | "Standard" = ATE_CR1, 75 | "AHT" = ATE_CR2, 76 | .id = "Test" 77 | ) %>% 78 | arrange(desc(Hypothesis)) 79 | 80 | mod_CR1 <- bind_rows(mod_CR1, .id = "Hypothesis") %>% as.data.frame() 81 | mod_CR2 <- bind_rows(mod_CR2, .id = "Hypothesis") %>% as.data.frame() 82 | mods <- 83 | bind_rows( 84 | "Standard" = mod_CR1, 85 | "AHT" = mod_CR2, 86 | .id = "Test" 87 | ) %>% 88 | arrange(desc(Hypothesis)) 89 | 90 | AL_results <- 91 | bind_rows(ATEs, mods) %>% 92 | select(Hypothesis, Test, F = Fstat, df = df_denom, p = p_val) %>% 93 | mutate(Hypothesis = ifelse(Test=="AHT",NA,Hypothesis)) 94 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/R/MLDA-example.R: -------------------------------------------------------------------------------- 1 | library(plm) 2 | library(nlme) 3 | library(clubSandwich) 4 | 5 | data(MortalityRates) 6 | 7 | # subset for deaths in motor vehicle accidents, 1970-1983 8 | MV_deaths <- subset(MortalityRates, cause=="Motor Vehicle" & 9 | year <= 1983 & !is.na(beertaxa), 10 | select = -cause) 11 | 12 | 13 | #------------------------ 14 | # Random effects 15 | #------------------------ 16 | 17 | RE_fit <- lme(mrate ~ legal + beertaxa + factor(year), data = MV_deaths, random = ~ 1 | state) 18 | 19 | RE_CR1 <- Wald_test(RE_fit, constraints = constrain_zero(2), vcov = "CR1", test = "Naive-F") 20 | RE_CR2 <- Wald_test(RE_fit, constraints = constrain_zero(2), vcov = "CR2", test = "HTZ") 21 | 22 | #------------------------ 23 | # Fixed effects 24 | #------------------------ 25 | 26 | FE_fit <- plm(mrate ~ legal + beertaxa, data = MV_deaths, 27 | effect = "twoways", index = c("state","year")) 28 | FE_CR1 <- Wald_test(FE_fit, constraints = constrain_zero(1), vcov = "CR1", 29 | cluster = MV_deaths$state, test = "Naive-F") 30 | FE_CR2 <- Wald_test(FE_fit, constraints = constrain_zero(1), vcov = "CR2", 31 | cluster = MV_deaths$state, test = "HTZ") 32 | 33 | #------------------------ 34 | # Hausmann tests 35 | #------------------------ 36 | 37 | MV_deaths <- within(MV_deaths, { 38 | legal_cent <- legal - tapply(legal, state, mean)[factor(state)] 39 | beertaxa_cent <- beertaxa - tapply(beertaxa, state, mean)[factor(state)] 40 | }) 41 | 42 | Hausman_fit <- lme(mrate ~ legal + beertaxa + legal_cent + beertaxa_cent + factor(year), 43 | data = MV_deaths, random = ~ 1 | state) 44 | Haus_CR1 <- Wald_test(Hausman_fit, constraints = constrain_zero(4:5), vcov = "CR1", test = "Naive-F") 45 | Haus_CR2 <- Wald_test(Hausman_fit, constraints = constrain_zero(4:5), vcov = "CR2", test = "HTZ") 46 | 47 | 48 | RE_tests <- bind_rows("Standard" = RE_CR1, "AHT" = RE_CR2, .id = "Test") %>% as.data.frame() 49 | FE_tests <- bind_rows("Standard" = FE_CR1, "AHT" = FE_CR2, .id = "Test") %>% as.data.frame() 50 | Hausman_tests <- bind_rows("Standard" = Haus_CR1, "AHT" = Haus_CR2, .id = "Test") %>% as.data.frame() 51 | 52 | 53 | MLDA_results <- 54 | bind_rows( 55 | "Random effects" = RE_tests, 56 | "Fixed effects" = FE_tests, 57 | "Hausman test" = Hausman_tests, 58 | .id = "Hypothesis" 59 | ) %>% 60 | select(Hypothesis, Test, "F" = Fstat, df = df_denom, p = p_val) %>% 61 | mutate(Hypothesis = ifelse(Test=="AHT", NA, Hypothesis)) 62 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/R/Panel simulation results.Rdata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/R/Panel simulation results.Rdata -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/R/figures for AIR.R: -------------------------------------------------------------------------------- 1 | rm(list=ls()) 2 | setwd("paper_ClusterRobustTesting") 3 | source("R/format results for figures.R") 4 | 5 | # standard test 6 | 7 | filter(results_long, alpha == .05 & test == "CR1 standard") %>% 8 | mutate(q_fac = paste("q =",q,ifelse(q==1, "(t-test)", "(F-test)"))) %>% 9 | ggplot(aes(m_fac, reject)) + 10 | geom_boxplot(coef = Inf, fill = "blue") + 11 | geom_blank(data = zeros_long) + 12 | geom_hline(aes(yintercept = alpha)) + 13 | geom_hline(aes(yintercept = UB), linetype = "dashed") + 14 | facet_wrap(~ q_fac, ncol = 2, scales = "free") + 15 | labs(x = NULL, y = "Rejection rate") + 16 | theme_bw() + theme(legend.position = "none") 17 | ggsave("AIR standard test.wmf", width = 8, height = 5) 18 | 19 | # AHT test 20 | filter(results_long, alpha == .05 & test %in% c("CR1 standard", "CR2 AHT")) %>% 21 | ggplot(aes(m_fac, reject, fill = test_lab)) + 22 | geom_boxplot(coef = Inf) + 23 | geom_blank(data = filter(zeros_long, test %in% c("CR1 standard", "CR2 AHT"))) + 24 | geom_hline(aes(yintercept = alpha)) + 25 | geom_hline(aes(yintercept = UB), linetype = "dashed") + 26 | scale_y_continuous(breaks = breaks_cut(.05)) + 27 | facet_wrap(~ test_q, ncol = 4, scales = "free") + 28 | labs(x = NULL, y = "Rejection rate") + 29 | theme_bw() + theme(legend.position = "none") 30 | ggsave("AIR AHT test.wmf", width = 10, height = 5) 31 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/R/figures for PRC.R: -------------------------------------------------------------------------------- 1 | library(tidyr) 2 | library(dplyr) 3 | library(ggplot2) 4 | library(stringr) 5 | rm(list=ls()) 6 | setwd("paper_ClusterRobustTesting") 7 | source("R/format results for figures.R") 8 | 9 | # standard test 10 | 11 | filter(results_long, alpha == .05 & test == "Standard") %>% 12 | mutate(q_fac = paste("q =",q,ifelse(q==1, "(t-test)", "(F-test)"))) %>% 13 | ggplot(aes(m_fac, reject)) + 14 | geom_boxplot(coef = Inf, fill = "blue") + 15 | geom_blank(data = zeros_long) + 16 | geom_hline(aes(yintercept = alpha)) + 17 | geom_hline(aes(yintercept = UB), linetype = "dashed") + 18 | facet_wrap(~ q_fac, ncol = 2, scales = "free") + 19 | labs(x = NULL, y = "Rejection rate") + 20 | theme_bw() + theme(legend.position = "none") 21 | ggsave("standard test.wmf", width = 8, height = 5) 22 | 23 | # BRL + Satterthwaite t-test 24 | 25 | filter(results_long, alpha == .05 & q == 1) %>% 26 | mutate(test_lab = ifelse(test=="AHT","BRL + Satterthwaite t-test","Standard t-test")) %>% 27 | ggplot(aes(m_fac, reject, fill = test)) + 28 | geom_boxplot(coef = Inf) + 29 | geom_blank(data = zeros_long) + 30 | geom_hline(aes(yintercept = alpha)) + 31 | geom_hline(aes(yintercept = UB), linetype = "dashed") + 32 | facet_wrap(~ test_lab) + 33 | labs(x = NULL, y = "Rejection rate") + 34 | theme_bw() + theme(legend.position = "none") 35 | ggsave("BRL + Satt.wmf", width = 7, height = 3.5) 36 | 37 | # AHT test 38 | 39 | filter(results_long, alpha == .05 & q != 1) %>% 40 | mutate(q_fac = paste("q =",q, "(F-test)")) %>% 41 | droplevels() %>% 42 | ggplot(aes(m_fac, reject, fill = test)) + 43 | geom_boxplot(coef = Inf) + 44 | geom_blank(data = zeros_long) + 45 | geom_hline(aes(yintercept = alpha)) + 46 | geom_hline(aes(yintercept = UB), linetype = "dashed") + 47 | facet_grid(test ~ q_fac, scales = "free") + 48 | labs(x = NULL, y = "Rejection rate") + 49 | theme_bw() + theme(legend.position = "none") 50 | ggsave("AHT test.wmf", width = 8, height = 5) 51 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/R/run_panel_simulation.slurm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #SBATCH -J CRVE # Job name 3 | #SBATCH -o CRVE.o%j # Name of stdout output file (%j expands to jobId) 4 | #SBATCH -e CRVE.o%j # Name of stderr output file(%j expands to jobId) 5 | #SBATCH -p normal # Submit to the 'normal' or 'development' queue 6 | #SBATCH -N 8 # Total number of nodes 7 | #SBATCH -n 128 # Total number of mpi tasks requested 8 | #SBATCH -t 8:00:00 # Run time (hh:mm:ss) 9 | #SBATCH --mail-user=jepusto@gmail.com 10 | #SBATCH --mail-type=begin 11 | #SBATCH --mail-type=end 12 | 13 | # load R module 14 | module load Rstats 15 | 16 | # call R code from RMPISNOW 17 | ibrun RMPISNOW < ./panel_simulation_for_TACC.R 18 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/R/unbalanced panel example.R: -------------------------------------------------------------------------------- 1 | library(foreign) 2 | library(tidyr) 3 | library(dplyr) 4 | library(ggplot2) 5 | library(plm) 6 | 7 | deaths <- read.dta("paper_ClusterRobustTesting/data/deaths.dta") 8 | 9 | filter(deaths, agegr=="18-20 yrs" & year <= 1983 & dtype == "MVA" & !is.na(beertaxa)) %>% 10 | select(-agegr, -dtype) %>% 11 | group_by(state) %>% 12 | mutate(legal_s = legal - mean(legal), 13 | beertaxa_s = beertaxa - mean(beertaxa)) %>% 14 | as.data.frame() -> 15 | death_dat 16 | 17 | death_dat$mrate_miss <- death_dat$mrate 18 | death_dat$mrate_miss[sample(nrow(death_dat), size = 100)] <- NA 19 | 20 | var_names <- c("legal","beertaxa") 21 | lm_fit <- lm(mrate_miss ~ 0 + legal + beertaxa + factor(state) + factor(year), data = death_dat) 22 | CR2_iv_lm <- vcovCR(lm_fit, cluster = death_dat$state, type = "CR2") 23 | CR2_iv_lm[var_names, var_names] 24 | vcovCR(lm_fit, cluster = death_dat$state, type = "CR2", inverse_var = FALSE)[var_names, var_names] 25 | plm_fit <- plm(mrate_miss ~ legal + beertaxa, data = death_dat, 26 | index = c("state", "year"), effect = "twoways", model = "within") 27 | coef(lm_fit)[var_names] 28 | coef(plm_fit) 29 | vcovCR(plm_fit, cluster = "individual", type = "CR2") 30 | vcovCR(plm_fit, cluster = death_dat$state, type = "CR2", inverse_var = FALSE) 31 | 32 | 33 | #------------------------ 34 | # Compute A matrices 35 | #------------------------ 36 | 37 | cluster <- with(death_dat, as.factor(state[!is.na(mrate_miss)])) 38 | 39 | X <- model.matrix(lm_fit) 40 | X_names <- colnames(X) 41 | R <- X[,var_names] 42 | S <- X[,grepl("year",X_names)] 43 | T <- X[,grepl("state",X_names)] 44 | 45 | Sp <- residuals(lm.fit(T, S)) 46 | Rp <- residuals(lm.fit(Sp, residuals(lm.fit(T, R)))) 47 | Up <- residuals(lm.fit(T, cbind(R, S))) 48 | 49 | R_list <- matrix_list(Rp, cluster, "row") 50 | U_list <- matrix_list(Up, cluster, "row") 51 | T_list <- matrix_list(T, cluster, "row") 52 | M_R <- chol2inv(chol(crossprod(Rp))) 53 | M_U <- chol2inv(chol(crossprod(Up))) 54 | M_T <- chol2inv(chol(crossprod(T))) 55 | IH_list <- IH_jj_list(M = M_U, X_list = U_list, XW_list = lapply(U_list, t)) 56 | A_mats <- lapply(IH_list, Sym_power, p = -1/2) 57 | terms <- Map(function(t_mat, a, r) t(t_mat) %*% a %*% r, t_mat = T_list, a = A_mats, r = R_list) 58 | meat <- Reduce("+", lapply(terms, function(x) t(x) %*% M_T %*% x)) 59 | M_R %*% meat %*% M_R 60 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/STAR_test_results.Rdata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/STAR_test_results.Rdata -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/Simulation Plan.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/Simulation Plan.docx -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/abstract.txt: -------------------------------------------------------------------------------- 1 | Cluster-robust variance estimation (CRVE) is commonly used to account for heteroskedasticity and un-modeled dependence among the errors in regression models with unobserved effects. Although asymptotically consist, CRVE can be biased downward when the number of clusters is small, leading to hypothesis tests with overly liberal rejection rates. One solution is to use bias-reduced linearization (BRL), which corrects the CRVE based on a working model, in conjunction with t-tests with Satterthwaite degrees of freedom. We propose a generalization of BRL that can be applied in models with arbitrary sets of fixed effects, where the original BRL method is undefined. We also propose a small-sample test for multiple-parameter hypotheses, which generalizes the Satterthwaite approximation for t-tests. In simulations covering a variety of scenarios, we find that conventional cluster-robust Wald tests can severely under-reject while the proposed small-sample test maintains Type I error close to nominal levels. -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/custom.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | font-size:1.8em; 3 | color: #000cb4; 4 | } 5 | slides > slide { 6 | color: #000000; 7 | } 8 | slides > slide.title-slide hgroup h1 { 9 | font-weight: bold; 10 | color: #000cb4; 11 | } 12 | slides > slide.title-slide hgroup h2 { 13 | color: black; 14 | } 15 | img[alt="minipic"] { 16 | max-width: 10px; 17 | display: block; 18 | } -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/data/AngristLavy_AERdata/base00.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/data/AngristLavy_AERdata/base00.dta -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/data/AngristLavy_AERdata/base01.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/data/AngristLavy_AERdata/base01.dta -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/data/AngristLavy_AERdata/base02.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/data/AngristLavy_AERdata/base02.dta -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/data/AngristLavy_AERdata/base99.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/data/AngristLavy_AERdata/base99.dta -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/data/AngristLavy_AERdata/readme.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/data/AngristLavy_AERdata/readme.doc -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/data/deaths.dta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/data/deaths.dta -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/panel_simulation_notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/panel_simulation_notes.pdf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/simulation_table.aux: -------------------------------------------------------------------------------- 1 | \relax 2 | \@setckpt{simulation_table}{ 3 | \setcounter{page}{22} 4 | \setcounter{equation}{13} 5 | \setcounter{enumi}{0} 6 | \setcounter{enumii}{0} 7 | \setcounter{enumiii}{0} 8 | \setcounter{enumiv}{0} 9 | \setcounter{footnote}{4} 10 | \setcounter{mpfootnote}{0} 11 | \setcounter{part}{0} 12 | \setcounter{section}{4} 13 | \setcounter{subsection}{1} 14 | \setcounter{subsubsection}{0} 15 | \setcounter{paragraph}{0} 16 | \setcounter{subparagraph}{0} 17 | \setcounter{figure}{0} 18 | \setcounter{table}{1} 19 | \setcounter{firstpage}{0} 20 | \setcounter{lastpage}{0} 21 | \setcounter{thanks}{1} 22 | \setcounter{author}{2} 23 | \setcounter{address}{0} 24 | \setcounter{addressref}{0} 25 | \setcounter{parentequation}{0} 26 | \setcounter{BibCnt}{0} 27 | \setcounter{NAT@ctr}{0} 28 | \setcounter{float@type}{4} 29 | \setcounter{r@tfl@t}{0} 30 | \setcounter{@todonotes@numberoftodonotes}{4} 31 | \setcounter{thm}{2} 32 | \setcounter{lem}{0} 33 | \setcounter{maskedRefs}{0} 34 | } 35 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/simulation_table.tex: -------------------------------------------------------------------------------- 1 | \begin{tabular}{lc cccc c cccc} 2 | \toprule 3 | & & \multicolumn{4}{c}{Data generation} & & \multicolumn{4}{c}{Type I error ($\alpha = .05$)} \\ \cmidrule{3-6} \cmidrule{8-11} 4 | & & & & \multirow{2}{1.5cm}{Error structure} & \multirow{2}{1.5cm}{Covariate type(s)} & \multirow{2}{1.5cm}{Working model} & \multicolumn{2}{c}{Standard} & \multicolumn{2}{c}{AHT} \\ 5 | Article & Table & $m$ & $n$ & & & & Min & Max & Min & Max \\ \midrule 6 | BM 2002 & 2 & 20 & 10 & RE(3) & c[50\%, 15\%, M], o[M] & I & .05 & .16 & .03 & .05 \\ 7 | CM 2015 & 2 & 6-50 & ~260 & IPUMS-CPS & c[50\%] & RE & .07 & .11 & .05 & .05 \\ \midrule 8 | \multirow{7}{1.5cm}{IK 2015} & 1 & 30 & 1 & H(5) & c[10\%] & I & .12 & .22 & .01 & .05 \\ 9 | & 2 & 30 & 1 & H(5); LN & c[10\%] & I & .07 & .32 & .00 & .13 \\ 10 | & 3 & 30 & 1 & H(5) & c[50\%] & I & .05 & .05 & .05 & .05 \\ 11 | & 4 & 5-10 & 10-60 & RE; RE+H & c[M] & I; RE & .08 & .13 & .03 & .06 \\ 12 | & 5 & 50 & 6 & RE & c[50\%] & I; RE & .06 & .06 & .05 & .05 \\ 13 | & 5 & 50 & 6 & RE; RE+H & c[6\%] & I; RE & .15 & .23 & .01 & .05 \\ 14 | & 5 & 50 & 6 & RE & c[K] & I; RE & .13 & .13 & .03 & .03 \\ \midrule 15 | \multirow{8}{1.5cm}{T 2015} & 1 & 10-40 & 1-10 & RE + C(9) & c[50\%] & H & .05 & .05 & .04 & .05 \\ 16 | & 1 & 10-40 & 1-10 & RE + C(9) & c[15\%] & H & .10 & .15 & .04 & .05 \\ 17 | & 1 & 10-40 & 1-10 & RE + C(9) & o[10\%] & H & .04 & .19 & .04 & .06 \\ 18 | & 1 & 10-40 & 1-10 & RE + C(9) & c[M] & H & .07 & .13 & .04 & .05 \\ 19 | & 1 & 10-40 & 1-10 & RE + C(9) & o[M] & H & .06 & .12 & .04 & .06 \\ 20 | & 1 & 10-40 & 1-10 & RE + C(9) & o[K] & H & .03 & .28 & .01 & .04 \\ 21 | & 2 & 20 & 1-10 & RE + C(9) & c[10\%,M], o[10\%, M] & H & .01 & .12 & .01 & .06 \\ 22 | & 2 & 20 & 1-10 & RE + C(9) & c[30\%,M], o[30\%, M] & H & .02 & .06 & .01 & .06 \\ 23 | \bottomrule 24 | \end{tabular} 25 | 26 | 27 | -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/standard test.wmf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/paper_ClusterRobustTesting/standard test.wmf -------------------------------------------------------------------------------- /paper_ClusterRobustTesting/summary rejection rates from simulation.csv: -------------------------------------------------------------------------------- 1 | "p","q","T-sq Z - min","T-sq Z - max","Naive F - min","Naive F - max" 2 | 5,5,0,0.04,0.0654,0.2246 3 | 5,4,0,0.052,0.047,0.1963 4 | 5,3,0,0.0567,0.0031,0.1855 5 | 5,2,0,0.0571,0.0011,0.1664 6 | 4,4,0,0.0512,0.0563,0.221 7 | 3,3,0,0.0556,0.049,0.2181 8 | 2,2,0,0.0564,0.018,0.1896 9 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(clubSandwich) 3 | 4 | test_check("clubSandwich") 5 | -------------------------------------------------------------------------------- /tests/testthat/test_conf_int.R: -------------------------------------------------------------------------------- 1 | context("confidence intervals") 2 | set.seed(20190513) 3 | 4 | skip_if_not_installed("nlme") 5 | 6 | library(nlme, quietly=TRUE, warn.conflicts=FALSE) 7 | 8 | data(Ovary, package = "nlme") 9 | 10 | Ovary$time_int <- 1:nrow(Ovary) 11 | 12 | gls_fit <- gls(follicles ~ sin(2*pi*Time) + cos(2*pi*Time), data = Ovary, 13 | correlation = corAR1(form = ~ time_int | Mare), 14 | weights = varPower()) 15 | 16 | CRs <- paste0("CR", 0:4) 17 | 18 | test_that("vcov arguments work", { 19 | VCR <- lapply(CRs, function(t) vcovCR(gls_fit, type = t)) 20 | CI_A <- lapply(VCR, function(v) conf_int(gls_fit, vcov = v, level = .98)) 21 | CI_B <- lapply(CRs, function(t) conf_int(gls_fit, vcov = t, level = .98)) 22 | expect_equal(CI_A, CI_B) 23 | }) 24 | 25 | test_that("coefs argument works", { 26 | which_grid <- expand.grid(rep(list(c(FALSE,TRUE)), length(coef(gls_fit)))) 27 | tests_all <- conf_int(gls_fit, vcov = "CR0", coefs = "All") 28 | 29 | CI_A <- apply(which_grid[-1,], 1, function(x) tests_all[x,]) 30 | CI_B <- apply(which_grid[-1,], 1, function(x) conf_int(gls_fit, vcov = "CR0", coefs = x)) 31 | expect_equal(CI_A, CI_B) 32 | }) 33 | 34 | test_that("printing works", { 35 | CIs <- conf_int(gls_fit, vcov = "CR0") 36 | expect_output(print(CIs)) 37 | 38 | CIs <- conf_int(gls_fit, vcov = "CR0", p_values = TRUE) 39 | expect_output(x <- print(CIs)) 40 | expect_true(all(c("p-value","Sig.") %in% names(x))) 41 | }) 42 | 43 | test_that("level checks work", { 44 | expect_error(conf_int(gls_fit, vcov = "CR0", level = -0.01)) 45 | expect_error(conf_int(gls_fit, vcov = "CR0", level = 95)) 46 | expect_output(print(conf_int(gls_fit, vcov = "CR0", level = runif(1)))) 47 | }) 48 | 49 | test_that("CI boundaries are ordered", { 50 | lev <- runif(1) 51 | CI_z <- conf_int(gls_fit, vcov = "CR0", test = "z", level = lev) 52 | CI_t <- conf_int(gls_fit, vcov = "CR0", test = "naive-t", level = lev) 53 | CI_Satt <- conf_int(gls_fit, vcov = "CR0", test = "Satterthwaite", level = lev) 54 | expect_true(all(CI_t$CI_L < CI_z$CI_L)) 55 | expect_true(all(CI_t$CI_U > CI_z$CI_U)) 56 | expect_true(all(CI_Satt$CI_L < CI_z$CI_L)) 57 | expect_true(all(CI_Satt$CI_U > CI_z$CI_U)) 58 | }) 59 | 60 | test_that("conf_int() is consistent with coef_test()", { 61 | 62 | lev <- runif(1) 63 | CIs <- lapply(CRs, function(v) conf_int(gls_fit, vcov = v, test = "Satterthwaite", level = lev, p_values = TRUE)) 64 | ttests <- lapply(CRs, function(v) coef_test(gls_fit, vcov = v, test = "Satterthwaite")) 65 | CI_L <- lapply(ttests, function(x) x$beta - x$SE * qt(1 - (1 - lev) / 2, df = x$df)) 66 | CI_U <- lapply(ttests, function(x) x$beta + x$SE * qt(1 - (1 - lev) / 2, df = x$df)) 67 | expect_equal(lapply(CIs, function(x) x$CI_L), CI_L) 68 | expect_equal(lapply(CIs, function(x) x$CI_U), CI_U) 69 | expect_equal(lapply(CIs, function(x) x$p_val), lapply(ttests, function(x) x$p_Satt)) 70 | 71 | lev <- runif(1) 72 | CIs <- lapply(CRs, function(v) conf_int(gls_fit, vcov = v, test = "naive-t", level = lev, p_values = TRUE)) 73 | ttests <- lapply(CRs, function(v) coef_test(gls_fit, vcov = v, test = "naive-t")) 74 | CI_L <- lapply(ttests, function(x) x$beta - x$SE * qt(1 - (1 - lev) / 2, df = x$df)) 75 | CI_U <- lapply(ttests, function(x) x$beta + x$SE * qt(1 - (1 - lev) / 2, df = x$df)) 76 | expect_equal(lapply(CIs, function(x) x$CI_L), CI_L) 77 | expect_equal(lapply(CIs, function(x) x$CI_U), CI_U) 78 | expect_equal(lapply(CIs, function(x) x$p_val), lapply(ttests, function(x) x$p_t)) 79 | 80 | lev <- runif(1) 81 | CIs <- lapply(CRs, function(v) conf_int(gls_fit, vcov = v, test = "z", level = lev, p_values = TRUE)) 82 | ttests <- lapply(CRs, function(v) coef_test(gls_fit, vcov = v, test = "z")) 83 | CI_L <- lapply(ttests, function(x) x$beta - x$SE * qt(1 - (1 - lev) / 2, df = x$df)) 84 | CI_U <- lapply(ttests, function(x) x$beta + x$SE * qt(1 - (1 - lev) / 2, df = x$df)) 85 | expect_equal(lapply(CIs, function(x) x$CI_L), CI_L) 86 | expect_equal(lapply(CIs, function(x) x$CI_U), CI_U) 87 | expect_equal(lapply(CIs, function(x) x$p_val), lapply(ttests, function(x) x$p_z)) 88 | 89 | }) 90 | 91 | test_that("conf_int has informative error messages.", { 92 | expect_error( 93 | conf_int(gls_fit, vcov = "CR0", test = "all") 94 | ) 95 | 96 | expect_error( 97 | conf_int(gls_fit, vcov = "CR0", test = "saddlepoint") 98 | ) 99 | }) 100 | -------------------------------------------------------------------------------- /tests/testthat/test_estfun.R: -------------------------------------------------------------------------------- 1 | context("estfun objects") 2 | 3 | skip_if_not_installed("zoo") 4 | skip_if_not_installed("AER") 5 | 6 | library(zoo, quietly=TRUE) 7 | library(AER, quietly=TRUE) 8 | 9 | CR_types <- paste0("CR",0:4) 10 | 11 | data("CigarettesSW", package = "AER") 12 | 13 | Cigs <- within(CigarettesSW, { 14 | rprice <- price/cpi 15 | rincome <- income/population/cpi 16 | tdiff <- (taxs - tax)/cpi 17 | }) 18 | 19 | obj_un <- ivreg(log(packs) ~ log(rprice) + log(rincome) + I(tax/cpi) | log(rincome) + tdiff + I(tax/cpi), 20 | data = Cigs) 21 | obj_wt <- ivreg(log(packs) ~ log(rprice) + log(rincome) + I(tax/cpi) | log(rincome) + tdiff + I(tax/cpi), 22 | data = Cigs, 23 | weights = population) 24 | 25 | red_form_un <- lm(log(packs) ~ log(rincome) + I(tax/cpi) + tdiff, data = Cigs) 26 | red_form_wt <- lm(log(packs) ~ log(rincome) + I(tax/cpi) + tdiff, data = Cigs, weights = population) 27 | stage1_un <- lm(log(rprice) ~ log(rincome) + I(tax/cpi) + tdiff, data = Cigs) 28 | stage1_wt <- lm(log(rprice) ~ log(rincome) + I(tax/cpi) + tdiff, data = Cigs, weights = population) 29 | 30 | test_that("estfun works for lm.", { 31 | 32 | V_CR <- lapply(CR_types, function(type) as.matrix(vcovCR(obj = red_form_un, cluster = Cigs$state, type = type))) 33 | e_CR <- lapply(CR_types, function(type) vcovCR(obj = red_form_un, cluster = Cigs$state, type = type, form = "estfun")) 34 | expect_equal(lapply(e_CR, tcrossprod), V_CR) 35 | 36 | V_CR <- lapply(CR_types, function(type) as.matrix(vcovCR(obj = red_form_wt, cluster = Cigs$state, type = type))) 37 | e_CR <- lapply(CR_types, function(type) vcovCR(obj = red_form_wt, cluster = Cigs$state, type = type, form = "estfun")) 38 | expect_equal(lapply(e_CR, tcrossprod), V_CR) 39 | 40 | V_CR <- lapply(CR_types, function(type) as.matrix(vcovCR(obj = stage1_un, cluster = Cigs$state, type = type))) 41 | e_CR <- lapply(CR_types, function(type) vcovCR(obj = stage1_un, cluster = Cigs$state, type = type, form = "estfun")) 42 | expect_equal(lapply(e_CR, tcrossprod), V_CR) 43 | 44 | V_CR <- lapply(CR_types, function(type) as.matrix(vcovCR(obj = stage1_wt, cluster = Cigs$state, type = type))) 45 | e_CR <- lapply(CR_types, function(type) vcovCR(obj = stage1_wt, cluster = Cigs$state, type = type, form = "estfun")) 46 | expect_equal(lapply(e_CR, tcrossprod), V_CR) 47 | 48 | }) 49 | 50 | test_that("stacked estimating equations are equivalent to 2SLS.", { 51 | 52 | e_CR <- lapply(CR_types, function(type) vcovCR(obj = red_form_un, cluster = Cigs$state, type = type, form = "estfun")) 53 | f_CR <- lapply(CR_types, function(type) vcovCR(obj = stage1_un, cluster = Cigs$state, type = type, form = "estfun")) 54 | 55 | V_CR_stack <- mapply(function(x, y) tcrossprod(rbind(x, y)), x = e_CR, y = f_CR, SIMPLIFY = FALSE) 56 | gamma <- coef(stage1_un)["tdiff"] 57 | beta <- coef(red_form_un)["tdiff"] 58 | delta <- beta / gamma 59 | 60 | V_CR_2SLS <- lapply(CR_types, function(type) vcovCR(obj = obj_un, cluster = Cigs$state, type = type)) 61 | V_CR_2SLS <- sapply(V_CR_2SLS, function(x) diag(x)["log(rprice)"]) 62 | V_delta <- sapply(V_CR_stack, function(x) sum(x[c(4,8), c(4,8)] * tcrossprod(c(1,-delta))) / gamma^2) 63 | }) 64 | -------------------------------------------------------------------------------- /tests/testthat/test_ignore_absorption.R: -------------------------------------------------------------------------------- 1 | context("ignoring absorbed fixed effects") 2 | set.seed(20190513) 3 | 4 | skip_if_not_installed("plm") 5 | 6 | library(plm) 7 | 8 | data(MortalityRates) 9 | MV_Mortality <- subset(MortalityRates, cause=="Motor Vehicle" & state %in% 1:8) 10 | table(MV_Mortality$state) 11 | MV_Mortality$state_fac <- factor(MV_Mortality$state) 12 | # MV_Mortality$pop <- with(MV_Mortality, 1 + rbinom(nlevels(state_fac), size = 4, prob = 0.5)[state_fac]) 13 | summary(MV_Mortality$pop) 14 | MV_Mortality$pop_scale <- with(MV_Mortality, pop / mean(pop)) 15 | summary(MV_Mortality$pop_scale) 16 | 17 | # model specification 18 | 19 | specification <- mrate ~ 0 + legal + beertaxa + beerpercap + winepercap + factor(state) 20 | 21 | #----------------------- 22 | # unweighted 23 | #----------------------- 24 | 25 | ols_LSDV <- lm(specification, data = MV_Mortality) 26 | ols_within <- plm(update(specification, . ~ . - 0 - factor(state)), data = MV_Mortality, effect = "individual", index = c("state","year")) 27 | 28 | test_that("Unweighted lsdv and within estimators are equivalent", { 29 | lsdv <- coef_test(ols_LSDV, vcov = "CR2", cluster = MV_Mortality$state, coefs = 1:4, p_values = FALSE) 30 | wthn <- coef_test(ols_within, vcov = "CR2", p_values = FALSE) 31 | expect_equal(lsdv, wthn) 32 | }) 33 | 34 | #----------------------- 35 | # iv-weights 36 | #----------------------- 37 | 38 | wls_LSDV <- lm(specification, weights = pop_scale, data = MV_Mortality) 39 | 40 | MV_Mortality_full <- model.frame(lm(specification, weights = pop_scale, data = MV_Mortality)) 41 | U_mat <- model.matrix(update(specification, . ~ . - factor(state)), data = MV_Mortality_full) 42 | T_mat <- model.matrix(~ factor(state), data = MV_Mortality_full) 43 | w <- MV_Mortality_full$"(weights)" 44 | state <- MV_Mortality_full$"factor(state)" 45 | U_absorb <- residuals(stats:::lm.wfit(x = T_mat, y = U_mat, w = w))[,-31] 46 | Y_absorb <- residuals(stats:::lm.wfit(x = T_mat, y = MV_Mortality_full$mrate, w = w)) 47 | wls_within <- lm(Y_absorb ~ 0 + U_absorb, weights = w) 48 | 49 | test_that("Inverse-variance weighted lsdv and within estimators are equivalent.", { 50 | lsdv <- coef_test(wls_LSDV, vcov = "CR2", cluster = MV_Mortality$state, inverse_var = TRUE, p_values = FALSE)[1:4,] 51 | wthn <- coef_test(wls_within, vcov = "CR2", cluster = state, inverse_var = TRUE, p_values = FALSE)[1:4,] 52 | expect_equal(lsdv$beta, wthn$beta, check.attributes = FALSE, tolerance = 10^-5) 53 | expect_equal(lsdv$SE, wthn$SE, check.attributes = FALSE, tolerance = 10^-2) 54 | expect_equal(lsdv$tstat, wthn$tstat, check.attributes = FALSE, tolerance = 10^-2) 55 | expect_equal(lsdv$df_Satt, wthn$df_Satt, check.attributes = FALSE, tolerance = 10^-2) 56 | }) 57 | 58 | #----------------------- 59 | # p-weights 60 | #----------------------- 61 | 62 | test_that("Probability-weighted lsdv and within estimators are not necessarily equivalent.", { 63 | lsdv <- coef_test(wls_LSDV, vcov = "CR2", cluster = MV_Mortality$state, inverse_var = FALSE, coefs = 1:4, p_values = FALSE) 64 | wthn <- coef_test(wls_within, vcov = "CR2", cluster = state, inverse_var = FALSE, p_values = FALSE) 65 | expect_equal(lsdv$beta, wthn$beta, check.attributes = FALSE, tolerance = 10^-5) 66 | expect_equal(lsdv$SE, wthn$SE, check.attributes = FALSE, tolerance = 10^-2) 67 | expect_equal(lsdv$tstat, wthn$tstat, check.attributes = FALSE, tolerance = 10^-2) 68 | expect_equal(lsdv$df_Satt, wthn$df_Satt, check.attributes = FALSE, tolerance = 10^-2) 69 | }) 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /tests/testthat/test_intercept_formulas.R: -------------------------------------------------------------------------------- 1 | context("population mean estimation") 2 | set.seed(20190513) 3 | 4 | m <- 14 5 | icc <- 0.2 6 | mu <- 5 7 | size <- 2 8 | nj <- 1 + rnbinom(m, size = size, mu = mu) 9 | group <- factor(rep(LETTERS[1:m], nj)) 10 | N <- sum(nj) 11 | 12 | Y <- rnorm(m, sd = sqrt(icc))[group] + rnorm(N, sd = sqrt(1 - icc)) 13 | y_bar <- tapply(Y, group, mean) 14 | lm_fit <- lm(Y ~ 1) 15 | 16 | test_that("CR0 and df agree with formulas", { 17 | CR0 <- coef_test(lm_fit, vcov = "CR0", cluster = group, test = "Satterthwaite") 18 | VCR0_f <- sum(nj^2 * (y_bar - mean(Y))^2) / sum(nj)^2 19 | df0_f <- (N^2 - sum(nj^2))^2 / (N^2 * sum(nj^2) - 2 * N * sum(nj^3) + sum(nj^2)^2) 20 | 21 | expect_equal(as.numeric(CR0$SE), sqrt(VCR0_f)) 22 | expect_equal(CR0$df, df0_f) 23 | }) 24 | 25 | test_that("CR1 and df agree with formulas", { 26 | CR1 <- coef_test(lm_fit, vcov = "CR1", cluster = group, test = "Satterthwaite") 27 | VCR1_f <- (m / (m - 1)) * sum(nj^2 * (y_bar - mean(Y))^2) / sum(nj)^2 28 | df1_f <- (N^2 - sum(nj^2))^2 / (N^2 * sum(nj^2) - 2 * N * sum(nj^3) + sum(nj^2)^2) 29 | 30 | expect_equal(as.numeric(CR1$SE), sqrt(VCR1_f)) 31 | expect_equal(CR1$df, df1_f) 32 | }) 33 | 34 | test_that("CR2 and df agree with formulas", { 35 | CR2 <- coef_test(lm_fit, vcov = "CR2", cluster = group, test = "Satterthwaite") 36 | VCR2_f <- sum(nj^2 * (y_bar - mean(Y))^2 / (1 - nj / N)) / sum(nj)^2 37 | df2_f <- N^2 / (N^2 * sum(nj^2 / (N - nj)^2) - 2 * N * sum(nj^3 / (N - nj)^2) + sum(nj^2 / (N - nj))^2) 38 | 39 | expect_equal(as.numeric(CR2$SE), sqrt(VCR2_f)) 40 | expect_equal(CR2$df, df2_f) 41 | }) 42 | 43 | test_that("CR3 agrees with formula", { 44 | CR3 <- coef_test(lm_fit, vcov = "CR3", cluster = group, test = "Satterthwaite") 45 | VCR3_f <- sum(nj^2 * (y_bar - mean(Y))^2 / (1 - nj / N)^2) / sum(nj)^2 46 | # df2_f <- N^2 / (N^2 * sum(nj^2 / (N - nj)^2) - 2 * N * sum(nj^3 / (N - nj)^2) + sum(nj^2 / (N - nj))^2) 47 | 48 | expect_equal(as.numeric(CR3$SE), sqrt(VCR3_f)) 49 | # expect_equal(CR2$df, df2_f) 50 | }) 51 | 52 | test_that("CR4 and df agree with formulas", { 53 | CR4 <- coef_test(lm_fit, vcov = "CR4", cluster = group, test = "Satterthwaite") 54 | VCR4_f <- sum(nj^2 * (y_bar - mean(Y))^2 / (1 - nj / N)) / sum(nj)^2 55 | df4_f <- N^2 / (N^2 * sum(nj^2 / (N - nj)^2) - 2 * N * sum(nj^3 / (N - nj)^2) + sum(nj^2 / (N - nj))^2) 56 | 57 | expect_equal(as.numeric(CR4$SE), sqrt(VCR4_f)) 58 | expect_equal(CR4$df, df4_f) 59 | }) 60 | -------------------------------------------------------------------------------- /tests/testthat/test_lm_robust.R: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jepusto/clubSandwich/7cc5060dcc9b96f5cf6280f0007347e85ff1fc39/tests/testthat/test_lm_robust.R -------------------------------------------------------------------------------- /tests/testthat/test_lme_MVML.R: -------------------------------------------------------------------------------- 1 | context("multi-variate multi-level lme objects") 2 | set.seed(20190513) 3 | 4 | skip_on_cran() 5 | 6 | dat <- read.table(file="https://raw.githubusercontent.com/wviechtb/multivariate_multilevel_models/master/data.dat", header=TRUE, sep="\t") 7 | dat$pa <- rowMeans(dat[, grepl("pa", names(dat))]) 8 | dat$na <- rowMeans(dat[, grepl("na", names(dat))]) 9 | 10 | # keep only variables that are needed 11 | dat <- dat[, c("id", "sex", "beep", "pa", "na")] 12 | 13 | # keep only the first 10 IDs 14 | dat <- subset(dat, id <= 10) 15 | 16 | # change into very long format 17 | dat <- reshape(dat, direction="long", varying=c("pa","na"), v.names="y", idvar="obs", timevar="outcome") 18 | dat$obs <- NULL 19 | dat <- dat[order(dat$id, dat$beep, dat$outcome),] 20 | rownames(dat) <- 1:nrow(dat) 21 | dat$outnum <- dat$outcome 22 | dat$outcome <- factor(dat$outcome) 23 | 24 | 25 | library(nlme, quietly=TRUE, warn.conflicts=FALSE) 26 | 27 | MVML_full <- lme(y ~ outcome - 1, 28 | random = ~ outcome - 1 | id, 29 | weights = varIdent(form = ~ 1 | outcome), 30 | correlation = corSymm(form = ~ outnum | id/beep), 31 | data = dat, na.action = na.omit) 32 | 33 | MVML_diag <- lme(y ~ outcome - 1, 34 | random = ~ outcome - 1 | id, 35 | weights = varIdent(form = ~ 1 | outcome), 36 | data = dat, na.action = na.omit) 37 | 38 | gls_full <- gls(y ~ outcome - 1, 39 | weights = varIdent(form = ~ 1 | outcome), 40 | correlation = corSymm(form = ~ outnum | id/beep), 41 | data = dat, na.action = na.omit) 42 | 43 | objects <- list(MVML_full = MVML_full, MVML_diag = MVML_diag, gls = gls_full) 44 | 45 | CR2_mats <- lapply(objects, vcovCR, type = "CR2") 46 | 47 | test_that("bread works", { 48 | bread_checks <- lapply(objects, check_bread, cluster = dat$id, y = dat$y) 49 | expect_true(all(unlist(bread_checks))) 50 | 51 | obj_vcovs <- lapply(objects, vcov) 52 | obj_bread <- lapply(objects, function(obj) obj$sigma^2 * sandwich::bread(obj) / v_scale(obj)) 53 | expect_equal(obj_vcovs, obj_bread) 54 | }) 55 | 56 | 57 | test_that("vcovCR options work for CR2", { 58 | 59 | expect_identical(vcovCR(MVML_full, cluster = dat$id, type = "CR2"), CR2_mats[["MVML_full"]]) 60 | expect_equal(vcovCR(MVML_full, type = "CR2", inverse_var = TRUE), CR2_mats[["MVML_full"]]) 61 | expect_false(identical(vcovCR(MVML_full, type = "CR2", inverse_var = FALSE), CR2_mats[["MVML_full"]])) 62 | target <- targetVariance(MVML_full) 63 | expect_equal(vcovCR(MVML_full, type = "CR2", target = target, inverse_var = TRUE), CR2_mats[["MVML_full"]]) 64 | attr(CR2_mats[["MVML_full"]], "inverse_var") <- FALSE 65 | expect_equal(vcovCR(MVML_full, type = "CR2", target = target, inverse_var = FALSE), CR2_mats[["MVML_full"]]) 66 | 67 | }) 68 | 69 | 70 | test_that("CR2 is target-unbiased", { 71 | 72 | CR2_checks <- mapply(check_CR, obj = objects, vcov = CR2_mats) 73 | expect_true(all(CR2_checks)) 74 | }) 75 | 76 | 77 | CR_types <- paste0("CR",0:3) 78 | 79 | test_that("Order doesn't matter.", { 80 | 81 | check_sort_order(MVML_full, dat, seed = 20200530) 82 | check_sort_order(MVML_diag, dat, seed = 20200530) 83 | 84 | }) 85 | 86 | 87 | test_that("clubSandwich works with dropped observations", { 88 | 89 | dat_miss <- dat 90 | dat_miss$y[sample.int(nrow(dat), size = round(nrow(dat) / 10))] <- NA 91 | obj_dropped <- update(MVML_full, data = dat_miss, na.action = na.omit) 92 | obj_complete <- update(MVML_full, data = dat_miss, subset = !is.na(y)) 93 | 94 | CR_drop <- lapply(CR_types, function(x) vcovCR(obj_dropped, type = x)) 95 | CR_complete <- lapply(CR_types, function(x) vcovCR(obj_complete, type = x)) 96 | expect_identical(CR_drop, CR_complete) 97 | 98 | test_drop <- lapply(CR_drop, function(x) coef_test(obj_dropped, vcov = x, test = "All", p_values = FALSE)) 99 | test_complete <- lapply(CR_complete, function(x) coef_test(obj_complete, vcov = x, test = "All", p_values = FALSE)) 100 | expect_identical(test_drop, test_complete) 101 | }) 102 | 103 | 104 | test_that("Possible to cluster at higher level than random effects", { 105 | 106 | # create 4th level 107 | n_groups <- nlevels(factor(dat$id)) 108 | group_id <- rep(1:n_groups, each = 4)[dat$id] 109 | 110 | # cluster at level 4 111 | expect_is(vcovCR(MVML_full, type = "CR2", cluster = group_id), "vcovCR") 112 | expect_is(vcovCR(MVML_diag, type = "CR2", cluster = group_id), "vcovCR") 113 | 114 | }) 115 | -------------------------------------------------------------------------------- /tests/testthat/test_plm_overspecified_problem.R: -------------------------------------------------------------------------------- 1 | context("plm objects - balanced panel with cluster-level interactions") 2 | 3 | skip_if_not_installed("plm") 4 | library(plm, quietly=TRUE) 5 | 6 | set.seed(20200721) 7 | G <- 93 8 | N <- 4 * G 9 | Ts <- 4 10 | 11 | beta1 <- rgamma(Ts, shape = 0.3, rate = 0.1) 12 | beta2 <- rgamma(Ts, shape = 0.2, rate = 0.1) 13 | 14 | grp <- factor(rep(1:G, each = 4 * Ts)) 15 | ID <- factor(rep(1:N, each = Ts)) 16 | trt <- factor(rep(LETTERS[1:4], times = N)) 17 | X1 <- rep(rnorm(N), each = Ts) 18 | X2 <- rep(rnorm(N), each = Ts) 19 | Y <- beta1[trt] * X1 + beta2[trt] * X2 + rnorm(N)[ID] + rnorm(N * Ts, sd = 0.5) 20 | 21 | dat <- data.frame(grp, ID, trt, X1, X2, Y) 22 | dat <- pdata.frame(dat, index = c("ID","trt")) 23 | 24 | obj <- plm(Y ~ trt + trt * X1 + trt * X2, 25 | data=dat, 26 | model="within") 27 | 28 | # cluster <- dat$grp 29 | # type <- "CR2" 30 | # target <- NULL 31 | # inverse_var <- TRUE 32 | # form <- "sandwich" 33 | # ignore_FE <- FALSE 34 | # 35 | # 36 | # colnames(model_matrix.plm(obj)) 37 | # model.matrix(obj) %>% str() 38 | # model.matrix(obj, cstcovar.rm = "all") %>% str() 39 | 40 | CR_types <- paste0("CR",0:2) 41 | 42 | test_that("vcovCR works with cluster-level interactions.", { 43 | meat_list <- lapply(CR_types, function(x) vcovCR(obj = obj, cluster=dat$grp, type = x, form = "meat")) 44 | bread_dim <- dim(bread(obj)) 45 | lapply(meat_list, function(x) expect_identical(dim(x), bread_dim)) 46 | 47 | V_CR_list <- lapply(CR_types, function(x) vcovCR(obj = obj, cluster=dat$grp, type = x)) 48 | lapply(V_CR_list, expect_s3_class, class = "vcovCR") 49 | 50 | }) 51 | 52 | test_that("CR0 agrees with built-in CRVE for plm", { 53 | V_plm <- vcovHC(obj, method = "arellano", type = "HC0") 54 | V_CR0 <- vcovCR(obj, type = "CR0") 55 | expect_equal(V_plm, as.matrix(V_CR0), check.attributes = FALSE) 56 | }) 57 | -------------------------------------------------------------------------------- /tests/testthat/test_rma-ls.R: -------------------------------------------------------------------------------- 1 | context("rma.uni location-scale models") 2 | 3 | skip_if_not_installed("metadat") 4 | skip_if_not_installed("metafor", minimum_version = "3.4-0") 5 | 6 | library(metadat) 7 | suppressMessages(library(metafor, quietly=TRUE)) 8 | 9 | dat <- dat.bangertdrowns2004 10 | dat$ni100 <- dat$ni/100 11 | dat$meta[is.na(dat$meta)] <- 0 12 | res <- rma(yi, vi, mods = ~ ni100 + meta, scale = ~ ni100 + imag, data = dat) 13 | 14 | 15 | test_that("bread works", { 16 | expect_true(check_bread(res, cluster = dat$id, y = dat$yi)) 17 | vcov_mat <- bread(res) / nobs(res) 18 | attr(vcov_mat, "dimnames") <- attr(vcov(res)$beta, "dimnames") 19 | expect_equal(vcov(res)$beta, vcov_mat) 20 | }) 21 | 22 | CR_types <- paste0("CR",0:4) 23 | 24 | test_that("order doesn't matter", { 25 | 26 | skip_on_cran() 27 | 28 | check_sort_order(res, dat, cluster = "id") 29 | 30 | }) 31 | 32 | test_that("clubSandwich works with dropped covariates", { 33 | 34 | dat_miss <- dat.bangertdrowns2004 35 | expect_warning(res_drop <- rma(yi, vi, mods = ~ length + feedback + info, scale = ~ wic, data = dat)) 36 | 37 | subset_ind <- with(dat_miss, complete.cases(length, feedback, info, wic, yi, vi)) 38 | res_complete <- rma(yi, vi, mods = ~ length + feedback + info, scale = ~ wic, data = dat_miss[subset_ind,]) 39 | expect_error(vcovCR(res_complete, type = "CR0", cluster = dat_miss$id)) 40 | 41 | CR_drop <- lapply(CR_types, function(x) vcovCR(res_drop, type = x, cluster = dat_miss$id)) 42 | CR_complete <- lapply(CR_types, function(x) vcovCR(res_complete, type = x, cluster = dat_miss$id[subset_ind])) 43 | expect_equal(CR_drop, CR_complete) 44 | 45 | test_drop <- lapply(CR_types, function(x) coef_test(res_drop, vcov = x, cluster = dat_miss$id, test = "All", p_values = FALSE)) 46 | test_complete <- lapply(CR_types, function(x) coef_test(res_complete, vcov = x, cluster = dat_miss$id[subset_ind], test = "All", p_values = FALSE)) 47 | compare_ttests(test_drop, test_complete) 48 | }) 49 | 50 | test_that("clubSandwich works with missing variances", { 51 | 52 | dat_miss <- dat 53 | dat_miss$vi[sample.int(nrow(dat_miss), size = round(nrow(dat_miss) / 10))] <- NA 54 | expect_warning(res_drop <- rma(yi, vi, mods = ~ ni100 + meta, scale = ~ ni100 + imag, data = dat_miss)) 55 | 56 | 57 | subset_ind <- with(dat_miss, !is.na(vi)) 58 | res_complete <- rma(yi, vi, mods = ~ ni100 + meta, scale = ~ ni100 + imag, data = dat_miss, subset = !is.na(vi)) 59 | 60 | expect_error(vcovCR(res_complete, type = "CR0", cluster = dat_miss$id)) 61 | 62 | CR_drop <- lapply(CR_types, function(x) vcovCR(res_drop, type = x, cluster = dat_miss$id)) 63 | CR_complete <- lapply(CR_types, function(x) vcovCR(res_complete, type = x, cluster = dat_miss$id[subset_ind])) 64 | expect_equal(CR_drop, CR_complete) 65 | 66 | }) 67 | 68 | 69 | test_that("vcovCR options work for CR2", { 70 | RE_var <- res$tau2 + dat$vi 71 | CR2_iv <- vcovCR(res, type = "CR2", cluster = dat$id) 72 | expect_equal(vcovCR(res, type = "CR2", cluster = dat$id, inverse_var = TRUE), CR2_iv) 73 | 74 | CR2_not <- vcovCR(res, type = "CR2", cluster = dat$id, inverse_var = FALSE) 75 | attr(CR2_iv, "inverse_var") <- FALSE 76 | attr(CR2_iv, "target") <- attr(CR2_not, "target") 77 | expect_equal(CR2_not, CR2_iv) 78 | expect_equal(vcovCR(res, type = "CR2", cluster = dat$id, target = RE_var), CR2_not) 79 | expect_equal(vcovCR(res, type = "CR2", cluster = dat$id, target = RE_var, inverse_var = FALSE), CR2_not) 80 | expect_false(identical(vcovCR(res, type = "CR2", cluster = dat$id, target = dat$vi), CR2_not)) 81 | }) 82 | -------------------------------------------------------------------------------- /vignettes/bibliography.bib: -------------------------------------------------------------------------------- 1 | @article{Angrist2009effects, 2 | author = {Angrist, Joshua and Lavy, Victor}, 3 | title = {The effects of high stakes high school achievement awards: Evidence from a randomized trial}, 4 | journal = {American Economic Review}, 5 | volume = {99}, 6 | number = {4}, 7 | year = {2009}, 8 | pages = {1384--1414}, 9 | doi = {10.1257/aer.99.4.1384}, 10 | url = {https://www.aeaweb.org/articles?id=10.1257/aer.99.4.1384} 11 | } 12 | 13 | @article{tipton2015small, 14 | title = {Small-sample adjustments for tests of moderators and model fit using robust variance estimation in meta-regression}, 15 | volume = {40}, 16 | url = {http://journals.sagepub.com/doi/10.3102/1076998615606099}, 17 | doi = {10.3102/1076998615606099}, 18 | number = {6}, 19 | journal = {Journal of Educational and Behavioral Statistics}, 20 | author = {Tipton, Elizabeth and Pustejovsky, James E.}, 21 | year = {2015}, 22 | pages = {604--634}, 23 | } 24 | 25 | 26 | @article{pustejovsky2018small, 27 | title = {Small-{Sample} {Methods} for {Cluster}-{Robust} {Variance} {Estimation} and {Hypothesis} {Testing} in {Fixed} {Effects} {Models}}, 28 | volume = {36}, 29 | url = {https://www.tandfonline.com/doi/full/10.1080/07350015.2016.1247004}, 30 | doi = {10.1080/07350015.2016.1247004}, 31 | number = {4}, 32 | journal = {Journal of Business \& Economic Statistics}, 33 | author = {Pustejovsky, James E. and Tipton, Elizabeth}, 34 | year = {2018}, 35 | pages = {672--683}, 36 | } 37 | --------------------------------------------------------------------------------