| Title: | Common Functions for Run-Length Encoded Vectors |
|---|---|
| Description: | Common 'base' and 'stats' methods for 'rle' objects, aiming to make it possible to treat them transparently as vectors. |
| Authors: | Pavel N. Krivitsky [aut, cre] (ORCID: <https://orcid.org/0000-0002-9101-3362>) |
| Maintainer: | Pavel N. Krivitsky <[email protected]> |
| License: | GPL-3 |
| Version: | 0.10.0 |
| Built: | 2026-05-21 10:54:40 UTC |
| Source: | https://github.com/statnet/rle |
Common base and stats
methods for rle objects, aiming to make it possible to treat
them transparently as vectors.
This package grew out of the needs of the ergm package for a
run-length encoded representation of extremely long vectors with a
small number of contiguous runs, and these functions were originally
implemented in the statnet.common package.
It has been split out into its own package to enable others to use this functionality without installing any unnecessary dependencies and to facilitate contributions under a simplified license.
The long-run aim of this package is to make it possible to treat
rle objects transparently as unnamed vectors. As of this
writing, the biggest unimplemented feature are:
It is possible to use the indexing ([ and [[) operators to
extract by positive numeric indices but not by logical or
negative numeric indices, and the implementation is far from
optimal. It is not possible to replace individual elements of the
vector represented by an rle object. See Extract.rle for more
details.
Method rep.rle currently has limited functionality.
Maintainer: Pavel N. Krivitsky [email protected] (ORCID)
Useful links:
Report bugs at https://github.com/statnet/rle/issues
rle if not already an rle objectCoerce to rle if not already an rle object
as.rle(x) ## S3 method for class 'rle' as.rle(x) ## Default S3 method: as.rle(x)as.rle(x) ## S3 method for class 'rle' as.rle(x) ## Default S3 method: as.rle(x)
x |
the object to be coerced. |
A generic function for compressing a data structure.
compress(x, ...)compress(x, ...)
x |
the object to be compressed. |
... |
additional arguments to methods. |
rle object by merging adjacent runsCompress the rle object by merging adjacent runs
## S3 method for class 'rle' compress(x, ...)## S3 method for class 'rle' compress(x, ...)
x |
an |
... |
additional objects; if given, all arguments are concatenated. |
Since rle stores run lengths as integers, compress.rle
will not merge runs that add up to lengths greater than what can
be represented by a 32-bit signed integer
(2147483647).
x <- rle(as.logical(rbinom(10,1,.7))) y <- rle(as.logical(rbinom(10,1,.3))) stopifnot(identical(rle(inverse.rle(x)&inverse.rle(y)),compress(x&y))) big <- structure(list(lengths=as.integer(rep(.Machine$integer.max/4,6)), values=rep(TRUE,6)), class="rle") stopifnot(all(aggregate(as.numeric(lengths)~values, data=as.data.frame(unclass(big)),FUN=sum) == aggregate(as.numeric(lengths)~values, data=as.data.frame(unclass(compress(big))), FUN=sum)))x <- rle(as.logical(rbinom(10,1,.7))) y <- rle(as.logical(rbinom(10,1,.3))) stopifnot(identical(rle(inverse.rle(x)&inverse.rle(y)),compress(x&y))) big <- structure(list(lengths=as.integer(rep(.Machine$integer.max/4,6)), values=rep(TRUE,6)), class="rle") stopifnot(all(aggregate(as.numeric(lengths)~values, data=as.data.frame(unclass(big)),FUN=sum) == aggregate(as.numeric(lengths)~values, data=as.data.frame(unclass(compress(big))), FUN=sum)))
rle ObjectsThese methods provide indexing functionality for
rle objects on the scale of the original scale (the elements
of the vector that was compressed) where possible.
## S3 method for class 'rle' x[i, ..., unclass = getOption("rle.unclass_index") %||% FALSE] ## S3 replacement method for class 'rle' x[i, ..., unclass = getOption("rle.unclass_index") %||% FALSE] <- value ## S3 method for class 'rle' x[[i, ..., unclass = getOption("rle.unclass_index") %||% FALSE]] ## S3 replacement method for class 'rle' x[[i, ..., unclass = getOption("rle.unclass_index") %||% FALSE]] <- value ## S3 method for class 'rle' x$name ## S3 replacement method for class 'rle' x$name <- value## S3 method for class 'rle' x[i, ..., unclass = getOption("rle.unclass_index") %||% FALSE] ## S3 replacement method for class 'rle' x[i, ..., unclass = getOption("rle.unclass_index") %||% FALSE] <- value ## S3 method for class 'rle' x[[i, ..., unclass = getOption("rle.unclass_index") %||% FALSE]] ## S3 replacement method for class 'rle' x[[i, ..., unclass = getOption("rle.unclass_index") %||% FALSE]] <- value ## S3 method for class 'rle' x$name ## S3 replacement method for class 'rle' x$name <- value
x, i, name, value, ...
|
Arguments to indexing operators. See Extract documentation in the base package. |
unclass |
Logical: whether to process the arguments as if for
an ordinary list; default other than |
At this time, the rle following form of indexing are supported:
| operation | index | effect |
[ |
numeric >= 0 |
as vector |
[ |
numeric < 0 |
no |
[ |
logical |
no |
[ |
character |
on rle |
[<- |
numeric >= 0 |
no |
[<- |
numeric < 0 |
no |
[<- |
logical |
no |
[<- |
character |
on rle |
[[ |
numeric |
as vector |
[[<- |
numeric |
no |
[[ |
character |
on rle |
[[<- |
character |
on rle |
$ |
character |
on rle |
$<- |
character |
on rle
|
Generally, character indexes will access the underlying elements of
the rle object, $lengths and $values.
For character indices, the corresponding sublists or
elements of the rle object; for numeric indices, for [[ the
element at the specified position and for [ an rle containing the
elements at the specified position(s).
Some of these methods and inputs produce an error in
order to future-proof code that depends on the rle package by
preventing their use.
# Indexing by character or by $ works, including sub-indexing. x <- rle(1:5) x[["values"]] <- 2:6 x x$values[2:3] <- 7:8 x # From example(rle): z <- c(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE) rle(z) rle(z)[3:5] # Extract a sub-rle rle(z)[[4]] # Extract an element stopifnot(identical(inverse.rle(rle(z)[3:5]), z[3:5])) # Fractional: stopifnot(identical(inverse.rle(rle(z)[3.5]), z[3.5])) # Zero: stopifnot(identical(inverse.rle(rle(z)[0]), z[0])) # Out of range: stopifnot(identical(inverse.rle(rle(z)[20]), z[20])) # A mix: strange <- c(20, 3:5, 0, NA, 1:2) stopifnot(identical(inverse.rle(rle(z)[strange]), z[strange]))# Indexing by character or by $ works, including sub-indexing. x <- rle(1:5) x[["values"]] <- 2:6 x x$values[2:3] <- 7:8 x # From example(rle): z <- c(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE) rle(z) rle(z)[3:5] # Extract a sub-rle rle(z)[[4]] # Extract an element stopifnot(identical(inverse.rle(rle(z)[3:5]), z[3:5])) # Fractional: stopifnot(identical(inverse.rle(rle(z)[3.5]), z[3.5])) # Zero: stopifnot(identical(inverse.rle(rle(z)[0]), z[0])) # Out of range: stopifnot(identical(inverse.rle(rle(z)[20]), z[20])) # A mix: strange <- c(20, 3:5, 0, NA, 1:2) stopifnot(identical(inverse.rle(rle(z)[strange]), z[strange]))
rle to its runMap an element in a vector represented by an rle to its run
index_to_run(x, i, ...) ## S3 method for class 'rle' index_to_run(x, i, ...)index_to_run(x, i, ...) ## S3 method for class 'rle' index_to_run(x, i, ...)
x |
an |
i |
a numeric vector of indices to map; fractional values are rounded down. |
... |
additional arguments to methods. |
An integer vector. Negative values of i and 0 are always
mapped to 0. Indexes above the range represented by x are
mapped to the number of runs + 1.
This function is generic for future-proofing.
# From example(rle): z <- c(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE) rle(z) stopifnot(identical( index_to_run(rle(z), (-1):10), c(0L, 0L, 1L, 1L, 2L, 2L, 3L, 4L, 5L, 5L, 5L, 6L) ))# From example(rle): z <- c(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE) rle(z) stopifnot(identical( index_to_run(rle(z), (-1):10), c(0L, 0L, 1L, 1L, 2L, 2L, 3L, 4L, 5L, 5L, 5L, 6L) ))
rle ObjectsMathematical functions that work independently elementwise on vectors described in Math are implemented for rle objects. See Details for list of exceptions.
## S3 method for class 'rle' Math(x, ...)## S3 method for class 'rle' Math(x, ...)
x |
An |
... |
Additional arguments. |
Supported functions include all elements of the S3 Math
group excluding the "cumulative" ones, which are not supported at
this time and will raise an error. As of this writing, functions
supported include (from R help) abs, sign, sqrt, floor,
ceiling, trunc, round, signif, exp, log, expm1,
log1p, cos, sin, tan, cospi, sinpi, tanpi, acos,
asin, atan, cosh, sinh, tanh, acosh, asinh,
atanh, lgamma, gamma, digamma, and trigamma.
Functions cumsum, cumprod, cummax, and cummin are not
supported at this time and will raise an error.
In every supported case, the call should result in an
rle that would have resulted had the call been applied to the
original (uncompressed) vector, then compressed using
rle. (At no point in the calculation is the uncompressed
vector actually constructed, of course.)
By default, the functions do not merge adjacent
runs with the same value. This must be done explicitly with
compress.rle.
x <- rle(sample(runif(2), 10, c(.7,.3), replace=TRUE)) stopifnot(isTRUE(all.equal(sin(inverse.rle(x)),inverse.rle(sin(x))))) stopifnot(inherits(try(cumprod(x)), "try-error"))x <- rle(sample(runif(2), 10, c(.7,.3), replace=TRUE)) stopifnot(isTRUE(all.equal(sin(inverse.rle(x)),inverse.rle(sin(x))))) stopifnot(inherits(try(cumprod(x)), "try-error"))
rle ObjectsUnary and binary Arithmetic and Logic operators (with
exceptions given below) are implemented between two rle objects
and between an rle object and a scalar.
## S3 method for class 'rle' Ops(e1, e2)## S3 method for class 'rle' Ops(e1, e2)
e1, e2
|
Arguments to unary ( |
Supported operations include all elements of the Ops
group, as well as xor. Within the Arithmetic and Logic
operators, this includes (taken from the R help): +, -, *,
/, ^, < , >, <=, >=, !=, ==, %%, %/%, &,
|, !, and xor; but excludes non-vector logical functions
and operators such as isTRUE and &&.
In every supported case, the operation should result in an
rle that would have resulted had the operation been applied
to the original (uncompressed) vectors, then compressed using
rle, with the proviso that if the resulting function creates
adjacent runs of the same value, they are not merged. This must
be done explicitly with compress.rle. (At no point in the
calculation are the uncompressed vectors actually constructed, of
course.)
An operation between an rle and a zero-length object produces
an empty rle.
x <- rle(as.logical(rbinom(10,1,.7))) y <- rle(as.logical(rbinom(10,1,.3))) stopifnot(isTRUE(all.equal((!inverse.rle(x)),inverse.rle(!x)))) stopifnot(isTRUE(all.equal((inverse.rle(x)|inverse.rle(y)),inverse.rle(x|y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)&inverse.rle(y)),inverse.rle(x&y)))) x <- rle(sample(c(-1,+1), 10, c(.7,.3), replace=TRUE)) y <- rle(sample(c(-1,+1), 10, c(.3,.7), replace=TRUE)) stopifnot(isTRUE(all.equal((inverse.rle(x)*inverse.rle(y)),inverse.rle(x*y)))) stopifnot(isTRUE(all.equal((2*inverse.rle(y)),inverse.rle(2*y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)*2),inverse.rle(x*2)))) stopifnot(isTRUE(all.equal((inverse.rle(x)/inverse.rle(y)),inverse.rle(x/y)))) stopifnot(isTRUE(all.equal((2/inverse.rle(y)),inverse.rle(2/y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)/2),inverse.rle(x/2)))) stopifnot(isTRUE(all.equal((-inverse.rle(y)),inverse.rle(-y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)-inverse.rle(y)),inverse.rle(x-y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)%/%inverse.rle(y)),inverse.rle(x%/%y)))) stopifnot(isTRUE(all.equal(inverse.rle(x)==inverse.rle(y),inverse.rle(x==y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)>inverse.rle(y)),inverse.rle(x>y))))x <- rle(as.logical(rbinom(10,1,.7))) y <- rle(as.logical(rbinom(10,1,.3))) stopifnot(isTRUE(all.equal((!inverse.rle(x)),inverse.rle(!x)))) stopifnot(isTRUE(all.equal((inverse.rle(x)|inverse.rle(y)),inverse.rle(x|y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)&inverse.rle(y)),inverse.rle(x&y)))) x <- rle(sample(c(-1,+1), 10, c(.7,.3), replace=TRUE)) y <- rle(sample(c(-1,+1), 10, c(.3,.7), replace=TRUE)) stopifnot(isTRUE(all.equal((inverse.rle(x)*inverse.rle(y)),inverse.rle(x*y)))) stopifnot(isTRUE(all.equal((2*inverse.rle(y)),inverse.rle(2*y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)*2),inverse.rle(x*2)))) stopifnot(isTRUE(all.equal((inverse.rle(x)/inverse.rle(y)),inverse.rle(x/y)))) stopifnot(isTRUE(all.equal((2/inverse.rle(y)),inverse.rle(2/y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)/2),inverse.rle(x/2)))) stopifnot(isTRUE(all.equal((-inverse.rle(y)),inverse.rle(-y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)-inverse.rle(y)),inverse.rle(x-y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)%/%inverse.rle(y)),inverse.rle(x%/%y)))) stopifnot(isTRUE(all.equal(inverse.rle(x)==inverse.rle(y),inverse.rle(x==y)))) stopifnot(isTRUE(all.equal((inverse.rle(x)>inverse.rle(y)),inverse.rle(x>y))))
rep method for rle objects## S3 method for class 'rle' rep( x, ..., scale = c("element", "run"), doNotCompact = FALSE, doNotCompress = doNotCompact )## S3 method for class 'rle' rep( x, ..., scale = c("element", "run"), doNotCompact = FALSE, doNotCompress = doNotCompact )
x |
an |
... |
see documentation for |
scale |
whether to replicate the elements of the RLE-compressed vector or the runs. |
doNotCompress, doNotCompact
|
whether the method should call
|
The rep method for rle objects is very limited at
this time. Even though the default setting is to replicate
elements of the vector, only the run-replicating functionality is
implemented at this time except for the simplest case (scalar
times argument).
x <- rle(sample(c(-1,+1), 10, c(.7,.3), replace=TRUE)) y <- rpois(length(x$lengths), 2) stopifnot(isTRUE(all.equal(rep(inverse.rle(x), rep(y, x$lengths)), inverse.rle(rep(x, y, scale="run"))))) stopifnot(isTRUE(all.equal(rep(inverse.rle(x), max(y)), inverse.rle(rep(x, max(y), scale="element")))))x <- rle(sample(c(-1,+1), 10, c(.7,.3), replace=TRUE)) y <- rpois(length(x$lengths), 2) stopifnot(isTRUE(all.equal(rep(inverse.rle(x), rep(y, x$lengths)), inverse.rle(rep(x, y, scale="run"))))) stopifnot(isTRUE(all.equal(rep(inverse.rle(x), max(y)), inverse.rle(rep(x, max(y), scale="element")))))
rle ObjectsMiscellaneous Common Methods for rle Objects
## S3 method for class 'rle' c(...) ## S3 method for class 'rle' mean(x, na.rm = FALSE, ...) ## S3 method for class 'rle' length(x) ## S3 method for class 'rle' is.na(x) ## S3 method for class 'rle' str(object, ...)## S3 method for class 'rle' c(...) ## S3 method for class 'rle' mean(x, na.rm = FALSE, ...) ## S3 method for class 'rle' length(x) ## S3 method for class 'rle' is.na(x) ## S3 method for class 'rle' str(object, ...)
... |
For |
x, object
|
An |
na.rm |
Whether missing values are to be ignored ( |
The length method returns the length of the vector
represented by the object, obtained by summing the lengths of
individual runs. This can be overridden by setting
options(rle.unclass_index = FALSE), which causes it to
return the length of the underlying representation (usually 2) instead.
x <- rle(as.logical(rbinom(10,1,.7))) y <- rle(as.logical(rbinom(10,1,.3))) stopifnot(isTRUE(all.equal(c(inverse.rle(x),inverse.rle(y)),inverse.rle(c(x,y))))) stopifnot(isTRUE(all.equal(mean(inverse.rle(x)),mean(x)))) stopifnot(isTRUE(all.equal(mean(inverse.rle(y)),mean(y)))) stopifnot(isTRUE(all.equal(length(inverse.rle(x)),length(x)))) stopifnot(isTRUE(all.equal(length(inverse.rle(y)),length(y)))) x$values[1] <- NA y$values[1] <- NA stopifnot(isTRUE(all.equal(is.na(inverse.rle(x)),inverse.rle(is.na(x))))) stopifnot(isTRUE(all.equal(is.na(inverse.rle(y)),inverse.rle(is.na(y))))) str(x)x <- rle(as.logical(rbinom(10,1,.7))) y <- rle(as.logical(rbinom(10,1,.3))) stopifnot(isTRUE(all.equal(c(inverse.rle(x),inverse.rle(y)),inverse.rle(c(x,y))))) stopifnot(isTRUE(all.equal(mean(inverse.rle(x)),mean(x)))) stopifnot(isTRUE(all.equal(mean(inverse.rle(y)),mean(y)))) stopifnot(isTRUE(all.equal(length(inverse.rle(x)),length(x)))) stopifnot(isTRUE(all.equal(length(inverse.rle(y)),length(y)))) x$values[1] <- NA y$values[1] <- NA stopifnot(isTRUE(all.equal(is.na(inverse.rle(x)),inverse.rle(is.na(x))))) stopifnot(isTRUE(all.equal(is.na(inverse.rle(y)),inverse.rle(is.na(y))))) str(x)
rle objects.Summarisation functions for vectors described in Summary are implemented for rle objects.
## S3 method for class 'rle' Summary(..., na.rm)## S3 method for class 'rle' Summary(..., na.rm)
... |
|
na.rm |
Whether the missing values should be ignored ( |
Supported functions include all elements of the S3
Summary group. As of this writing, functions supported include
(from R help) all, any, max, min, prod, range, and
sum.
In every supported case, the call should produce the same
result as what would have resulted had the call been applied to
the original (uncompressed) vector. (At no point in the
calculation is the uncompressed vector actually constructed, of
course.) The exception is that if values are of class
integer, the result will nonetheless always be upcast to
numeric to avert overflows. This behaviour may change in the
future.
x <- rle(as.logical(rbinom(20,1,.7))) y <- rle(as.logical(rbinom(20,1,.3))) stopifnot(isTRUE(all.equal(any(x, y),any(inverse.rle(x), inverse.rle(y))))) stopifnot(isTRUE(all.equal(any(y),any(inverse.rle(y))))) stopifnot(isTRUE(all.equal(sum(inverse.rle(x),inverse.rle(y)),sum(x,y)))) stopifnot(isTRUE(all.equal(sum(inverse.rle(y)),sum(y)))) y$values[2:3] <- NA stopifnot(isTRUE(all.equal(sum(inverse.rle(y), na.rm=TRUE),sum(y, na.rm=TRUE)))) stopifnot(isTRUE(all.equal(sum(inverse.rle(y), na.rm=FALSE),sum(y, na.rm=FALSE))))x <- rle(as.logical(rbinom(20,1,.7))) y <- rle(as.logical(rbinom(20,1,.3))) stopifnot(isTRUE(all.equal(any(x, y),any(inverse.rle(x), inverse.rle(y))))) stopifnot(isTRUE(all.equal(any(y),any(inverse.rle(y))))) stopifnot(isTRUE(all.equal(sum(inverse.rle(x),inverse.rle(y)),sum(x,y)))) stopifnot(isTRUE(all.equal(sum(inverse.rle(y)),sum(y)))) y$values[2:3] <- NA stopifnot(isTRUE(all.equal(sum(inverse.rle(y), na.rm=TRUE),sum(y, na.rm=TRUE)))) stopifnot(isTRUE(all.equal(sum(inverse.rle(y), na.rm=FALSE),sum(y, na.rm=FALSE))))