|
1 | 1 | # ---- Distances ----
|
2 | 2 | #' @title Calculate the DTW distance between temporal patterns and time-series.
|
3 |
| -#' @name .dtw_distance |
4 |
| -#' @description This function calculates the DTW distance between label patterns |
5 |
| -#' and real data (e.g., sample data, data cube data). The distance is calculated |
6 |
| -#' without a window. It's use is recommended for big datasets. |
7 |
| -#' @keywords internal |
8 |
| -#' @noRd |
9 |
| -.dtw_distance <- function(data, patterns) { |
10 |
| - # Prepare input data |
11 |
| - data <- as.matrix(.ts_values(data)) |
12 |
| - # Calculate the DTW distance between `data` and `patterns` |
13 |
| - purrr::map_dfc(patterns, function(pattern) { |
14 |
| - # Prepare pattern data |
15 |
| - pattern_ts <- as.matrix(.ts_values(pattern)) |
16 |
| - # Calculate distance |
17 |
| - stats::setNames( |
18 |
| - data.frame(distance = dtw_distance(data, pattern_ts)), |
19 |
| - pattern[["label"]][[1]] |
20 |
| - ) |
21 |
| - }) |
22 |
| -} |
23 |
| -#' @title Calculate the DTW distance between temporal patterns and time-series. |
24 | 3 | #' @name .dtw_distance_windowed
|
25 | 4 | #' @description This function calculates the DTW distance between label patterns
|
26 | 5 | #' and real data (e.g., sample data, data cube data). The distance is calculated
|
|
35 | 14 | # Windowed search
|
36 | 15 | distances <- purrr::map_df(windows, function(window) {
|
37 | 16 | # Get time-series in the window
|
38 |
| - data_in_window <- |
39 |
| - dplyr::filter(data, |
40 |
| - .data[["Index"]] >= window[["start"]], |
41 |
| - .data[["Index"]] <= window[["end"]]) |
42 |
| - # Remove the time reference column |
43 |
| - data_in_window <- as.matrix(.ts_values(data_in_window)) |
| 17 | + data_in_window <- as.matrix(.ts_values(data[window,])) |
44 | 18 | # Calculate distance
|
45 | 19 | data.frame(distance = dtw_distance(data_in_window, pattern_ts))
|
46 | 20 | })
|
|
49 | 23 | })
|
50 | 24 | }
|
51 | 25 | # ---- Operation mode ----
|
52 |
| -#' @title Search for events in time series using complete data (no windowing). |
53 |
| -#' @name .dtw_complete_ts |
54 |
| -#' @description This function searches for events in time series without |
55 |
| -#' windowing. |
| 26 | +#' @title Search for events in data cube. |
| 27 | +#' @name .dtw_cube |
| 28 | +#' @description This function searches for events in data cubes. |
56 | 29 | #' @keywords internal
|
57 | 30 | #' @noRd
|
58 |
| -.dtw_complete_ts <- function(values, patterns, threshold, ...) { |
| 31 | +.dtw_cube <- function(values, patterns, window, threshold, ...) { |
| 32 | + # Extract dates |
| 33 | + dates <- .ts_index(values[[1]]) |
| 34 | + dates_min <- .ts_min_date(values[[1]]) |
| 35 | + dates_max <- .ts_max_date(values[[1]]) |
| 36 | + # Assume time-series are regularized, then use the period |
| 37 | + # as the step of the moving window. As a result, we have |
| 38 | + # one step per iteration. |
| 39 | + dates_step <- lubridate::as.period( |
| 40 | + lubridate::int_diff(.ts_index(values[[1]])) |
| 41 | + ) |
| 42 | + dates_step <- dates_step[[1]] |
| 43 | + # Create comparison windows |
| 44 | + comparison_windows <- .period_windows( |
| 45 | + period = window, |
| 46 | + step = dates_step, |
| 47 | + start_date = dates_min, |
| 48 | + end_date = dates_max |
| 49 | + ) |
| 50 | + # Transform comparison windows to indices to avoid filters |
| 51 | + comparison_windows <- purrr::map(comparison_windows, function(window) { |
| 52 | + which( |
| 53 | + dates >= window[["start"]] & dates <= window[["end"]] |
| 54 | + ) |
| 55 | + }) |
59 | 56 | # Do the change detection for each time-series
|
60 | 57 | purrr::map_vec(values, function(value_row) {
|
61 | 58 | # Search for the patterns
|
62 |
| - patterns_distances <- .dtw_distance( |
| 59 | + patterns_distances <- .dtw_distance_windowed( |
63 | 60 | data = value_row,
|
64 |
| - patterns = patterns |
| 61 | + patterns = patterns, |
| 62 | + windows = comparison_windows |
65 | 63 | )
|
66 | 64 | # Remove distances out the user-defined threshold
|
67 |
| - as.numeric(any(patterns_distances <= threshold)) |
| 65 | + patterns_distances[patterns_distances <= threshold] <- 1 |
| 66 | + patterns_distances[patterns_distances > threshold] <- 0 |
| 67 | + # Get the position of the valid values |
| 68 | + patterns_distances <- which(patterns_distances == 1) |
| 69 | + # Return value |
| 70 | + ifelse(length(patterns_distances) > 0, min(patterns_distances), 0) |
68 | 71 | })
|
69 | 72 | }
|
70 |
| -#' @title Search for events in time series using windowing. |
71 |
| -#' @name .dtw_windowed_ts |
72 |
| -#' @description This function searches for events in time series with windowing. |
| 73 | +#' @title Search for events in time-series. |
| 74 | +#' @name .dtw_ts |
| 75 | +#' @description This function searches for events in time-series |
73 | 76 | #' @keywords internal
|
74 | 77 | #' @noRd
|
75 |
| -.dtw_windowed_ts <- function(values, patterns, window, threshold) { |
| 78 | +.dtw_ts <- function(values, patterns, window, threshold, ...) { |
76 | 79 | # Extract dates
|
| 80 | + dates <- .ts_index(values[[1]]) |
77 | 81 | dates_min <- .ts_min_date(values[[1]])
|
78 | 82 | dates_max <- .ts_max_date(values[[1]])
|
79 | 83 | # Assume time-series are regularized, then use the period
|
|
90 | 94 | start_date = dates_min,
|
91 | 95 | end_date = dates_max
|
92 | 96 | )
|
| 97 | + # Transform comparison windows to indices to avoid filters |
| 98 | + comparison_windows_idx <- purrr::map(comparison_windows, function(window) { |
| 99 | + which( |
| 100 | + dates >= window[["start"]] & dates <= window[["end"]] |
| 101 | + ) |
| 102 | + }) |
93 | 103 | # Do the change detection for each time-series
|
94 | 104 | purrr::map(values, function(value_row) {
|
95 | 105 | # Search for the patterns
|
96 | 106 | patterns_distances <- .dtw_distance_windowed(
|
97 | 107 | data = value_row,
|
98 | 108 | patterns = patterns,
|
99 |
| - windows = comparison_windows |
| 109 | + windows = comparison_windows_idx |
100 | 110 | )
|
101 | 111 | # Remove distances out the user-defined threshold
|
102 | 112 | patterns_distances[patterns_distances > threshold] <- NA
|
|
0 commit comments