Skip to content

Commit 82d149f

Browse files
committed
Allow constant variance
1 parent 7941d3f commit 82d149f

2 files changed

Lines changed: 23 additions & 15 deletions

File tree

R/formula.R

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ parse_hetero_formula <- function(formula) {
1212
f_char <- Reduce(paste, deparse(formula))
1313

1414

15-
# Check for | separator
16-
15+
# Check for | separator - if missing, default to intercept-only variance
1716
if (!grepl("\\|", f_char)) {
18-
stop("Formula must contain '|' separating mean and variance equations.\n",
19-
" Usage: y ~ x1 + x2 | z1 + z2", call. = FALSE)
20-
}
17+
# No variance equation specified - use intercept-only (homoscedastic)
18+
mean_part <- f_char
19+
var_part <- "1"
20+
} else {
21+
# Split: everything before | is mean equation, after is variance equation
22+
parts <- strsplit(f_char, "\\|")[[1]]
23+
if (length(parts) != 2) {
24+
stop("Formula must have exactly one '|' separator.", call. = FALSE)
25+
}
2126

22-
# Split: everything before | is mean equation, after is variance equation
23-
parts <- strsplit(f_char, "\\|")[[1]]
24-
if (length(parts) != 2) {
25-
stop("Formula must have exactly one '|' separator.", call. = FALSE)
27+
mean_part <- trimws(parts[1]) # "y ~ x1 + x2"
28+
var_part <- trimws(parts[2]) # "z1 + z2"
2629
}
2730

28-
mean_part <- trimws(parts[1]) # "y ~ x1 + x2"
29-
var_part <- trimws(parts[2]) # "z1 + z2"
30-
3131
# Parse mean equation (standard formula)
3232
mean_formula <- as.formula(mean_part)
3333
lhs <- all.vars(mean_formula[[2]]) # Response variable

R/methods.R

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,17 @@ summary.hetero_fit <- function(object, ...) {
109109
}
110110

111111
# Heteroscedasticity assessment: SD of Pearson residuals by quantile of fitted variance
112-
var_quantiles <- cut(pred$sigma, breaks = quantile(pred$sigma, probs = c(0, 0.25, 0.5, 0.75, 1)),
113-
include.lowest = TRUE, labels = c("Q1", "Q2", "Q3", "Q4"))
114-
resid_sd_by_var <- tapply(pearson_resid, var_quantiles, sd)
112+
# Handle constant sigma case (homoscedastic model with intercept-only variance)
113+
sigma_range <- diff(range(pred$sigma))
114+
if (sigma_range < .Machine$double.eps * 100) {
115+
# Constant sigma - no heteroscedasticity to assess
116+
resid_sd_by_var <- c(Q1 = sd(pearson_resid))
117+
names(resid_sd_by_var) <- "All (constant variance)"
118+
} else {
119+
var_quantiles <- cut(pred$sigma, breaks = quantile(pred$sigma, probs = c(0, 0.25, 0.5, 0.75, 1)),
120+
include.lowest = TRUE, labels = c("Q1", "Q2", "Q3", "Q4"))
121+
resid_sd_by_var <- tapply(pearson_resid, var_quantiles, sd)
122+
}
115123

116124
# Build summary object
117125
result <- list(

0 commit comments

Comments
 (0)