### Install bacondecomp Source: https://github.com/evanjflack/bacondecomp/blob/master/README.md Installation instructions for the package from CRAN or GitHub. ```R install.packages("bacondecomp") ``` ```R library(devtools) install_github("evanjflack/bacondecomp") ``` -------------------------------- ### Install bacondecomp Development Version from GitHub Source: https://context7.com/evanjflack/bacondecomp/llms.txt Install the latest development version of the bacondecomp package directly from GitHub using the devtools package. This is useful for accessing the newest features or bug fixes. ```r library(devtools) install_github("evanjflack/bacondecomp") ``` -------------------------------- ### Install bacondecomp from CRAN Source: https://context7.com/evanjflack/bacondecomp/llms.txt Use this command to install the stable version of the bacondecomp package from the Comprehensive R Archive Network (CRAN). ```r install.packages("bacondecomp") ``` -------------------------------- ### Perform Controlled Goodman-Bacon Decomposition Source: https://context7.com/evanjflack/bacondecomp/llms.txt This example shows how to perform a Goodman-Bacon decomposition that includes time-varying covariates. The `bacon()` function returns a list containing the within-group coefficient, its weight, and the between-group 2x2 estimates. This allows for a more nuanced analysis by accounting for additional sources of variation. ```r library(bacondecomp) # Decomposition with time-varying controls # Including log population and log income as controls ret_bacon <- bacon( formula = l_homicide ~ post + l_pop + l_income, data = bacondecomp::castle, id_var = "state", time_var = "year" ) # Access components of the controlled decomposition beta_hat_w <- ret_bacon$beta_hat_w # Within timing group coefficient Omega <- ret_bacon$Omega # Weight on within-group estimate two_by_twos <- ret_bacon$two_by_twos # Between-group 2x2 estimates print(paste("Within timing group estimate (beta_hat_w):", round(beta_hat_w, 4))) print(paste("Within group weight (Omega):", round(Omega, 4))) # Calculate weighted sum using the formula: # beta_hat = Omega * beta_hat_w + (1 - Omega) * sum(s_kl * beta_hat_d_bkl) beta_hat_b <- weighted.mean(two_by_twos$estimate, two_by_twos$weight) bacon_coef_cont <- Omega * beta_hat_w + (1 - Omega) * beta_hat_b print(paste("Weighted sum of decomposition =", round(bacon_coef_cont, 4))) # Verify with two-way FE including controls two_way_fe_cont <- lm(l_homicide ~ post + l_pop + l_income + factor(state) + factor(year), data = bacondecomp::castle) print(paste("Two-way FE estimate =", round(two_way_fe_cont$coefficients["post"], 4))) ``` -------------------------------- ### Summarize Bacon Decomposition Results Source: https://context7.com/evanjflack/bacondecomp/llms.txt Aggregates 2x2 decomposition results by comparison type to show total weight and average estimate. Use `return_df = TRUE` to get results as a data frame for further analysis. ```r library(bacondecomp) # Perform decomposition df_bacon <- bacon( formula = l_homicide ~ post, data = bacondecomp::castle, id_var = "state", time_var = "year", quietly = TRUE ) # Get summary by comparison type bacon_summary(df_bacon) #> type weight avg_est #> 1 Earlier vs Later Treated 0.05041 -0.00143 #> 2 Later vs Earlier Treated 0.05041 0.11706 #> 3 Treated vs Untreated 0.89918 0.07965 # Return as data frame for further analysis summary_df <- bacon_summary(df_bacon, return_df = TRUE) # Identify problematic comparisons # "Later vs Earlier Treated" can be biased if treatment effects vary over time print(paste("Weight on potentially biased comparisons:", round(summary_df[summary_df$type == "Later vs Earlier Treated", "weight"], 4))) ``` -------------------------------- ### bacon_summary() Source: https://context7.com/evanjflack/bacondecomp/llms.txt Aggregates 2x2 decomposition results by comparison type to calculate total weights and weighted average estimates. ```APIDOC ## bacon_summary(df_bacon, return_df = FALSE) ### Description Aggregates the 2x2 decomposition results by comparison type, providing the total weight and weighted average estimate for each category. ### Parameters #### Request Body - **df_bacon** (object) - Required - The output object from the bacon() function. - **return_df** (boolean) - Optional - If TRUE, returns the summary as a data frame instead of printing to console. ### Response #### Success Response (200) - **type** (string) - The comparison category (e.g., Earlier vs Later Treated). - **weight** (numeric) - The total weight assigned to this comparison type. - **avg_est** (numeric) - The weighted average estimate for this comparison type. ``` -------------------------------- ### Plot 2x2 Estimates and Weights Source: https://github.com/evanjflack/bacondecomp/blob/master/index.ipynb Visualize the decomposition by plotting each 2x2 estimate against its corresponding weight. This helps identify which specific comparisons drive the overall fixed effects estimate. ```R ggplot(df_bacon) + aes(x = weight, y = estimate, shape = factor(type)) + labs(x = "Weight", y = "Estimate", shape = "Type") + geom_point() ``` -------------------------------- ### Perform Basic Goodman-Bacon Decomposition Source: https://context7.com/evanjflack/bacondecomp/llms.txt This snippet demonstrates how to perform a basic Goodman-Bacon decomposition using the `bacon()` function. It estimates the effect of 'post' on 'l_homicide' using the 'castle' dataset, identifying units by 'state' and time by 'year'. The output shows 2x2 estimates and their weights. ```r library(bacondecomp) # Basic decomposition without controls (Castle Doctrine data) # Estimate effect of castle doctrine laws on homicide rates df_bacon <- bacon( formula = l_homicide ~ post, data = bacondecomp::castle, id_var = "state", time_var = "year", quietly = FALSE ) # View the 2x2 estimates and weights head(df_bacon) ``` ```r # Verify decomposition equals TWFE estimate coef_bacon <- sum(df_bacon$estimate * df_bacon$weight) print(paste("Weighted sum of decomposition =", round(coef_bacon, 4))) # Compare with standard two-way fixed effects fit_tw <- fixest::feols(l_homicide ~ post | state + year, data = bacondecomp::castle) print(paste("Two-way FE estimate =", round(fit_tw$coefficients[1], 4))) ``` -------------------------------- ### Built-in Datasets Source: https://context7.com/evanjflack/bacondecomp/llms.txt Access to panel datasets provided by the package for replication and analysis. ```APIDOC ## Built-in Datasets ### Description The package includes several datasets used in seminal difference-in-differences research. ### Available Datasets - **castle** (data.frame) - State-year panel data from Cheng and Hoekstra (2013) on castle doctrine laws. - **math_reform** (data.frame) - Aggregated state-cohort data from Goodman (2019) on education reform. - **divorce** (data.frame) - State-year panel data from Stevenson and Wolfers (2006) on unilateral divorce laws. ### Usage Example ```r data(castle) head(castle) ``` ``` -------------------------------- ### Visualize Decomposition Results Source: https://github.com/evanjflack/bacondecomp/blob/master/README.md Create a scatter plot of weights versus estimates using ggplot2. ```R library(ggplot2) ggplot(df_bacon) + aes(x = weight, y = estimate, shape = factor(type)) + geom_point() + geom_hline(yintercept = 0) + theme_minimal() + labs(x = "Weight", y = "Estimate", shape = "Type") ``` -------------------------------- ### Load and Inspect Castle Doctrine Data Source: https://context7.com/evanjflack/bacondecomp/llms.txt Loads the 'castle' dataset, which contains state-year panel data on the effect of 'castle doctrine' laws on homicide rates. Displays the first few rows with relevant columns. ```r library(bacondecomp) # Load castle doctrine data data(castle) head(castle[, c("state", "year", "l_homicide", "post", "l_pop", "l_income")]) #> state year l_homicide post l_pop l_income #> 1 AK 2000 2.227751 0 13.47196 10.44691 #> 2 AK 2001 1.945910 0 13.47946 10.47745 #> 3 AK 2002 2.063070 0 13.48688 10.44863 #> 4 AK 2003 2.010792 0 13.49246 10.47087 #> 5 AK 2004 1.791759 0 13.49907 10.51173 #> 6 AK 2005 1.609438 0 13.50535 10.56039 # Basic analysis df_bacon <- bacon(l_homicide ~ post, data = castle, id_var = "state", time_var = "year") ``` -------------------------------- ### Load and Analyze Math Reform Data Source: https://context7.com/evanjflack/bacondecomp/llms.txt Loads the 'math_reform' dataset, which contains aggregated state-cohort data on the effect of compulsory high school math coursework on future earnings. Performs a bacon decomposition and displays a summary. ```r library(bacondecomp) # Load math reform data data(math_reform) head(math_reform) #> state class reform_math reformyr_math incearn_ln #> 1 AK 1973 0 NA 10.19299 #> 2 AK 1974 0 NA 10.19891 #> 3 AK 1975 0 NA 10.18728 # Decomposition for education reform effect df_bacon <- bacon( formula = incearn_ln ~ reform_math, data = math_reform, id_var = "state", time_var = "class" ) # View summary bacon_summary(df_bacon) #> type weight avg_est #> 1 Earlier vs Later Treated 0.06353 0.02868 #> 2 Later vs Earlier Treated 0.05265 0.03375 #> 3 Treated vs Untreated 0.88382 -0.00129 ``` -------------------------------- ### Load Divorce Law Data Source: https://context7.com/evanjflack/bacondecomp/llms.txt Loads the 'divorce' dataset, which contains state-year panel data examining the effect of unilateral divorce laws. The structure of the data is then displayed. ```r library(bacondecomp) # Load divorce data data(divorce) str(divorce) ``` -------------------------------- ### Visualize Bacon Decomposition Estimates vs Weights Source: https://context7.com/evanjflack/bacondecomp/llms.txt Plots 2x2 decomposition estimates against their weights, colored by comparison type. This helps identify which comparisons drive the overall TWFE estimate and detect concerning patterns. Use `ret_bacon$two_by_twos` for controlled decomposition plots. ```r library(bacondecomp) library(ggplot2) # Perform decomposition df_bacon <- bacon( formula = l_homicide ~ post, data = bacondecomp::castle, id_var = "state", time_var = "year" ) # Plot estimates vs weights by type ggplot(df_bacon) + aes(x = weight, y = estimate, shape = factor(type), color = factor(type)) + geom_point(size = 3) + geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") + theme_minimal() + labs( x = "Weight", y = "Estimate", shape = "Comparison Type", color = "Comparison Type", title = "Goodman-Bacon Decomposition", subtitle = "Castle Doctrine Effect on Homicide Rates" ) + theme(legend.position = "bottom") # For controlled decomposition ret_bacon <- bacon( formula = l_homicide ~ post + l_pop + l_income, data = bacondecomp::castle, id_var = "state", time_var = "year" ) ggplot(ret_bacon$two_by_twos) + aes(x = weight, y = estimate, shape = factor(type)) + geom_point(size = 3) + geom_hline(yintercept = 0, linetype = "dashed") + theme_minimal() + labs(x = "Weight", y = "Estimate", shape = "Type") ``` -------------------------------- ### Calculate Two-Way Fixed Effects Estimate Source: https://github.com/evanjflack/bacondecomp/blob/master/index.ipynb Fit a standard two-way fixed effects model using `lm` to obtain the overall estimate. This estimate should be equal to the weighted average of the 2x2 decompositions. ```R fit_tw <- lm(l_homicide ~ post + factor(state) + factor(year), data = bacon::castle) print(paste("Two-way FE estimate =", fit_tw$coefficients[2])) ``` -------------------------------- ### Identify Estimate with Top Weight Source: https://github.com/evanjflack/bacondecomp/blob/master/index.ipynb Extract and print the specific 2x2 estimate that has the largest weight in the decomposition. This can highlight the most influential comparison in the analysis. ```R top_weight <- df_bacon[order(-df_bacon$weight), ][1, ] print(top_weight) ``` -------------------------------- ### Decompose Two-Way Fixed Effects Source: https://github.com/evanjflack/bacondecomp/blob/master/README.md Calculate 2x2 differences-in-differences estimates and generate a summary of the decomposition. ```R library(bacondecomp) #> Loading required package: fixest #> fixest 0.9.0, BREAKING changes! (Permanently remove this message with fixest_startup_msg(FALSE).) #> - In i(): #> + the first two arguments have been swapped! Now it's i(factor_var, continuous_var) for interactions. #> + argument 'drop' has been removed (put everything in 'ref' now). #> - In feglm(): #> + the default family becomes 'gaussian' to be in line with glm(). Hence, for Poisson estimations, please use fepois() instead. df_bacon <- bacon(incearn_ln ~ reform_math, data = bacondecomp::math_reform, id_var = "state", time_var = "class") # All 2x2 Comparisons head(df_bacon) #> treated untreated estimate weight type #> 2 1987 1985 0.04575585 0.031655309 Later vs Earlier Treated #> 4 1986 1985 0.11390411 0.001978457 Later vs Earlier Treated #> 5 1984 1985 0.12012908 0.001978457 Earlier vs Later Treated #> 6 1985 1987 0.01021379 0.039569136 Earlier vs Later Treated #> 9 1986 1987 -0.09374495 0.005440756 Earlier vs Later Treated #> 10 1984 1987 0.09784857 0.013354583 Earlier vs Later Treated # Summary of Early vs. Later, Later vs. Earlier, and Treated vs. Untreated bacon_summary(df_bacon) #> type weight avg_est #> 1 Earlier vs Later Treated 0.06353 0.02868 #> 2 Later vs Earlier Treated 0.05265 0.03375 #> 3 Treated vs Untreated 0.88382 -0.00129 ``` -------------------------------- ### Decompose Two-Way Fixed Effects Model with bacon Source: https://github.com/evanjflack/bacondecomp/blob/master/index.ipynb Use the `bacon` function to decompose a two-way fixed effects model. Specify the outcome and treatment variables, the data, and the id and time variables. This function calculates all 2x2 estimates and their weights. ```R library(bacon) library(ggplot2) df_bacon <- bacon(l_homicide ~ post, data = bacon::castle, id_var = "state", time_var = "year") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.