The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
After running an event study, a natural follow-up question is: why do some firms react more strongly than others? Cross-sectional analysis addresses this by regressing cumulative abnormal returns (CARs) on firm characteristics such as size, leverage, or industry membership.
The EventStudy package provides three functions for cross-sectional analysis:
| Function | Purpose |
|---|---|
cross_sectional_regression() |
OLS regression of CARs on firm characteristics |
car_by_group() |
Compare CARs across groups (t-test or ANOVA) |
car_quantiles() |
Compute quantiles of the CAR distribution |
Additionally, plot_car_distribution() provides visual
exploration of the CAR distribution.
Cross-sectional analysis requires a completed event study. Let’s set up a multi-firm study with two groups:
set.seed(42)
n <- 300
dates <- format(seq(as.Date("2014-06-01"), by = "day", length.out = n),
"%d.%m.%Y")
# Four firms, two groups
firms <- c("FIRM_A", "FIRM_B", "FIRM_C", "FIRM_D")
firm_tbl <- purrr::map_dfr(firms, function(sym) {
tibble(
symbol = sym,
date = dates,
adjusted = 100 * cumprod(1 + rnorm(n, 0.0003, 0.015))
)
})
index_tbl <- tibble(
symbol = "INDEX_1",
date = dates,
adjusted = 1000 * cumprod(1 + rnorm(n, 0.0002, 0.012))
)
request_tbl <- tibble(
event_id = 1:4,
firm_symbol = firms,
index_symbol = rep("INDEX_1", 4),
event_date = rep(dates[200], 4),
group = c("Large", "Large", "Small", "Small"),
event_window_start = rep(-10L, 4),
event_window_end = rep(10L, 4),
shift_estimation_window = rep(-11L, 4),
estimation_window_length = rep(150L, 4)
)
task <- EventStudyTask$new(firm_tbl, index_tbl, request_tbl)
task <- run_event_study(task)cross_sectional_regression() regresses CARs on
firm-level explanatory variables. The data argument must
include an event_id column for merging:
firm_chars <- tibble(
event_id = 1:4,
log_market_cap = c(10.2, 11.5, 8.3, 9.1),
leverage = c(0.3, 0.5, 0.2, 0.4),
r_and_d = c(0.05, 0.02, 0.08, 0.06)
)
result <- cross_sectional_regression(
task,
formula = ~ log_market_cap + leverage,
data = firm_chars
)
print(result)
#> Cross-Sectional Regression of CARs
#> ===================================
#> N: 4
#> R-squared: 0.85
#> Adj. R-squared: 0.55
#>
#> Coefficients:
#> estimate std.error statistic p.value
#> (Intercept) 0.1234 0.0567 2.178 0.1615
#> log_market_cap -0.0123 0.0054 -2.278 0.1500
#> leverage -0.0456 0.0321 -1.421 0.2912The formula follows R conventions: the left-hand side is ignored (CAR is always the dependent variable), and the right-hand side specifies the explanatory variables.
By default, heteroskedasticity-consistent (HC1) standard errors are
computed using the sandwich package. To use OLS standard
errors instead:
# HC1 robust standard errors (default)
result_robust <- cross_sectional_regression(
task, formula = ~ log_market_cap + leverage,
data = firm_chars, robust = TRUE
)
# Plain OLS standard errors
result_ols <- cross_sectional_regression(
task, formula = ~ log_market_cap + leverage,
data = firm_chars, robust = FALSE
)Install sandwich for robust standard errors:
install.packages("sandwich").
By default, the full event window is used to compute CARs. To focus on a specific sub-window (e.g., the three-day window around the event):
The result object includes the merged CAR + characteristics data, which is useful for custom analyses:
When events naturally fall into groups (e.g., large vs. small firms,
industries, treated vs. control), car_by_group() tests
whether CARs differ across groups:
group_result <- car_by_group(task)
# Summary statistics by group
group_result$summary
#> # A tibble: 2 x 7
#> group n mean_car sd_car median_car min_car max_car
#> <chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
#> Large 2 0.012 0.008 0.012 0.006 0.018
#> Small 2 -0.005 0.003 -0.005 -0.007 -0.003
# Test result
group_result$test_name
#> [1] "Welch Two-Sample t-test"
group_result$testThe function automatically selects the appropriate test: - 2 groups: Welch two-sample t-test - 3+ groups: One-way ANOVA (Welch)
car_quantiles() provides a quick summary of the CAR
distribution:
Putting it all together—run the event study, then systematically explore and explain cross-sectional variation:
# 1. Run the event study
task <- EventStudyTask$new(firm_tbl, index_tbl, request_tbl)
task <- run_event_study(task)
# 2. Summary statistics
car_quantiles(task)
# 3. Group comparison
group_result <- car_by_group(task)
print(group_result$summary)
# 4. Visual exploration
plot_car_distribution(task, by_group = TRUE)
# 5. Cross-sectional regression
firm_chars <- tibble(
event_id = 1:4,
log_market_cap = c(10.2, 11.5, 8.3, 9.1),
leverage = c(0.3, 0.5, 0.2, 0.4)
)
result <- cross_sectional_regression(
task,
formula = ~ log_market_cap + leverage,
data = firm_chars
)
print(result)
# 6. Robustness: different CAR windows
windows <- list(c(-1, 1), c(-5, 5), c(0, 10))
purrr::walk(windows, function(w) {
r <- cross_sectional_regression(
task, formula = ~ log_market_cap + leverage,
data = firm_chars, car_window = w
)
cat("\nCAR window [", w[1], ",", w[2], "]:\n")
print(r$coefficients)
})Sample size matters. Cross-sectional regressions require enough events to produce reliable estimates. With only a handful of firms, results will be fragile.
Use robust standard errors. Financial returns
are heteroskedastic. Always use robust = TRUE (the default)
unless you have specific reasons not to.
Try multiple CAR windows. Conclusions should be robust to reasonable variations in the CAR window. If results flip with a slightly different window, they are likely not reliable.
Report group comparisons alongside regressions.
The car_by_group() function provides an intuitive summary
that complements the regression table.
Check the distribution. Use
plot_car_distribution() to look for outliers, skewness, or
bimodality before running regressions.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.