-
Notifications
You must be signed in to change notification settings - Fork 1k
adapt uneven time series rolling window #5576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
67 commits
Select commit
Hold shift + click to select a range
cca5b79
frollmax exact, buggy fast, no fast adaptive
jangorecki 14555b2
frollmax fast fixing bugs
jangorecki 437b928
frollmax man to fix CRAN check
jangorecki 2fd0faf
frollmax fast adaptive non NA, dev
jangorecki 6c3201a
froll docs, adaptive left
jangorecki 4a6f063
no frollmax fast adaptive
jangorecki feef63d
frollmax adaptive exact NAs handling
jangorecki 63ea485
PR summary in news
jangorecki 63f2e7d
align happens in one place, less duplicated code
jangorecki 5341409
push up even more to frollR to reduce code duplication
jangorecki c4675be
frollapply push up align arg and early stopping up
jangorecki ccd5c43
typo fix in NEWS.md
jangorecki 2494b97
keep R agnostic C code in froll.c, yet deduplicated
jangorecki 77a01e7
new functionality unit tests
jangorecki 311d12f
doc further improving
jangorecki 2a54cfd
tests and NEWS
jangorecki 5a52167
partial window support for rolling functions
jangorecki cab28b5
unit tests for partial corner cases
jangorecki 161f9f5
frollapply adaptive
jangorecki fc69835
add frollapply to timings
jangorecki 6c25f5f
fix missing break
jangorecki dd72ba0
frollmax non-adaptive, fast, exact, NAs
jangorecki fa36f41
fix wrong fun name in docs
jangorecki 1e8117f
docs
jangorecki 2f326de
more automated tests, check for SET_GROWABLE_BIT support
jangorecki 911968f
eliminate TODOs
jangorecki 844edc5
simplify frollmax adaptive
jangorecki f8a909a
docs
jangorecki d26aa5e
extend readme
jangorecki 3c11ac0
readme tidy links
jangorecki d7bf748
bold names
jangorecki 0385c31
mean exact no re-run NA-aware when Inf/-Inf present
jangorecki 11dde58
handle Inf in froll mean and sum
jangorecki e99c381
has.nf, bring back warnings
jangorecki 2b106ec
no need extra temp var here
jangorecki 18b26bf
refresh timings in NEWS
jangorecki 8a69058
deduplicate N arg handling
jangorecki fa796e3
minor rename
jangorecki a47c7a4
simplify even more k arg
jangorecki cb25135
remove debug line
jangorecki 7184024
improve doc too mention adaptive rolling function to address #3241
jangorecki c5caf2c
fix code covr, thanks to Jim
jangorecki e3eaefe
fix nocov blocks
jangorecki 1f66c43
fix codecov
jangorecki 4218fa5
more clearly address #5306
jangorecki 6277b71
codecov
jangorecki 95d8cca
deduplicate partial and left adaptive logic
jangorecki c54ccce
give.names arg for rolling functions
jangorecki 88a5c2d
give.names mention in news.md
jangorecki 1661f03
fix conflict to partial preprocessing
jangorecki a642a99
deduplicate some code by using helper instead of macros
jangorecki c5417cd
simplify helper fun ansSetMsg
jangorecki 9c4fbc8
fix codecov exposed after removing macros
jangorecki b3f81cd
support for adaptive and partial
jangorecki a14b486
added batch tests for adaptive and partial
jangorecki d096517
frollapply rewritten
jangorecki 309ef97
dev adapt
jangorecki 149677b
vectorized, renamed
jangorecki ceee3a5
tests frolladapt and improvements
jangorecki f2c3b70
tests against slider
jangorecki 873d4de
frolladapt man
jangorecki 771f0fd
more frolladapt tests
jangorecki a732043
remove deve pieces from frolladapt
jangorecki 107181c
remove unused
jangorecki bda8c09
frolladapt new entry
jangorecki 566f1d1
use Date rather than IDate to convey it works with base R classes as …
jangorecki 319c027
mention frolladapt is only align=right for the moment
jangorecki File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,182 @@ | ||
| froll = function(fun, x, n, fill=NA, algo=c("fast", "exact"), align=c("right", "left", "center"), na.rm=FALSE, hasNA=NA, adaptive=FALSE) { | ||
| ## those two helpers does not quote argument names in errors because frollapply has them in uppercase | ||
| partial2adaptive = function(x, n, align, adaptive) { | ||
| if (align=="center") | ||
| stopf("'partial' cannot be used together with align='center'") | ||
| if (is.list(x)) { | ||
| if (!is.data.frame(x) && length(unique(vapply(x, length, 0L)))!=1L) ## froll | ||
| stopf("'partial' does not support variable length of columns in x") | ||
| else if (all(vapply(x, is.data.frame, FALSE)) && length(unique(vapply(x, nrow, 0L)))!=1L) ## frollapply by.column=F, single DT already wrapped into list | ||
| stopf("'partial' does not support variable nrow of data.tables in x") | ||
| } | ||
| if (!adaptive) { | ||
| if (is.list(n)) | ||
| stopf("n must be integer, list is accepted for adaptive TRUE") | ||
| else if (!is.numeric(n)) | ||
| stopf("n must be integer vector") | ||
| } else if (!(is.numeric(n) || (is.list(n) && all(vapply(n, is.numeric, FALSE))))) { | ||
| stopf("n must be integer vector or list of integer vectors") | ||
| } | ||
| len = if (is.list(x)) { | ||
| if (is.data.frame(x[[1L]])) ## frollapply by.column | ||
| nrow(x[[1L]]) | ||
| else | ||
| length(x[[1L]]) ## froll, this will work for both x list and x dt on input | ||
| } else length(x) | ||
| verbose = getOption("datatable.verbose") | ||
| if (!adaptive) { | ||
| n = as.list(n) ## test 6006.032 | ||
| if (verbose) | ||
| cat("partial2adaptive: froll partial=TRUE trimming n and redirecting to adaptive=TRUE\n") | ||
| trimn = function(n, len, align) { | ||
| n = min(n, len) | ||
| if (align=="right") | ||
| c(seq_len(n), rep(n, len-n)) | ||
| else | ||
| c(rep(n, len-n), rev(seq_len(n))) | ||
| } | ||
| sapply(n, len, align, FUN=trimn, simplify=FALSE) | ||
| } else { | ||
| if (!is.list(n)) n = list(n) | ||
| if (length(unique(vapply(n, length, 0L)))!=1L) | ||
| stopf("adaptive windows provided in n must not to have different lengths") | ||
| if (length(n[[1L]]) != len) | ||
| stopf("length of vectors in x must match to length of adaptive window in n") | ||
| if (verbose) | ||
| cat("partial2adaptive: froll adaptive=TRUE and partial=TRUE trimming n\n") | ||
| triman = function(n, align) { | ||
| if (align=="right") | ||
| pmin(n, seq_along(n)) | ||
| else | ||
| pmin(n, rev(seq_along(n))) | ||
| } | ||
| sapply(n, align, FUN=triman, simplify=FALSE) | ||
| } | ||
| } | ||
| make.roll.names = function(x.len, n.len, n, x.nm, n.nm, fun, adaptive) { | ||
| if (is.null(n.nm)) { | ||
| if (!adaptive) { | ||
| if (!is.numeric(n)) | ||
| stopf("internal error: misuse of make.names, n must be numeric for !adaptive") ## nocov | ||
| n.nm = paste0("roll", fun, as.character(as.integer(n))) | ||
| } else { | ||
| n.nm = paste0("aroll", fun, seq_len(n.len)) | ||
| } | ||
| } else if (!length(n.nm) && !adaptive) | ||
| stopf("internal error: misuse of make.names, non-null length 0 n is not possible for !adaptive") ## nocov | ||
| if (is.null(x.nm)) { | ||
| x.nm = paste0("V", seq_len(x.len)) | ||
| } | ||
| ans = if (length(x.nm)) { ## is.list(x) && !is.data.frame(x) | ||
| if (length(n.nm)) { ## !adaptive || is.list(n) | ||
| paste(rep(x.nm, each=length(n.nm)), n.nm, sep="_") | ||
| } else { ## adaptive && is.numeric(n) | ||
| x.nm | ||
| } | ||
| } else { ## (by.column && is.atomic(x)) || (!by.column && is.data.frame(x)) | ||
| if (length(n.nm)) { ## !adaptive || is.list(n) | ||
| n.nm | ||
| } else { ## adaptive && is.numeric(n) | ||
| NULL | ||
| } | ||
| } | ||
| if (!is.null(ans) && length(ans) != x.len*n.len) | ||
| stopf("internal error: make.names generated names of wrong length") ## nocov | ||
| ans | ||
| } | ||
|
|
||
| ## irregularly spaced time series, helper for creating adaptive window size | ||
| frolladapt = function(x, n, align="right", partial=FALSE, give.names=FALSE) { | ||
| x = unclass(x) | ||
| if (!is.numeric(x)) | ||
| stopf("Index vector 'x' must of numeric type") | ||
| if (!is.integer(x)) | ||
| x = as.integer(x) | ||
| if (!is.numeric(n)) { | ||
| stopf("Window size 'n' must be integer") | ||
| } else { | ||
| nms = names(n) ## only for give.names | ||
| if (!is.integer(n)) { | ||
| if (!isRealReallyInt(n)) | ||
| stopf("Window size 'n' must be integer") | ||
| n = as.integer(n) | ||
| } | ||
| } | ||
| if (length(n) < 1L || anyNA(n)) | ||
| stopf("Argument 'n' must be non-zero length and must not have NAs") | ||
| if (!identical(align, "right")) | ||
| stopf("Argument 'align' other than 'right' has not yet been implemented") | ||
| if (!isTRUEorFALSE(partial)) | ||
| stopf("Argument 'partial' must be TRUE or FALSE") | ||
| if (!isTRUEorFALSE(give.names)) | ||
| stopf("Argument 'give.names' must be TRUE or FALSE") | ||
|
|
||
| if (length(n) == 1L) { | ||
| ans = .Call(Cfrolladapt, x, n, partial) | ||
| } else { | ||
| ans = lapply(n, function(.n) .Call(Cfrolladapt, x, .n, partial)) | ||
| if (give.names) { | ||
| if (is.null(nms)) | ||
| nms = paste0("n", as.character(n)) | ||
| setattr(ans, "names", nms) | ||
| } | ||
| } | ||
| ans | ||
| } | ||
|
|
||
| froll = 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, give.names=FALSE, hasNA=NA) { | ||
| stopifnot(!missing(fun), is.character(fun), length(fun)==1L, !is.na(fun)) | ||
| if (!missing(hasNA)) { | ||
| if (!is.na(has.nf)) | ||
| stopf("hasNA is deprecated, use has.nf instead") | ||
| warning("hasNA is deprecated, use has.nf instead") | ||
| has.nf = hasNA | ||
| } # remove check on next major release | ||
| algo = match.arg(algo) | ||
| align = match.arg(align) | ||
| ans = .Call(CfrollfunR, fun, x, n, fill, algo, align, na.rm, hasNA, adaptive) | ||
| if (isTRUE(give.names)) { | ||
| orig = list(n=n, adaptive=adaptive) | ||
| xnam = if (is.list(x)) names(x) else character() | ||
| nnam = if (isTRUE(adaptive)) { | ||
| if (is.list(n)) names(n) else character() | ||
| } else names(n) | ||
| nx = if (is.list(x)) length(x) else 1L | ||
| nn = if (isTRUE(adaptive)) { | ||
| if (is.list(n)) length(n) else 1L | ||
| } else length(n) | ||
| } | ||
| if (isTRUE(partial)) { | ||
| n = partial2adaptive(x, n, align, adaptive) | ||
| adaptive = TRUE | ||
| } ## support for partial added in #5441 | ||
| leftadaptive = isTRUE(adaptive) && align=="left" | ||
| if (leftadaptive) { | ||
| verbose = getOption("datatable.verbose") | ||
| rev2 = function(x) if (is.list(x)) sapply(x, rev, simplify=FALSE) else rev(x) | ||
| if (verbose) | ||
| cat("froll: adaptive=TRUE && align='left' pre-processing for align='right'\n") | ||
| x = rev2(x) | ||
| n = rev2(n) | ||
| align = "right" | ||
| } ## support for left adaptive added in #5441 | ||
| ans = .Call(CfrollfunR, fun, x, n, fill, algo, align, na.rm, has.nf, adaptive) | ||
| if (leftadaptive) { | ||
| if (verbose) | ||
| cat("froll: adaptive=TRUE && align='left' post-processing from align='right'\n") | ||
| ans = rev2(ans) | ||
| } | ||
| if (isTRUE(give.names) && is.list(ans)) { | ||
| nms = make.roll.names(x.len=nx, n.len=nn, n=orig$n, x.nm=xnam, n.nm=nnam, fun=fun, adaptive=orig$adaptive) | ||
| setattr(ans, "names", nms) | ||
| } | ||
| ans | ||
| } | ||
|
|
||
| frollmean = function(x, n, fill=NA, algo=c("fast", "exact"), align=c("right", "left", "center"), na.rm=FALSE, hasNA=NA, adaptive=FALSE) { | ||
| froll(fun="mean", x=x, n=n, fill=fill, algo=algo, align=align, na.rm=na.rm, hasNA=hasNA, adaptive=adaptive) | ||
| 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, give.names=FALSE, hasNA) { | ||
| froll(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) | ||
| } | ||
| frollsum = function(x, n, fill=NA, algo=c("fast","exact"), align=c("right", "left", "center"), na.rm=FALSE, hasNA=NA, adaptive=FALSE) { | ||
| froll(fun="sum", x=x, n=n, fill=fill, algo=algo, align=align, na.rm=na.rm, hasNA=hasNA, adaptive=adaptive) | ||
| 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, give.names=FALSE, hasNA) { | ||
| froll(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) | ||
| } | ||
| frollapply = function(x, n, FUN, ..., fill=NA, align=c("right", "left", "center")) { | ||
| FUN = match.fun(FUN) | ||
| align = match.arg(align) | ||
| rho = new.env() | ||
| ans = .Call(CfrollapplyR, FUN, x, n, fill, align, rho) | ||
| ans | ||
| 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, give.names=FALSE, hasNA) { | ||
| froll(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) | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.