Skip to content

Commit 61c29af

Browse files
committed
some minor improvements
1 parent c4bb7b8 commit 61c29af

9 files changed

Lines changed: 137 additions & 55 deletions

File tree

DESCRIPTION

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,14 @@ Type: Package
33
Title: Tools for Studying Revision Properties in Real-Time Time Series Vintages
44
Version: 0.1.0.9000
55
Authors@R: c(
6-
person("Marc", "Burri", ,"marc.burri91@gmail.com", role = c("aut", "cre", "cph"),
6+
person(given = "Marc", family = "Burri", email = "marc.burri91@gmail.com", role = c("aut", "cre", "cph"),
77
comment = c(ORCID = "0000-0001-8974-9090")),
88
person(given = "Philipp", family = "Wegmueller",
99
email = "philipp.wemueller@seco.admin.ch", role = c("aut", "cph"))
1010
)
1111
Description: Provides tools to analyze revision properties in real-time time series data.
12-
Maintainers: c(
13-
person("Marc", "Burri", ,"marc.burri91@gmail.com",
14-
comment = c(ORCID = "0000-0001-8974-9090")),
15-
person(given = "Philipp", family = "Wegmueller",
16-
email = "philipp.wemueller@seco.admin.ch")
17-
)
12+
Author: Marc Burri [aut, cre, cph] (ORCID: <https://orcid.org/0000-0001-8974-9090>), Philipp Wegmueller [aut, cph]
13+
Maintainer: Marc Burri <marc.burri91@gmail.com>
1814
License: MIT + file LICENSE
1915
Encoding: UTF-8
2016
LazyData: true

R/jvn.R

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#' vintage estimate for the same time period. Rows are time periods.
88
#' @param e An integer indicating the number of data vintages to include in the
99
#' model. Must be greater than 0.
10-
#' @param ar_order Integer specifying AR order for true values (default = 2).
10+
#' @param ar_order Integer specifying AR order for true values (default = 1).
1111
#' @param h Integer specifying the forecast horizon (default = 0).
1212
#' @param include_news Logical, whether to include news component in
1313
#' measurement error (default = TRUE).
@@ -28,7 +28,7 @@
2828
#' - startvals: Named vector of starting values (optional)
2929
#' - transform_se: T/F whether standard errors should be constrained to be
3030
#' positive in optimization.
31-
#' . - method: String specifying optimization method (default = "L-BFGS-B").
31+
#' - method: String specifying optimization method (default = "L-BFGS-B").
3232
#' - se_method: Method for standard error calculation (default = "hessian")
3333
#' - n_starts: Number of random starting points for multi-start optimization
3434
#'
@@ -153,10 +153,10 @@ jvn_nowcast <- function(
153153
if (
154154
length(setdiff(names(solver_options), names(default_solver_options))) > 0
155155
) {
156-
rlang::abort(
156+
rlang::abort(paste0(
157157
"Invalid solver options provided. Valid options are: ",
158158
paste(names(default_solver_options), collapse = ", ")
159-
)
159+
))
160160
}
161161

162162
# Update default options with user-provided options

R/kk.R

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,10 @@ kk_nowcast <- function(
146146
if (
147147
length(setdiff(names(solver_options), names(default_solver_options))) > 0
148148
) {
149-
rlang::abort(
149+
rlang::abort(paste0(
150150
"Invalid solver options provided. Valid options are: ",
151151
paste(names(default_solver_options), collapse = ", ")
152-
)
152+
))
153153
}
154154

155155
# Update default options with user-provided options
@@ -1454,8 +1454,11 @@ kk_matrices <- function(e, model, params = NULL, type = "numeric") {
14541454
}
14551455

14561456
# Check params are named
1457-
if (!is.null(params) && !all(!is.na(names(params)))) {
1458-
rlang::abort("All parameters must be named!")
1457+
if (!is.null(params)) {
1458+
param_names <- names(params)
1459+
if (is.null(param_names) || anyNA(param_names) || any(param_names == "")) {
1460+
rlang::abort("All parameters must be named!")
1461+
}
14591462
}
14601463

14611464
# Check params input

R/revisions.R

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,7 +2252,7 @@ friedman_test <- function(series, frequency = 12) {
22522252
#' - Positive integer or vector (e.g., 0 for first release, 1 for second, etc.)
22532253
#' - `"first"` to extract the first release.
22542254
#' - `"latest"` to extract the most recent release.
2255-
#' Default is 1 (the first release).
2255+
#' Default is 0 (the first release).
22562256
#' @param diagonal Logical. If `TRUE`, the function only returns real
22572257
#' first releases.
22582258
#'
@@ -2338,22 +2338,21 @@ get_nth_release <- function(df, n = 0, diagonal = FALSE) {
23382338
nth_release <- get_first_release(df)
23392339
}
23402340
if (diagonal) {
2341-
min_pub_date <- df %>%
2342-
dplyr::group_by("id") %>%
2343-
dplyr::summarize(min_pub_date = min(.data$pub_date)) %>%
2344-
dplyr::pull("min_pub_date", "id") %>%
2345-
as.Date()
2346-
2347-
max_time <- df %>%
2348-
dplyr::filter(.data$pub_date == min_pub_date) %>%
2341+
diagonal_thresholds <- df %>%
23492342
dplyr::group_by(.data$id) %>%
2350-
dplyr::summarize(max_time = max(.data$time)) %>%
2351-
dplyr::pull("max_time", "id") %>%
2352-
as.Date()
2343+
dplyr::summarise(min_pub_date = min(.data$pub_date), .groups = "drop") %>%
2344+
dplyr::left_join(
2345+
df %>%
2346+
dplyr::group_by(.data$id, .data$pub_date) %>%
2347+
dplyr::summarise(max_time = max(.data$time), .groups = "drop"),
2348+
by = c("id", "min_pub_date" = "pub_date")
2349+
) %>%
2350+
dplyr::select(.data$id, .data$max_time)
23532351

2354-
# Filter using direct vectorized lookup
2355-
df <- df %>%
2356-
dplyr::filter(.data$time >= max_time[.data$id])
2352+
nth_release <- nth_release %>%
2353+
dplyr::left_join(diagonal_thresholds, by = "id") %>%
2354+
dplyr::filter(.data$time >= .data$max_time) %>%
2355+
dplyr::select(-"max_time")
23572356
}
23582357
} else {
23592358
# Ensure data is sorted by pub_date and time
@@ -2380,7 +2379,7 @@ get_nth_release <- function(df, n = 0, diagonal = FALSE) {
23802379
if (diagonal) {
23812380
min_pub_date <- min(df$pub_date)
23822381
max_time <- max(df$time[df$pub_date == min_pub_date])
2383-
df <- df %>%
2382+
nth_release <- nth_release %>%
23842383
dplyr::filter(
23852384
.data$time >= max_time
23862385
)
@@ -2508,7 +2507,7 @@ get_latest_release <- function(df) {
25082507
dplyr::arrange(.data$id, .data$pub_date, .data$time)
25092508
df <- df %>%
25102509
dplyr::group_by(.data$id, .data$time) %>%
2511-
dplyr::mutate("release" = paste0("release_", dplyr::n())) %>%
2510+
dplyr::mutate("release" = paste0("release_", dplyr::n() - 1)) %>%
25122511
dplyr::filter(.data$pub_date == max(.data$pub_date)) %>%
25132512
dplyr::ungroup()
25142513
} else {
@@ -2517,7 +2516,7 @@ get_latest_release <- function(df) {
25172516
dplyr::arrange(.data$pub_date, .data$time)
25182517
df <- df %>%
25192518
dplyr::group_by(.data$time) %>%
2520-
dplyr::mutate("release" = paste0("release_", dplyr::n())) %>%
2519+
dplyr::mutate("release" = paste0("release_", dplyr::n() - 1)) %>%
25212520
dplyr::filter(.data$pub_date == max(.data$pub_date)) %>%
25222521
dplyr::ungroup()
25232522
}
@@ -2538,10 +2537,12 @@ get_latest_release <- function(df) {
25382537
#' time` (observation date).
25392538
#' @param month An optional parameter specifying the target month as a name
25402539
#' ("July") or an integer (7). Cannot be used with `quarter`.
2540+
#' At least one of `month` or `quarter` must be supplied.
25412541
#' @param quarter An optional parameter specifying the target quarter (1-4).
2542-
#' Cannot be used with `month`.
2543-
#' @param years The integer number of unrestricted years after `pub_date` for
2544-
#' which the values should be extracted.
2542+
#' Cannot be used with `month`. At least one of `month` or `quarter` must be
2543+
#' supplied.
2544+
#' @param years A single whole number of years after `pub_date` for which the
2545+
#' values should be extracted.
25452546
#'
25462547
#' @return A filtered data frame containing values matching the
25472548
#' specified criteria.
@@ -2559,26 +2560,45 @@ get_fixed_release <- function(df, years, month = NULL, quarter = NULL) {
25592560
rlang::abort("Specify either a month or a quarter, not both.")
25602561
}
25612562

2562-
# Ensure years is numeric and integer or can be converted to integer
2563-
if (is.numeric(years)) {
2564-
if (years %% 1 != 0) {
2565-
rlang::abort("years' must be a whole number.")
2566-
}
2567-
years <- as.integer(years)
2563+
# Ensure one target period is specified
2564+
if (is.null(month) && is.null(quarter)) {
2565+
rlang::abort("Specify one of 'month' or 'quarter'.")
25682566
}
25692567

2568+
# Ensure years is a single whole number
2569+
if (!is.numeric(years) || length(years) != 1 || is.na(years) || years %% 1 != 0) {
2570+
rlang::abort("'years' must be a single whole number.")
2571+
}
2572+
years <- as.integer(years)
2573+
25702574
# Ensure the month is in numeric format if provided
25712575
if (!is.null(month)) {
25722576
if (is.character(month)) {
2577+
if (length(month) != 1) {
2578+
rlang::abort("Invalid 'month'. Must be a single month name or integer.")
2579+
}
25732580
month <- match(tolower(month), tolower(month.name))
25742581
if (is.na(month)) rlang::abort("Invalid 'month' name")
2582+
} else if (
2583+
!is.numeric(month) || length(month) != 1 || is.na(month) ||
2584+
month %% 1 != 0 || month < 1 || month > 12
2585+
) {
2586+
rlang::abort(
2587+
"Invalid 'month'. Must be an integer between 1 and 12 or a month name."
2588+
)
25752589
}
2590+
month <- as.integer(month)
25762591
}
2592+
25772593
# Ensure quarter is in numeric format if provided
25782594
if (!is.null(quarter)) {
2579-
if (!quarter %in% 1:4) {
2595+
if (
2596+
!is.numeric(quarter) || length(quarter) != 1 || is.na(quarter) ||
2597+
quarter %% 1 != 0 || !quarter %in% 1:4
2598+
) {
25802599
rlang::abort("Invalid quarter number. Must be between 1 and 4.")
25812600
}
2601+
quarter <- as.integer(quarter)
25822602
}
25832603

25842604
check <- vintages_check(df)

man/get_fixed_release.Rd

Lines changed: 6 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/get_nth_release.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/jvn_nowcast.Rd

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-revisions.R

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,56 @@ test_that("get_nth_release case insensitivity", {
320320
expect_equal(nrow(result1), nrow(result2))
321321
})
322322

323+
test_that("get_nth_release diagonal filters historical rows", {
324+
df_diag <- tibble::tibble(
325+
time = as.Date(c(
326+
"2020-01-01", "2020-02-01", "2020-01-01", "2020-02-01", "2020-03-01"
327+
)),
328+
pub_date = as.Date(c(
329+
"2020-02-01", "2020-02-01", "2020-03-01", "2020-03-01", "2020-03-01"
330+
)),
331+
value = c(1, 2, 1.1, 2.1, 3.1)
332+
)
333+
334+
result_all <- get_nth_release(df_diag, n = 0, diagonal = FALSE)
335+
result_diag <- get_nth_release(df_diag, n = 0, diagonal = TRUE)
336+
337+
expect_lt(nrow(result_diag), nrow(result_all))
338+
expect_true(all(result_diag$time >= as.Date("2020-02-01")))
339+
})
340+
341+
test_that("get_nth_release diagonal works for multiple IDs", {
342+
df_a <- tibble::tibble(
343+
id = "A",
344+
time = as.Date(c(
345+
"2020-01-01", "2020-02-01", "2020-01-01", "2020-02-01", "2020-03-01"
346+
)),
347+
pub_date = as.Date(c(
348+
"2020-02-01", "2020-02-01", "2020-03-01", "2020-03-01", "2020-03-01"
349+
)),
350+
value = c(1, 2, 1.1, 2.1, 3.1)
351+
)
352+
df_b <- tibble::tibble(
353+
id = "B",
354+
time = as.Date(c(
355+
"2020-01-01", "2020-01-01", "2020-02-01", "2020-03-01"
356+
)),
357+
pub_date = as.Date(c(
358+
"2020-02-01", "2020-03-01", "2020-03-01", "2020-03-01"
359+
)),
360+
value = c(5, 5.1, 6.1, 7.1)
361+
)
362+
df_multi <- dplyr::bind_rows(df_a, df_b)
363+
364+
result <- get_nth_release(df_multi, n = "first", diagonal = TRUE)
365+
counts <- result %>%
366+
dplyr::count(id) %>%
367+
dplyr::arrange(id)
368+
369+
expect_equal(counts$n[counts$id == "A"], 2)
370+
expect_equal(counts$n[counts$id == "B"], 3)
371+
})
372+
323373
# ===== Tests for get_first_release =====
324374

325375
test_that("get_first_release returns first release", {
@@ -336,6 +386,7 @@ test_that("get_latest_release returns latest release", {
336386

337387
expect_true(inherits(result, "tbl_pubdate") || inherits(result, "tbl_release"))
338388
expect_true("release" %in% colnames(result))
389+
expect_true(all(result$release == "release_4"))
339390
})
340391

341392
# ===== Tests for get_fixed_release =====
@@ -365,6 +416,13 @@ test_that("get_fixed_release validates exclusive parameters", {
365416
)
366417
})
367418

419+
test_that("get_fixed_release requires month or quarter", {
420+
expect_error(
421+
get_fixed_release(df_long_rev, years = 1),
422+
"Specify one of 'month' or 'quarter'"
423+
)
424+
})
425+
368426
test_that("get_fixed_release validates years parameter", {
369427
expect_error(
370428
get_fixed_release(df_long_rev, month = 7, years = 1.5),
@@ -521,4 +579,4 @@ test_that("summary.lst_efficient handles NA efficient release", {
521579

522580
expect_s3_class(df_out, "data.frame")
523581
expect_true(is.na(df_out$e))
524-
})
582+
})

tests/testthat/tests-kk.R

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -520,9 +520,12 @@ test_that("kk_matrices validates params length", {
520520
})
521521

522522
test_that("kk_matrices validates params are named", {
523-
# Skip - the function tries to access params by name before validating they are named
524-
# This is a design issue in kk_matrices that causes subscript out of bounds error
525-
skip("kk_matrices accesses params before validating names")
523+
params <- rep(0.2, 5) # Correct length for e = 1 KK model, but unnamed
524+
525+
expect_error(
526+
kk_matrices(e = 1, model = "KK", params = params, type = "numeric"),
527+
"All parameters must be named"
528+
)
526529
})
527530

528531
test_that("kk_matrices handles Howrey model correctly", {
@@ -893,4 +896,4 @@ test_that("kk_nowcast confidence intervals have correct coverage", {
893896
states <- result$states
894897
expect_true(all(states$lower <= states$estimate, na.rm = TRUE))
895898
expect_true(all(states$estimate <= states$upper, na.rm = TRUE))
896-
})
899+
})

0 commit comments

Comments
 (0)