|
1 |
| -froll = function(fun, x, n, fill=NA, algo=c("fast", "exact"), align=c("right", "left", "center"), na.rm=FALSE, hasNA=NA, adaptive=FALSE) { |
2 |
| - stopifnot(!missing(fun), is.character(fun), length(fun)==1L, !is.na(fun)) |
3 |
| - algo = match.arg(algo) |
| 1 | +# helpers for partial2adaptive |
| 2 | +trimn = function(n, len, align) { |
| 3 | + n = min(n, len) ## so frollsum(1:2, 3, partial=TRUE) works |
| 4 | + if (align=="right") |
| 5 | + c(seq_len(n), rep.int(n, len-n)) |
| 6 | + else |
| 7 | + c(rep.int(n, len-n), rev(seq_len(n))) |
| 8 | +} |
| 9 | +trimnadaptive = function(n, align) { |
| 10 | + if (align=="right") |
| 11 | + pmin(n, seq_along(n)) |
| 12 | + else |
| 13 | + pmin(n, rev(seq_along(n))) |
| 14 | +} |
| 15 | + |
| 16 | +# partial2adaptive helper function |
| 17 | +## tune provided 'n' via partial=TRUE to adaptive=TRUE by prepared adaptive 'n' as shown in ?froll examples |
| 18 | +# partial2adaptive(1:4, 2, "right", adaptive=FALSE) |
| 19 | +# partial2adaptive(1:4, 2:3, "right", adaptive=FALSE) |
| 20 | +# partial2adaptive(list(1:4, 2:5), 2:3, "right", adaptive=FALSE) |
| 21 | +# frollsum(1:4, 2, partial=FALSE, adaptive=FALSE) |
| 22 | +# frollsum(1:4, 2, partial=TRUE, adaptive=FALSE) |
| 23 | +# frollsum(1:4, 2:3, partial=FALSE, adaptive=FALSE) |
| 24 | +# frollsum(1:4, 2:3, partial=TRUE, adaptive=FALSE) |
| 25 | +# frollsum(list(1:4, 2:5), 2:3, partial=FALSE, adaptive=FALSE) |
| 26 | +# frollsum(list(1:4, 2:5), 2:3, partial=TRUE, adaptive=FALSE) |
| 27 | +partial2adaptive = function(x, n, align, adaptive) { |
| 28 | + if (!length(n)) |
| 29 | + stopf("n must be non 0 length") |
| 30 | + if (align=="center") |
| 31 | + stopf("'partial' cannot be used together with align='center'") |
| 32 | + if (is.list(x) && length(unique(lengths(x))) != 1L) |
| 33 | + stopf("'partial' does not support variable length of columns in 'x'") |
| 34 | + len = if (is.list(x)) length(x[[1L]]) else length(x) |
| 35 | + verbose = getOption("datatable.verbose") |
| 36 | + if (!adaptive) { |
| 37 | + if (is.list(n)) |
| 38 | + stopf("n must be an integer, list is accepted for adaptive TRUE") |
| 39 | + if (!is.numeric(n)) |
| 40 | + stopf("n must be an integer vector or a list of integer vectors") |
| 41 | + if (verbose) |
| 42 | + catf("partial2adaptive: froll partial=TRUE trimming 'n' and redirecting to adaptive=TRUE\n") |
| 43 | + if (length(n) > 1L) { |
| 44 | + ## c(2,3) -> list(c(1,2,2,2),c(1,2,3,3)) ## for x=1:4 |
| 45 | + lapply(n, len, align, FUN=trimn) |
| 46 | + } else { |
| 47 | + ## 3 -> c(1,2,3,3) ## for x=1:4 |
| 48 | + trimn(n, len, align) |
| 49 | + } |
| 50 | + } else { |
| 51 | + if (!(is.numeric(n) || (is.list(n) && all(vapply_1b(n, is.numeric))))) |
| 52 | + stopf("n must be an integer vector or a list of integer vectors") |
| 53 | + if (length(unique(lengths(n))) != 1L) |
| 54 | + stopf("adaptive window provided in 'n' must not to have different lengths") |
| 55 | + if (is.numeric(n) && length(n) != len) |
| 56 | + stopf("length of 'n' argument must be equal to number of observations provided in 'x'") |
| 57 | + if (is.list(n) && length(n[[1L]]) != len) |
| 58 | + stopf("length of vectors in 'x' must match to length of adaptive window in 'n'") |
| 59 | + if (verbose) |
| 60 | + catf("partial2adaptive: froll adaptive=TRUE and partial=TRUE trimming 'n'\n") |
| 61 | + if (is.numeric(n)) { |
| 62 | + ## c(3,3,3,2) -> c(1,2,3,2) ## for x=1:4 |
| 63 | + trimnadaptive(n, align) |
| 64 | + } else { |
| 65 | + ## list(c(3,3,3,2),c(4,2,3,3)) -> list(c(1,2,3,2),c(1,2,3,3)) ## for x=1:4 |
| 66 | + lapply(n, align, FUN = trimnadaptive) |
| 67 | + } |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +froll = function(fun, x, n, fill=NA, algo, align=c("right","left","center"), na.rm=FALSE, has.nf=NA, adaptive=FALSE, partial=FALSE, FUN, rho, give.names=FALSE) { |
4 | 72 | align = match.arg(align)
|
5 |
| - ans = .Call(CfrollfunR, fun, x, n, fill, algo, align, na.rm, hasNA, adaptive) |
| 73 | + if (isTRUE(give.names)) |
| 74 | + orig = list(n=n, adaptive=adaptive) |
| 75 | + if (isTRUE(partial)) { |
| 76 | + n = partial2adaptive(x, n, align, adaptive) |
| 77 | + adaptive = TRUE |
| 78 | + } |
| 79 | + leftadaptive = isTRUE(adaptive) && align=="left" |
| 80 | + if (leftadaptive) { |
| 81 | + verbose = getOption("datatable.verbose") |
| 82 | + rev2 = function(x) if (is.list(x)) lapply(x, rev) else rev(x) |
| 83 | + if (verbose) |
| 84 | + catf("froll: adaptive=TRUE && align='left' pre-processing for align='right'\n") |
| 85 | + x = rev2(x) |
| 86 | + n = rev2(n) |
| 87 | + align = "right" |
| 88 | + } ## support for left adaptive added in #5441 |
| 89 | + if (missing(FUN)) |
| 90 | + ans = .Call(CfrollfunR, fun, x, n, fill, algo, align, na.rm, has.nf, adaptive) |
| 91 | + else |
| 92 | + ans = .Call(CfrollapplyR, FUN, x, n, fill, align, adaptive, rho) |
| 93 | + if (leftadaptive) { |
| 94 | + if (verbose) |
| 95 | + catf("froll: adaptive=TRUE && align='left' post-processing from align='right'\n") |
| 96 | + ans = rev2(ans) |
| 97 | + } |
| 98 | + if (isTRUE(give.names) && is.list(ans)) { |
| 99 | + n = orig$n |
| 100 | + adaptive = orig$adaptive |
| 101 | + nx = names(x) |
| 102 | + nn = names(n) |
| 103 | + if (is.null(nx)) nx = paste0("V", if (is.atomic(x)) 1L else seq_along(x)) |
| 104 | + if (is.null(nn)) nn = if (adaptive) paste0("N", if (is.atomic(n)) 1L else seq_along(n)) else paste("roll", as.character(n), sep="_") |
| 105 | + setattr(ans, "names", paste(rep(nx, each=length(nn)), nn, sep="_")) |
| 106 | + } |
6 | 107 | ans
|
7 | 108 | }
|
8 | 109 |
|
9 |
| -frollmean = function(x, n, fill=NA, algo=c("fast", "exact"), align=c("right", "left", "center"), na.rm=FALSE, hasNA=NA, adaptive=FALSE) { |
10 |
| - froll(fun="mean", x=x, n=n, fill=fill, algo=algo, align=align, na.rm=na.rm, hasNA=hasNA, adaptive=adaptive) |
| 110 | +frollfun = function(fun, x, n, fill=NA, algo=c("fast","exact"), align=c("right","left","center"), na.rm=FALSE, has.nf=NA, adaptive=FALSE, partial=FALSE, hasNA, give.names=FALSE) { |
| 111 | + stopifnot(!missing(fun), is.character(fun), length(fun)==1L, !is.na(fun)) |
| 112 | + if (!missing(hasNA)) { |
| 113 | + if (!is.na(has.nf)) |
| 114 | + stopf("hasNA is deprecated, use has.nf instead") |
| 115 | + warningf("hasNA is deprecated, use has.nf instead") |
| 116 | + has.nf = hasNA |
| 117 | + } # remove check on next major release |
| 118 | + algo = match.arg(algo) |
| 119 | + froll(fun=fun, x=x, n=n, fill=fill, algo=algo, align=align, na.rm=na.rm, has.nf=has.nf, adaptive=adaptive, partial=partial, give.names=give.names) |
| 120 | +} |
| 121 | + |
| 122 | +frollmean = function(x, n, fill=NA, algo=c("fast","exact"), align=c("right","left","center"), na.rm=FALSE, has.nf=NA, adaptive=FALSE, partial=FALSE, hasNA, give.names=FALSE) { |
| 123 | + frollfun(fun="mean", x=x, n=n, fill=fill, algo=algo, align=align, na.rm=na.rm, has.nf=has.nf, adaptive=adaptive, partial=partial, hasNA=hasNA, give.names=give.names) |
| 124 | +} |
| 125 | +frollsum = function(x, n, fill=NA, algo=c("fast","exact"), align=c("right","left","center"), na.rm=FALSE, has.nf=NA, adaptive=FALSE, partial=FALSE, hasNA, give.names=FALSE) { |
| 126 | + frollfun(fun="sum", x=x, n=n, fill=fill, algo=algo, align=align, na.rm=na.rm, has.nf=has.nf, adaptive=adaptive, partial=partial, hasNA=hasNA, give.names=give.names) |
11 | 127 | }
|
12 |
| -frollsum = function(x, n, fill=NA, algo=c("fast","exact"), align=c("right", "left", "center"), na.rm=FALSE, hasNA=NA, adaptive=FALSE) { |
13 |
| - froll(fun="sum", x=x, n=n, fill=fill, algo=algo, align=align, na.rm=na.rm, hasNA=hasNA, adaptive=adaptive) |
| 128 | +frollmax = function(x, n, fill=NA, algo=c("fast","exact"), align=c("right","left","center"), na.rm=FALSE, has.nf=NA, adaptive=FALSE, partial=FALSE, hasNA, give.names=FALSE) { |
| 129 | + frollfun(fun="max", x=x, n=n, fill=fill, algo=algo, align=align, na.rm=na.rm, has.nf=has.nf, adaptive=adaptive, partial=partial, hasNA=hasNA, give.names=give.names) |
14 | 130 | }
|
15 |
| -frollapply = function(x, n, FUN, ..., fill=NA, align=c("right", "left", "center")) { |
| 131 | + |
| 132 | +frollapply = function(x, n, FUN, ..., fill=NA, align=c("right","left","center"), adaptive=FALSE, partial=FALSE, give.names=FALSE) { |
16 | 133 | FUN = match.fun(FUN)
|
17 |
| - align = match.arg(align) |
18 | 134 | rho = new.env()
|
19 |
| - ans = .Call(CfrollapplyR, FUN, x, n, fill, align, rho) |
20 |
| - ans |
| 135 | + froll(FUN=FUN, rho=rho, x=x, n=n, fill=fill, align=align, adaptive=adaptive, partial=partial, give.names=give.names) |
21 | 136 | }
|
0 commit comments