Nothing
## ---------------------------------------------------------
## Edge case and boundary condition tests
## ---------------------------------------------------------
test_that("fect handles single treated unit", {
skip_on_cran()
set.seed(7001)
N <- 20
TT <- 15
T0 <- 10
Ntr <- 1 # only one treated unit
tau <- 3.0
alpha_i <- rnorm(N, 0, 1)
xi_t <- rnorm(TT, 0, 0.5)
Y_vec <- numeric(N * TT)
D_vec <- integer(N * TT)
id_vec <- integer(N * TT)
time_vec <- integer(N * TT)
idx <- 1
for (i in 1:N) {
for (t in 1:TT) {
treated <- (i <= Ntr) && (t > T0)
D_vec[idx] <- as.integer(treated)
eps <- rnorm(1, 0, 0.5)
Y_vec[idx] <- alpha_i[i] + xi_t[t] + tau * D_vec[idx] + eps
id_vec[idx] <- i
time_vec[idx] <- t
idx <- idx + 1
}
}
simdf <- data.frame(
id = id_vec,
time = time_vec,
Y = Y_vec,
D = D_vec
)
## Should not error with a single treated unit
out <- suppressWarnings(fect::fect(
Y ~ D,
data = simdf,
index = c("id", "time"),
method = "fe",
force = "two-way",
se = FALSE,
parallel = FALSE
))
expect_true(is.numeric(out$att.avg))
expect_true(!is.na(out$att.avg))
expect_true(is.matrix(out$eff))
})
test_that("fect handles missing data (scattered NAs in Y)", {
skip_on_cran()
set.seed(7002)
N <- 25
TT <- 15
T0 <- 10
Ntr <- 8
tau <- 2.0
alpha_i <- rnorm(N, 0, 1)
xi_t <- rnorm(TT, 0, 0.5)
Y_vec <- numeric(N * TT)
D_vec <- integer(N * TT)
id_vec <- integer(N * TT)
time_vec <- integer(N * TT)
idx <- 1
for (i in 1:N) {
for (t in 1:TT) {
treated <- (i <= Ntr) && (t > T0)
D_vec[idx] <- as.integer(treated)
eps <- rnorm(1, 0, 1)
Y_vec[idx] <- alpha_i[i] + xi_t[t] + tau * D_vec[idx] + eps
id_vec[idx] <- i
time_vec[idx] <- t
idx <- idx + 1
}
}
## Introduce ~5% missing values in Y (but NOT in treated post-period)
miss_candidates <- which(D_vec == 0)
n_miss <- min(floor(0.05 * length(Y_vec)), length(miss_candidates))
miss_idx <- sample(miss_candidates, n_miss)
Y_vec[miss_idx] <- NA
simdf <- data.frame(
id = id_vec,
time = time_vec,
Y = Y_vec,
D = D_vec
)
## Should handle missing data without error
out <- suppressWarnings(fect::fect(
Y ~ D,
data = simdf,
index = c("id", "time"),
method = "fe",
force = "two-way",
se = FALSE,
parallel = FALSE,
na.rm = TRUE
))
expect_true(is.numeric(out$att.avg))
expect_true(!is.na(out$att.avg))
## ATT should still be roughly correct
expect_lt(abs(out$att.avg - tau), 1.5,
label = paste0("Missing data FE: att.avg = ",
round(out$att.avg, 4), ", tau = ", tau))
})
test_that("fect output structure is complete (FE)", {
skip_on_cran()
set.seed(7003)
N <- 20
TT <- 10
T0 <- 6
Ntr <- 8
Y_vec <- numeric(N * TT)
D_vec <- integer(N * TT)
id_vec <- integer(N * TT)
time_vec <- integer(N * TT)
idx <- 1
for (i in 1:N) {
for (t in 1:TT) {
treated <- (i <= Ntr) && (t > T0)
D_vec[idx] <- as.integer(treated)
Y_vec[idx] <- rnorm(1) + 2.0 * D_vec[idx]
id_vec[idx] <- i
time_vec[idx] <- t
idx <- idx + 1
}
}
simdf <- data.frame(
id = id_vec,
time = time_vec,
Y = Y_vec,
D = D_vec
)
out <- suppressWarnings(fect::fect(
Y ~ D,
data = simdf,
index = c("id", "time"),
method = "fe",
force = "two-way",
se = FALSE,
parallel = FALSE
))
## Check required output slots exist
expect_true(!is.null(out$att.avg))
expect_true(!is.null(out$att.avg.unit))
expect_true(!is.null(out$eff))
expect_true(!is.null(out$Y.ct))
expect_true(!is.null(out$time))
expect_true(!is.null(out$att))
expect_true(!is.null(out$count))
expect_true(!is.null(out$sigma2))
})
test_that("fect with many treated units still works", {
skip_on_cran()
set.seed(7004)
N <- 25
TT <- 12
T0 <- 8
Ntr <- 20 # 80% treated
tau <- 1.5
alpha_i <- rnorm(N, 0, 0.5)
xi_t <- rnorm(TT, 0, 0.3)
Y_vec <- numeric(N * TT)
D_vec <- integer(N * TT)
id_vec <- integer(N * TT)
time_vec <- integer(N * TT)
idx <- 1
for (i in 1:N) {
for (t in 1:TT) {
treated <- (i <= Ntr) && (t > T0)
D_vec[idx] <- as.integer(treated)
eps <- rnorm(1, 0, 1)
Y_vec[idx] <- alpha_i[i] + xi_t[t] + tau * D_vec[idx] + eps
id_vec[idx] <- i
time_vec[idx] <- t
idx <- idx + 1
}
}
simdf <- data.frame(
id = id_vec,
time = time_vec,
Y = Y_vec,
D = D_vec
)
## Should work even with many treated / few control
out <- suppressWarnings(fect::fect(
Y ~ D,
data = simdf,
index = c("id", "time"),
method = "fe",
force = "two-way",
se = FALSE,
parallel = FALSE
))
expect_true(is.numeric(out$att.avg))
expect_true(!is.na(out$att.avg))
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.