├── .Rbuildignore
├── .gitignore
├── DESCRIPTION
├── LICENSE.md
├── NAMESPACE
├── NEWS.md
├── R
├── bind.R
├── dim.R
├── dim2.R
├── dimnames.R
├── extract.R
├── map.R
├── modify.R
├── onehot.R
├── reshape.R
├── seq_along.R
├── shuffle.R
├── split.R
├── standardize.R
├── utils.R
└── zzz.R
├── README.Rmd
├── README.md
├── _pkgdown.yml
├── cran-comments.md
├── docs
├── 404.html
├── LICENSE.html
├── authors.html
├── bootstrap-toc.css
├── bootstrap-toc.js
├── docsearch.css
├── docsearch.js
├── extra.css
├── index.html
├── link.svg
├── pkgdown.css
├── pkgdown.js
├── pkgdown.yml
└── reference
│ ├── DIM.html
│ ├── array2.html
│ ├── bind-arrays.html
│ ├── drop_dimnames.html
│ ├── expand_dims.html
│ ├── extract_dim.html
│ ├── index.html
│ ├── map_along_dim.html
│ ├── modify_along_dim.html
│ ├── ndim.html
│ ├── onehot.html
│ ├── seq_along_dim.html
│ ├── set_as_rows.html
│ ├── set_dim.html
│ ├── set_dimnames.html
│ ├── shuffle_rows.html
│ ├── split-array.html
│ └── t.array.html
├── listarrays.Rproj
├── man
├── DIM.Rd
├── array2.Rd
├── bind-arrays.Rd
├── drop_dimnames.Rd
├── expand_dims.Rd
├── extract_dim.Rd
├── map_along_dim.Rd
├── modify_along_dim.Rd
├── ndim.Rd
├── onehot.Rd
├── seq_along_dim.Rd
├── set_as_rows.Rd
├── set_dim.Rd
├── set_dimnames.Rd
├── shuffle_rows.Rd
└── split-array.Rd
├── pkgdown
└── extra.css
└── tests
├── testthat.R
└── testthat
├── test-bind.R
├── test-dimnames.R
├── test-map.R
├── test-modify.R
├── test-onehot.R
├── test-shuffle.R
└── test-split.R
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^.*\.Rproj$
2 | ^\.Rproj\.user$
3 | ^README\.Rmd$
4 | ^LICENSE\.md$
5 | ^docs$
6 | ^pkgdown$
7 | ^_
8 | ^_pkgdown\.yml$
9 | ^CRAN-SUBMISSION$
10 | ^cran-comments\.md$
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .RData
4 | .Ruserdata
5 | R/_*.R
6 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: listarrays
2 | Type: Package
3 | Title: A Toolbox for Working with R Arrays in a Functional Programming Style
4 | Version: 0.4.0
5 | Authors@R: person("Tomasz", "Kalinowski", email = "kalinowskit@gmail.com",
6 | role = c("aut", "cre"))
7 | Description: A toolbox for R arrays. Flexibly split, bind, reshape, modify,
8 | subset and name arrays.
9 | URL: https://github.com/t-kalinowski/listarrays, https://t-kalinowski.github.io/listarrays/
10 | BugReports: https://github.com/t-kalinowski/listarrays/issues
11 | License: GPL-3
12 | Encoding: UTF-8
13 | LazyData: true
14 | ByteCompile: true
15 | RoxygenNote: 7.3.1
16 | Roxygen: list(markdown = TRUE)
17 | Suggests:
18 | testthat, magrittr, zeallot, rlang, tibble, purrr
19 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | export("dim2<-")
4 | export(DIM)
5 | export(DROP)
6 | export(array2)
7 | export(bind_as_cols)
8 | export(bind_as_dim)
9 | export(bind_as_rows)
10 | export(bind_on_cols)
11 | export(bind_on_dim)
12 | export(bind_on_rows)
13 | export(decode_onehot)
14 | export(drop_dim)
15 | export(drop_dim2)
16 | export(drop_dimnames)
17 | export(expand_dims)
18 | export(extract_cols)
19 | export(extract_dim)
20 | export(extract_rows)
21 | export(map_along_cols)
22 | export(map_along_dim)
23 | export(map_along_rows)
24 | export(matrix2)
25 | export(modify_along_cols)
26 | export(modify_along_dim)
27 | export(modify_along_rows)
28 | export(ndim)
29 | export(onehot)
30 | export(onehot_decoder)
31 | export(onehot_with_decoder)
32 | export(seq_along_cols)
33 | export(seq_along_dim)
34 | export(seq_along_rows)
35 | export(set_as_cols)
36 | export(set_as_rows)
37 | export(set_dim)
38 | export(set_dim2)
39 | export(set_dimnames)
40 | export(shuffle_rows)
41 | export(split_along_cols)
42 | export(split_along_dim)
43 | export(split_along_rows)
44 | export(split_on_cols)
45 | export(split_on_dim)
46 | export(split_on_rows)
47 | importFrom(compiler,cmpfun)
48 | importFrom(utils,modifyList)
49 |
--------------------------------------------------------------------------------
/NEWS.md:
--------------------------------------------------------------------------------
1 | # listarrays 0.4.0
2 |
3 | * Removed `t.arrray()` S3 method
4 | * Added a `NEWS.md` file to track changes to the package.
5 |
--------------------------------------------------------------------------------
/R/bind.R:
--------------------------------------------------------------------------------
1 | #' Bind arrays along a specified dimension
2 | #'
3 | #' `bind_as_*` introduces a new dimension, such that each element in
4 | #' `list_of_arrays` corresponds to one index position along the new dimension in
5 | #' the returned array. `bind_on_*` binds all elements along an existing
6 | #' dimension, (meaning, the returned array has the same number of dimensions as
7 | #' each of the arrays in the list).
8 | #'
9 | #' `bind_*_rows()` is a wrapper for the common case of `bind_*_dim(X, 1)`.
10 | #' `bind_*_cols()` is a wrapper for the common case of `bind_*_dim(X, -1)`.
11 | #'
12 | #' @param list_of_arrays a list of arrays. All arrays must be of the same
13 | #' dimension. NULL's in place of arrays are automatically dropped.
14 | #' @param ... Arrays to be bound, specified individually or supplied as a single
15 | #' list
16 | #' @param which_dim Scalar integer specifying the index position of where to
17 | #' introduce the new dimension to introduce. Negative numbers count from the
18 | #' back. For example, given a 3 dimensional array, `-1`, is equivalent to `3`,
19 | #' `-2` to `2` and `-3` to `1`.
20 | #'
21 | #' @return An array, with one additional dimension.
22 | #' @rdname bind-arrays
23 | #' @export
24 | #'
25 | #' @examples
26 | #' list_of_arrays <- replicate(10, array(1:8, dim = c(2,3,4)), FALSE)
27 | #'
28 | #' dim(list_of_arrays[[1]])
29 | #'
30 | #' # bind on a new dimension
31 | #' combined_as <- bind_as_rows(list_of_arrays)
32 | #' dim(combined_as)
33 | #' dim(combined_as)[1] == length(list_of_arrays)
34 | #'
35 | #' # each element in `list_of_arrays` corresponds to one "row"
36 | #' # (i.e., one entry in along the first dimension)
37 | #' for(i in seq_along(list_of_arrays))
38 | #' stopifnot(identical(combined_as[i,,,], list_of_arrays[[i]]))
39 | #'
40 | #' # bind on an existing dimension
41 | #' combined_on <- bind_on_rows(list_of_arrays)
42 | #' dim(combined_on)
43 | #' dim(combined_on)[1] == sum(sapply(list_of_arrays, function(x) dim(x)[1]))
44 | #' identical(list_of_arrays[[1]], combined_on[1:2,,])
45 | #' for (i in seq_along(list_of_arrays))
46 | #' stopifnot(identical(
47 | #' list_of_arrays[[i]], combined_on[ (1:2) + (i-1)*2,,]
48 | #' ))
49 | #'
50 | #' # bind on any dimension
51 | #' combined <- bind_as_dim(list_of_arrays, 3)
52 | #' dim(combined)
53 | #' for(i in seq_along(list_of_arrays))
54 | #' stopifnot(identical(combined[,,i,], list_of_arrays[[i]]))
55 | bind_as_dim <- function(list_of_arrays, which_dim) {
56 |
57 | # standardize_which_dim(which_dim, n_dim = )
58 | check.is.integerish(which_dim, 1L)
59 | new_axis_nm <- names(which_dim)
60 | which_dim <- as.integer(which_dim)
61 |
62 | stopifnot(is.list(list_of_arrays))
63 | list_of_arrays <- dropNULLs(list_of_arrays)
64 |
65 | base_dim <- unique(lapply(list_of_arrays, function(x) dim(x) %||% length(x)))
66 | stopifnot(is.scalar(base_dim))
67 | base_dim <- base_dim[[1]]
68 |
69 | if(is.negative(which_dim))
70 | which_dim <- which_dim + length(base_dim) + 2L
71 |
72 | X <- simplify2array(list_of_arrays)
73 | rank <- length(base_dim)
74 | if (which_dim != rank + 1L) {
75 | perm <- append(seq_len(rank), rank + 1L, after = which_dim - 1L)
76 | X <- aperm(X, perm)
77 | }
78 |
79 | if(!is.null(new_axis_nm))
80 | names(dimnames(X))[which_dim] <- new_axis_nm
81 |
82 | X
83 | }
84 |
85 | #' @rdname bind-arrays
86 | #' @export
87 | bind_as_rows <- function(...) {
88 | list_of_arrays <- list(...)
89 | if (identical(nargs(), 1L))
90 | list_of_arrays <- list_of_arrays[[1]]
91 | bind_as_dim(list_of_arrays, which_dim = 1L)
92 | }
93 |
94 | #' @rdname bind-arrays
95 | #' @export
96 | bind_as_cols <- function(...) {
97 | list_of_arrays <- list(...)
98 | if (identical(nargs(), 1L))
99 | list_of_arrays <- list_of_arrays[[1]]
100 | bind_as_dim(list_of_arrays, which_dim = -1L)
101 | }
102 |
103 |
104 |
105 |
106 |
107 |
108 | BIND_ON_FN_TEMPLATE <-
109 | alist(list_of_arrays = , n_entries_per_array = , new_dim = , {
110 | X <- array(vector(typeof(list_of_arrays[[1L]])), dim = new_dim)
111 | start <- 1L
112 | for (i in seq_along(list_of_arrays)) {
113 | end <- start + n_entries_per_array[[i]] - 1L
114 | EXTRACT_CALL <- list_of_arrays[[i]]
115 | start <- end + 1L
116 | }
117 | X
118 | })
119 |
120 | minimal_bind_on_env <-
121 | list2env(mget(
122 | c(
123 | "array",
124 | "vector",
125 | "typeof",
126 | "seq_along",
127 | "<-",
128 | "+",
129 | "-",
130 | "[[",
131 | "[<-",
132 | ":", "{", "for"
133 | ),
134 | envir = baseenv()
135 | ))
136 |
137 |
138 | new_bind_on_fn <- function(extract_call) {
139 | BIND_ON_FN_TEMPLATE[[c(4L, 4L, 4L, 3L, 2L)]] <- extract_call
140 | as.function.default(BIND_ON_FN_TEMPLATE, envir = minimal_bind_on_env)
141 | }
142 |
143 | #' @rdname bind-arrays
144 | #' @export
145 | bind_on_dim <- function(list_of_arrays, which_dim) {
146 |
147 | stopifnot(is.list(list_of_arrays))
148 | list_of_arrays <- dropNULLs(list_of_arrays)
149 |
150 | all_dims <- lapply(list_of_arrays, function(x) dim(x) %||% length(x))
151 | all_n_dims <- lengths(all_dims) #lapply(all_dims, length)
152 | stopifnot(is.scalar(unique(all_n_dims)))
153 | n_dim <- all_n_dims[[1]]
154 |
155 | which_dim <- standardize_which_dim(which_dim,
156 | names_dimnames_X = {
157 | all_axis_names <- lapply(list_of_arrays, function(x) names(dimnames(x)))
158 | stopifnot(length(unique(all_axis_names)) == 1L)
159 | all_axis_names[[1]]
160 | }, n_dim = n_dim)
161 |
162 | base_dim <- unique(lapply(all_dims, function(d)
163 | d[-which_dim]))
164 | stopifnot(identical(length(base_dim), 1L))
165 | base_dim <- base_dim[[1]]
166 |
167 | n_entries_per_array <- quick_cbind(all_dims)[which_dim,]
168 |
169 | new_dim <- all_dims[[1]]
170 | new_dim[which_dim] <- sum(n_entries_per_array)
171 |
172 | X_start_to_end <- extract_dim_expr(
173 | var_to_subset = quote(X), idx_var_sym = quote(start:end),
174 | which_dim = which_dim, ndims = length(new_dim))
175 |
176 | bind_it <- new_bind_on_fn(X_start_to_end)
177 |
178 | if(length(list_of_arrays) > 100)
179 | bind_it <- cmpfun(bind_it)
180 |
181 | X <- bind_it(list_of_arrays, n_entries_per_array, new_dim)
182 |
183 | if (!is.null(names(list_of_arrays)))
184 | dimnames(X)[[which_dim]] <-
185 | rep(names(list_of_arrays), times = n_entries_per_array)
186 |
187 | X
188 | }
189 |
190 | #' @rdname bind-arrays
191 | #' @export
192 | bind_on_rows <- function(...) {
193 | list_of_arrays <- list(...)
194 | if (identical(length(list_of_arrays), 1L))
195 | list_of_arrays <- list_of_arrays[[1]]
196 |
197 | bind_on_dim(list_of_arrays, which_dim = 1L)
198 | }
199 |
200 | #' @rdname bind-arrays
201 | #' @export
202 | bind_on_cols <- function(...) {
203 | list_of_arrays <- list(...)
204 | if (identical(length(list_of_arrays), 1L))
205 | list_of_arrays <- list_of_arrays[[1]]
206 |
207 | bind_on_dim(list_of_arrays, which_dim = -1L)
208 | }
209 |
--------------------------------------------------------------------------------
/R/dim.R:
--------------------------------------------------------------------------------
1 | #' Reshape an array
2 | #'
3 | #' Pipe friendly `dim<-()`, with option to pad to necessary length. Also allows
4 | #' for filling the array using C style row-major semantics.
5 | #'
6 | #' @param x A vector or array to set dimensions on
7 | #' @param new_dim The desired dimensions (an integer(ish) vector)
8 | #' @param pad The value to pad the vector with. `NULL` (the default) performs no
9 | #' padding.
10 | #' @param order whether to use row-major (C) or column major (F) style
11 | #' semantics. The default, "F", corresponds to the default behavior of R's
12 | #' `dim<-()`, while "C" corresponds to the default behavior of
13 | #' `reticulate::array_reshape()`, numpy, reshaping semantics commonly
14 | #' encountered in the python world.
15 | #' @param verbose Whether to emit a message if padding. By default, `FALSE`.
16 | #'
17 | #'
18 | #' @return Object with dimensions set
19 | #' @export
20 | #' @rdname set_dim
21 | #'
22 | #' @seealso `set_dim2()`, \code{`dim<-`()}, `reticulate::array_reshape()`
23 | #'
24 | #' @examples
25 | #' set_dim(1:10, c(2, 5))
26 | #' try( set_dim(1:7, c(2, 5)) ) # error by default, just like `dim<-`()
27 | #' set_dim(1:7, c(2, 5), pad = 99)
28 | #' set_dim(1:7, c(2, 5), pad = 99, order = "C") # fills row-wise
29 | #'
30 | #' y <- x <- 1:4
31 | #' # base::dim<- fills the array column wise
32 | #' dim(x) <- c(2, 2)
33 | #' x
34 | #'
35 | #' # dim2 will fill the array row-wise
36 | #' dim2(y) <- c(2, 2)
37 | #' y
38 | #'
39 | #' identical(x, set_dim(1:4, c(2,2)))
40 | #' identical(y, set_dim(1:4, c(2,2), order = "C"))
41 | #'
42 | #' \dontrun{
43 | #' py_reshaped <- reticulate::array_reshape(1:4, c(2,2))
44 | #' storage.mode(py_reshaped) <- "integer" # reticulate coerces to double
45 | #' identical(y, py_reshaped)
46 | #' # if needed, see listarrays:::array_reshape() for
47 | #' # a drop-in pure R replacement for reticulate::array_reshape()
48 | #' }
49 | set_dim <- function(x, new_dim,
50 | pad = getOption("listarrays.autopad_arrays_with", NULL),
51 | order = c("F", "C"),
52 | verbose = getOption("verbose")) {
53 |
54 | if (!is.null(pad) && !identical(length(x), needed_len <- prod(new_dim))) {
55 | stopifnot(identical(length(pad), 1L))
56 | if (verbose)
57 | message("Padding vector with ", pad, "s",
58 | " from length ", length(x), " to length ", needed_len)
59 | x <- c(x, rep_len(pad, needed_len - length(x)))
60 | }
61 |
62 | order <- match.arg(order)
63 | if (identical(order, "C"))
64 | dim2(x) <- new_dim
65 | else
66 | dim(x) <- new_dim
67 |
68 | x
69 | }
70 |
71 |
72 |
73 | #' Expand the shape of an array
74 | #'
75 | #' This is the inverse operation of `base::drop()`.
76 | #' It is analogous to python's `numpy.expand_dims()`, but vectorized on
77 | #' `which_dim`.
78 | #'
79 | #' @param x an array. Bare vectors are treated as 1-d arrays.
80 | #' @param which_dim numeric. Desired index position of the new axis or axes in
81 | #' the returned array. Negative numbers count from the back. Can be any
82 | #' length.Throws a warning if any duplicates are provided.
83 | #'
84 | #'
85 | #' @return the array `x` with new dim
86 | #' @export
87 | #'
88 | #' @examples
89 | #' x <- array(1:24, 2:4)
90 | #' dim(x)
91 | #' dim(expand_dims(x))
92 | #' dim(expand_dims(x, 2))
93 | #' dim(expand_dims(x, c(1,2)))
94 | #' dim(expand_dims(x, c(1,-1)))
95 | #' dim(expand_dims(x, 6)) # implicitly also expands dims 4,5
96 | #' dim(expand_dims(x, 4:6))
97 | #'
98 | #' # error, implicit expansion with negative indexes not supported
99 | #' try(expand_dims(x, -6))
100 | #'
101 | #' # supply them explicitly instead
102 | #' dim(expand_dims(x, -(4:6)))
103 | expand_dims <- function(x, which_dim = -1L) {
104 | d <- DIM(x)
105 | nd <- length(d)
106 | nwd <- length(which_dim)
107 |
108 | stopifnot(is.integerish(which_dim))
109 | wd <- which_dim
110 | storage.mode(wd) <- "integer"
111 |
112 |
113 | neg <- wd < 0L
114 | if(any(neg))
115 | wd[neg] <- wd[neg] + nd + nwd + 1L
116 |
117 | if (min(wd) < 1L)
118 | stop("Implicit additional dims for expansion with negative indexes not supported")
119 |
120 | if ((max_wd <- max(wd)) > nd + nwd) {
121 | # implicitly pad on right
122 | wd <- unique(c(wd, (nd + 1L):max_wd))
123 | ndout <- max_wd
124 | } else
125 | ndout <- nd + nwd
126 |
127 |
128 | if(anyDuplicated(wd)) {
129 | warning("Duplicate axis specified, ignored")
130 | wd <- unique(wd)
131 | }
132 |
133 | dims <- rep(1L, ndout)
134 | dims[-wd] <- d
135 |
136 | dim(x) <- dims
137 | x
138 | }
139 |
--------------------------------------------------------------------------------
/R/dim2.R:
--------------------------------------------------------------------------------
1 | #' Make or reshape an array with C-style (row-major) semantics
2 | #'
3 | #' These functions reshape or make an array using C-style, row-major semantics.
4 | #' The returned array is still R's native F-style, (meaning, the underlying
5 | #' vector has been reordered).
6 | #'
7 | #' Other than the C-style semantics, these functions behave identically to their
8 | #' counterparts (`array2()` behaves identically to `array()`, \code{`dim2<-`()}
9 | #' to \code{`dim<-`()}). `set_dim2()` is just a wrapper around `set_dim(...,
10 | #' order = "C")`.
11 | #'
12 | #' See examples for a drop-in pure R replacement to `reticulate::array_reshape()`
13 | #'
14 | #' @param data what to fill the array with
15 | #' @param dim numeric vector of dimensions
16 | #' @param dimnames a list of dimnames, must be the same length as `dims`
17 | #'
18 | #' @export
19 | #' @examples
20 | #' array(1:4, c(2,2))
21 | #' array2(1:4, c(2,2))
22 | #'
23 | #' # for a drop-in replacement to reticulate::array_reshape
24 | #' array_reshape <- listarrays:::array_reshape
25 | #' array_reshape(1:4, c(2,2))
26 | array2 <- function(data, dim = length(data), dimnames = NULL) {
27 | pd <- prod(dim)
28 | if(length(data) != pd)
29 | data <- rep_len(data, pd)
30 | dim2(data) <- dim
31 | dimnames(data) <- dimnames
32 | data
33 | }
34 |
35 |
36 | #' @export
37 | #' @rdname array2
38 | matrix2 <- function(...)
39 | matrix(..., byrow = TRUE)
40 |
41 | #' @export
42 | #' @rdname array2
43 | #' @param x object to set dimensions on (array or atomic vector)
44 | #' @param value a numeric (integerish) vector of new dimensions
45 | `dim2<-` <- function(x, value) {
46 | if (is.null(value)) {
47 | if (is.null(dim(x) -> dx))
48 | return(x)
49 |
50 | if(length(dx) > 1L)
51 | x <- t(x)
52 |
53 | dim(x) <- NULL
54 |
55 | return(x)
56 | }
57 |
58 | dim_x <- dim(x)
59 | if(identical(dim_x, as.integer(value)))
60 | return(x)
61 |
62 | if (!is.null(dim_x))
63 | x <- t(x)
64 |
65 | dim(x) <- rev(value)
66 | t(x)
67 | }
68 |
69 |
70 | #' @export
71 | #' @rdname array2
72 | #' @param ... passed on to `set_dim()`
73 | set_dim2 <- function(...) {
74 | set_dim(..., order = "C")
75 | }
76 |
77 |
78 |
79 | # equivelant to reticulate::array_reshape(),
80 | # but a pure R solution (and therefore usually faster)
81 | array_reshape <- function(x, dim, order = c("C", "F")) {
82 |
83 | # rename to avoid possible recursive loop when calling dim()
84 | # arg is named `dim` for compatability with reticulate::array_reshape()
85 | new_dim <- dim; rm(dim)
86 |
87 | order <- match.arg(order)
88 | if (identical(order, "C"))
89 | dim2(x) <- new_dim
90 | else
91 | dim(x) <- new_dim
92 |
93 | # match reticulate behavior
94 | if(identical(storage.mode(x), "integer"))
95 | storage.mode(x) <- "double"
96 |
97 | x
98 | }
99 |
100 |
101 | #' transpose an array
102 | #'
103 | #' @param x an array
104 | #'
105 | #' This reverses the dimensions of an array
106 | #'
107 | #' #export
108 | #' @noRd
109 | #' @examples
110 | #' x <- array(1:27, c(3,3,3))
111 | #' tx <- t(x)
112 | #' for (i in 1:3)
113 | #' for(j in 1:3)
114 | #' stopifnot(x[,j,i] == tx[i,j,])
115 |
116 | # this is no longer exported because it is now invoked for 2d arrays (matrixes)
117 | # too, and before dispatch to the primitive. This introduces substantial
118 | # overhead in code that would otherwise not dispatch. Additionally, aperm() does
119 | # not preserve attributes. This was discovered when utils::getParseData() was
120 | # raising an error, because the expression `t(unclass(data))` was losing
121 | # attributes(data) if listarrays was loaded.
122 |
123 | # t.array <-
124 | function(x) {
125 | if(is.matrix(x)) return(NextMethod()) # copies attrs already
126 |
127 | # handle bug in aperm(), R 4.3.2. aperm() docs say it copies over other attrs,
128 | # but in actuality, it doesn't.
129 | out <- aperm(x)
130 | attrs <- attributes(x)
131 | attrs$dim <- attrs$dimnames <- NULL
132 | attributes(out) <- a
133 | out
134 | }
135 |
--------------------------------------------------------------------------------
/R/dimnames.R:
--------------------------------------------------------------------------------
1 | #' Set dimnames
2 | #'
3 | #' A more flexible and pipe-friendly version of `dimnames<-`.
4 | #'
5 | #' @param x an array
6 | #' @param nm A list or character vector.
7 | #' @param which_dim a character vector or numeric vector or `NULL`
8 | #'
9 | #' @details This function is quite flexible. See examples for the complete
10 | #' picture.
11 | #'
12 | #' @note The word "dimnames" is slightly overloaded. Most commonly it refers to
13 | #' the names of entries along a particular axis (e.g., date1, date2, date3,
14 | #' ...), but occasionally it is also used to refer to the names of the array
15 | #' axes themselves (e.g, dates, temperature, pressure, ...). To disambiguate,
16 | #' in the examples 'dimnames' always refers to the first case, while 'axis
17 | #' names' refers to the second. `set_dimnames()` can be used to set either or both
18 | #' axis names and dimnames.
19 | #'
20 | #' @return x, with modified dimnames and or axisnames
21 | #' @export
22 | #' @importFrom utils modifyList
23 | #'
24 | #' @examples
25 | #' x <- array(1:8, 2:4)
26 | #'
27 | #' # to set axis names, leave which_dim=NULL and pass a character vector
28 | #' dimnames(set_dimnames(x, c("a", "b", "c")))
29 | #'
30 | #' # to set names along a single axis, specify which_dim
31 | #' dimnames(set_dimnames(x, c("a", "b", "c"), 2))
32 | #'
33 | #' # to set an axis name and names along the axis, pass a named list
34 | #' dimnames(set_dimnames(x, list(axis2 = c("a", "b", "c")), 2))
35 | #' dimnames(set_dimnames(x, list(axis2 = c("a", "b", "c"),
36 | #' axis3 = 1:4), which_dim = 2:3))
37 | #'
38 | #' # if the array already has axis names, those are used when possible
39 | #' nx <- set_dimnames(x, paste0("axis", 1:3))
40 | #' dimnames(nx)
41 | #' dimnames(set_dimnames(nx, list(axis2 = c("x", "y", "z"))))
42 | #' dimnames(set_dimnames(nx, c("x", "y", "z"), which_dim = "axis2"))
43 | #'
44 | #'
45 | #' # pass NULL to drop all dimnames, or just names along a single dimension
46 | #' nx2 <- set_dimnames(nx, c("x", "y", "z"), which_dim = "axis2")
47 | #' nx2 <- set_dimnames(nx2, LETTERS[1:4], which_dim = "axis3")
48 | #' dimnames(nx2)
49 | #' dimnames(set_dimnames(nx2, NULL))
50 | #' dimnames(set_dimnames(nx2, NULL, 2))
51 | #' dimnames(set_dimnames(nx2, NULL, c(2, 3)))
52 | #' # to preserve an axis name and only drop the dimnames, wrap the NULL in a list()
53 | #' dimnames(set_dimnames(nx2, list(NULL)))
54 | #' dimnames(set_dimnames(nx2, list(NULL), 2))
55 | #' dimnames(set_dimnames(nx2, list(axis2 = NULL)))
56 | #' dimnames(set_dimnames(nx2, list(axis2 = NULL, axis3 = NULL)))
57 | #' dimnames(set_dimnames(nx2, list(NULL), 2:3))
58 | set_dimnames <- function(x, nm, which_dim = NULL) {
59 | if (is.null(nm))
60 | return(drop_dimnames(x, which_dim))
61 |
62 | else if (is.list(nm)) {
63 | nm <- lapply(nm, as.character)
64 | if (identical(nm, list(character())))
65 | return(drop_dimnames(x, which_dim, keep_axis_names = TRUE))
66 | } else
67 | nm <- as.character(nm)
68 |
69 | dim_nms <- dimnames(x) %||% vector("list", ndim(x))
70 |
71 | if (is.null(which_dim)) {
72 | if (is.character(nm)) {
73 | stopifnot(identical(length(nm), length(dim(x))))
74 | names(dim_nms) <- nm
75 | dimnames(x) <- dim_nms
76 | return(x)
77 |
78 | } else if (is.list(nm)) {
79 | # if x dims are named and nm is a named list, match names
80 | if (!is.null(names(nm)) &&
81 | all(nzchar(names(nm))) &&
82 | all(names(nm) %in% names(dim_nms))) {
83 | dim_nms <- modifyList(dim_nms, nm, keep.null = TRUE)
84 | dimnames(x) <- dim_nms
85 | return(x)
86 |
87 | } else {
88 | stopifnot(length(nm) == dim(x))
89 | if (!is.null(names(nm)))
90 | warning("Names supplied to `nm` are ignored")
91 | dimnames(x) <- nm
92 | return(x)
93 | }
94 | }
95 | } else { # which_dim supplied
96 | if(is.character(which_dim)) {
97 | stopifnot(all(which_dim %in% names(dimnames(x))))
98 | which_dim <- match(which_dim, names(dimnames(x)))
99 | }
100 |
101 | if (is.character(nm)) {
102 | stopifnot(identical(length(which_dim), 1L),
103 | identical(length(nm), dim(x)[which_dim]))
104 | dimnames(x)[[which_dim]] <- nm
105 | return(x)
106 |
107 | } else { # nm is a list and dim supplied
108 |
109 | stopifnot(identical(length(nm), length(which_dim)))
110 | for (i in seq_along(nm)) {
111 | dim_nms[[which_dim[i]]] <- nm[[i]]
112 | }
113 |
114 | if(!is.null(names(nm))) {
115 | new_axis_nms <- names(dim_nms) %||% character(length(dim_nms))
116 | new_axis_nms[which_dim] <- names(nm)
117 | new_axis_nms[!nzchar(new_axis_nms)] <-
118 | names(dim_nms)[!nzchar(new_axis_nms)] %||% ""
119 | names(dim_nms) <- new_axis_nms
120 | }
121 |
122 | dimnames(x) <- dim_nms
123 | return(x)
124 |
125 | } # end nm is a list and dim supplied
126 |
127 | } # end else which_dim supplied
128 | stop("invalid input")
129 | }
130 |
131 |
132 | #' Drop dimnames
133 | #'
134 | #' A pipe-friendly wrapper for `dim(x) <- NULL` and `dimnames(x) <- NULL` or, if
135 | #' `which_dim` is not `NULL`, \code{dimnames(x)[which_dim] <- list(NULL)}
136 | #'
137 | #' @param x an object, potentially with dimnames
138 | #' @param which_dim If `NULL` (the default) then all dimnames are dropped. If
139 | #' integer vector, then dimnames only at the specified dimensions are dropped.
140 | #' @param keep_axis_names TRUE or FALSE, whether to preserve the axis names when
141 | #' dropping the dimnames
142 | #'
143 | #' @export
144 | drop_dimnames <- function(x, which_dim = NULL, keep_axis_names = FALSE) {
145 | if(is.null(which_dim)) {
146 | if(keep_axis_names)
147 | dimnames(x) <- lapply(dimnames(x), function(...) NULL)
148 | else
149 | dimnames(x) <- NULL
150 | } else {
151 | which_dim <- standardize_which_dim(which_dim, x, multiple_OK = TRUE)
152 | dimnames(x)[which_dim] <- list(NULL)
153 | if(!keep_axis_names)
154 | names(dimnames(x))[which_dim] <- ""
155 | }
156 | x
157 | }
158 |
159 | #' @rdname drop_dimnames
160 | #' @export
161 | drop_dim <- function(x) {
162 | dim(x) <- NULL
163 | x
164 | }
165 |
166 | #' @rdname drop_dimnames
167 | #' @export
168 | drop_dim2 <- function(x) {
169 | dim2(x) <- NULL
170 | x
171 | }
172 |
--------------------------------------------------------------------------------
/R/extract.R:
--------------------------------------------------------------------------------
1 | #' Extract with `[` on a specified dimension
2 | #'
3 | #' @param X Typically, an array, but any object with a `[` method is accepted
4 | #' (e.g., dataframe, vectors)
5 | #' @param which_dim A scalar integer or character, specifying the dimension to
6 | #' extract from
7 | #' @param idx A numeric, boolean, or character vector to perform subsetting
8 | #' with.
9 | #' @param drop Passed on to `[`. If `NULL` (the default), then drop is omitted
10 | #' from the argument, and the default is used (defaults to TRUE for most
11 | #' objects, including arrays)
12 | #' @param depth Scalar number, how many levels to recurse down if `X` is a list
13 | #' of arrays. Set this if you want to explicitly treat a list as a vector
14 | #' (that is, a one-dimensional array). (You can alternatively set a dim
15 | #' attribute with `dim<-` on the list to prevent recursion)
16 | #'
17 | #' @export
18 | #'
19 | #' @examples
20 | #' # extract_rows is useful to keep the same code path for arrays of various sizes
21 | #' X <- array(1:8, c(4, 3, 2))
22 | #' y <- c("a", "b", "c", "d")
23 | #' (Y <- onehot(y))
24 | #'
25 | #' extract_rows(X, 2)
26 | #' extract_rows(Y, 2)
27 | #' extract_rows(y, 2)
28 | #'
29 | #' library(zeallot)
30 | #' c(X2, Y2, y2) %<-% extract_rows(list(X, Y, y), 2)
31 | #' X2
32 | #' Y2
33 | #' y2
34 | extract_dim <- function(X, which_dim, idx, drop = NULL, depth = Inf) {
35 | which_dim <- standardize_which_dim(which_dim, X)
36 |
37 | if(is.list(X) && is.null(dim(X)) && depth > 0L)
38 | return(lapply(X, function(x)
39 | extract_dim(x, which_dim, idx, drop = drop, depth = depth - 1L)))
40 |
41 | expr <- extract_dim_expr(X, which_dim, idx_var_sym = quote(idx), drop = drop)
42 | eval(expr)
43 | }
44 |
45 |
46 | #' @rdname extract_dim
47 | #' @export
48 | extract_rows <- function(X, idx, drop = NULL, depth = Inf)
49 | extract_dim(X, 1L, idx, drop = drop, depth = depth)
50 |
51 | #' @rdname extract_dim
52 | #' @export
53 | extract_cols <- function(X, idx, drop = NULL, depth = Inf)
54 | extract_dim(X, -1L, idx, drop = drop, depth = depth)
55 |
56 |
57 |
58 |
59 | extract_dim_chr_expr <-
60 | function(X, which_dim, drop = NULL, ndims = ndim(X),
61 | idx_var_nm = names(which_dim) %||%
62 | paste0("idx", if(length(which_dim) > 1L) seq_along(which_dim)),
63 | var_to_subset = deparse(substitute(X))) {
64 |
65 | force(var_to_subset)
66 |
67 | which_dim <- as.integer(which_dim)
68 | stopifnot(identical(length(idx_var_nm), length(which_dim)),
69 | !anyDuplicated(idx_var_nm))
70 |
71 | args <- character(ndims)
72 | args[which_dim] <- idx_var_nm
73 |
74 | if(!is.null(drop))
75 | args <- c(args, " drop = drop")
76 |
77 | args <- paste0(args, collapse = ",")
78 | sprintf("%s[%s]", var_to_subset, args)
79 | }
80 |
81 |
82 | extract_dim_expr <-
83 | function(X,
84 | which_dim,
85 | drop = NULL,
86 | ndims = ndim(X),
87 | idx_var_sym = names(which_dim) %||%
88 | paste0("idx", if (length(which_dim) > 1L)
89 | seq_along(which_dim)),
90 | var_to_subset = substitute(X)) {
91 | args <- rep(list(quote(expr =)), ndims)
92 | args[[which_dim]] <- idx_var_sym
93 | if(!is.null(drop))
94 | args$drop <- drop
95 | as.call(c(quote(`[`), var_to_subset, args))
96 |
97 | }
98 |
99 |
100 |
101 | #
102 | # extract_call <-
103 | # function(X,
104 | # which_dim,
105 | # drop = NULL,
106 | # ndims = ndim(X),
107 | # idx_var_sym = names(which_dim) %||%
108 | # paste0("idx", if (length(which_dim) > 1L)
109 | # seq_along(which_dim)),
110 | # var_to_subset = substitute(X)) {
111 | # args <- rep(list(quote(expr =)), ndims)
112 | # args[[which_dim]] <- idx_var_sym
113 | # if(!is.null(drop))
114 | # args$drop <- drop
115 | # as.call(c(quote(`[`), var_to_subset, args))
116 | #
117 | # }
118 |
--------------------------------------------------------------------------------
/R/map.R:
--------------------------------------------------------------------------------
1 | #' Apply a function across subsets along an array dimension
2 | #'
3 | #' @description
4 | #' `map_along_dim(X, dim, func)` is a simple wrapper around `split_along_dim(X,
5 | #' dim) %>% map(func)`. It is conceptually and functionally equivalent to
6 | #' `base::apply()`, with the following key differences:
7 | #'
8 | #' + it is guaranteed to return a list (`base::apply()` attempts to simplify the
9 | #' output to an array, sometimes unsuccessfully, making the output unstable)
10 | #'
11 | #' + it accepts the compact lambda notation `~.x` just like in [`purrr::map`]
12 | #' (and [`modify_along_dim()`])
13 | #'
14 | #'
15 | #' @param X an R array
16 | #' @param .dim which dimension to map along. Passed on to [`split_along_dim()`],
17 | #' and accepts all the same inputs. Valid inputs include
18 | #'
19 | #' * positive integers (index position(s) of dimension),
20 | #' * negative integers (index positions(s) of dimensions, counting from the back), or
21 | #' * character vector (corresponding to array dimnames)
22 | #' @param .f A function, string of a function name, or `purrr` style compact lambda syntax (e.g, `~.x + 1`)
23 | #' @param ... passed on to `.f()`
24 | #'
25 | #' @return An R list
26 | #' @export
27 | #'
28 | #' @rdname map_along_dim
29 | #' @examples
30 | #' X <- matrix2(letters[1:15], ncol = 3)
31 | #'
32 | #' apply(X, 1, function(x) paste(x, collapse = "")) # simplifies to a vector
33 | #' map_along_dim(X, 1, ~paste(.x, collapse = "")) # returns a list
34 | #'
35 | #' identical(
36 | #' map_along_rows(X, identity),
37 | #' map_along_dim(X, 1, identity)) # TRUE
38 | #'
39 | #' identical(
40 | #' map_along_cols(X, identity),
41 | #' map_along_dim(X, -1, identity)) # TRUE
42 | map_along_dim <- function(X, .dim, .f, ...) {
43 | stopifnot(is.array(X))
44 | if (requireNamespace("rlang", quietly = TRUE)) {
45 | .f <- rlang::as_function(.f)
46 | } else {
47 | if (inherits(.f, "formula"))
48 | stop("Specifing functions via forumla syntax requires ",
49 | "package rlang to be available")
50 | .f <- match.fun(.f)
51 | }
52 | lapply(split_along_dim(X, .dim), .f, ...)
53 | }
54 |
55 | #' @export
56 | #' @rdname map_along_dim
57 | map_along_rows <- function(X, .f, ...)
58 | map_along_dim(X, 1L, .f, ...)
59 |
60 | #' @export
61 | #' @rdname map_along_dim
62 | map_along_cols <- function(X, .f, ...)
63 | map_along_dim(X, -1L, .f, ...)
64 |
65 |
66 |
67 | ## Maybe add this?
68 | # map_*_dim <- function(x, which_dim, .f) {
69 | # map(x, .f) %>%
70 | # bind_*_dim()
71 | # }
72 |
--------------------------------------------------------------------------------
/R/modify.R:
--------------------------------------------------------------------------------
1 |
2 | #' Modify an array by mapping over 1 or more dimensions
3 | #'
4 | #' This function can be thought of as a version of `base::apply()` that is
5 | #' guaranteed to return a object of the same dimensions as it was input. It also
6 | #' generally preserves attributes, as it's built on top of `[<-`.
7 | #'
8 | #' @param X An array, or a list of arrays
9 | #' @param which_dim integer vector of dimensions to modify at
10 | #' @param .f a function or formula defining a function(same semantics as
11 | #' [`purrr::map()`]). The function must return either an array the same shape
12 | #' as it was passed, a vector of the same length, or a scalar, although the
13 | #' type of the returned object does not need to be the same as was passed in.
14 | #' @param ... passed on to `.f()`
15 | #'
16 | #' @export
17 | #' @rdname modify_along_dim
18 | #' @return An array, or if `X` was a list, a list of arrays of the same shape as
19 | #' was passed in.
20 | #' @examples
21 | #' x <- array(1:6, 1:3)
22 | #' modify_along_dim(x, 3, ~mean(.x))
23 | #' modify_along_dim(x, 3, ~.x/mean(.x))
24 | modify_along_dim <- function(X, which_dim, .f, ...) {
25 |
26 | if(is.list(X) && is.null(dim(X)))
27 | return(lapply(X, function(x) modify_along_dim(x, which_dim, .f, ...)))
28 |
29 | if (requireNamespace("rlang", quietly = TRUE)) {
30 | .f <- rlang::as_function(.f)
31 | } else {
32 | if (inherits(.f, "formula"))
33 | stop("Specifing functions via forumla syntax requires ",
34 | "package rlang to be available")
35 | .f <- match.fun(.f)
36 | }
37 |
38 | which_dim <- standardize_which_dim(which_dim, X, multiple_OK = TRUE)
39 |
40 | names(which_dim) <- paste0("idx", seq_along(which_dim))
41 |
42 | Xe <- extract_dim_chr_expr(X, which_dim,
43 | idx_var_nm = names(which_dim),
44 | var_to_subset = "X")
45 |
46 | loop_controlflow <- paste0(
47 | "for (", names(which_dim),
48 | " in .seq_along_dim(X,", as.integer(which_dim), "))",
49 | collapse = "\n")
50 |
51 | args <- as.pairlist(alist(X = , .f = , ... = ))
52 | body <- parse1(sprintf("{
53 | oX <- X
54 | storage.mode(X) <- 'logical'
55 | %s
56 | %s <- .f(o%s, ...)
57 | X
58 | }", loop_controlflow, Xe, Xe))
59 |
60 | modify_it <- eval(call("function", args, body))
61 |
62 | if (prod(DIM(X)[which_dim]) > 100)
63 | modify_it <- cmpfun(modify_it)
64 |
65 | modify_it(X, .f, ...)
66 | }
67 |
68 | #' @export
69 | #' @rdname modify_along_dim
70 | modify_along_rows <- function(X, .f, ...)
71 | modify_along_dim(X, 1L, .f, ...)
72 |
73 | #' @export
74 | #' @rdname modify_along_dim
75 | modify_along_cols <- function(X, .f, ...)
76 | modify_along_dim(X, -1L, .f, ...)
77 |
78 | MODIFY_ALONG_FN_TEMPLATE <- alist(X = , .f = , ... = , {
79 | oX <- X
80 | storage.mode(X) <- "logical"
81 | for (idx1 in .seq_along_dim(X, 3))
82 | X[, , idx1] <- .f(oX[, , idx1], ...)
83 | X
84 | })
85 |
--------------------------------------------------------------------------------
/R/onehot.R:
--------------------------------------------------------------------------------
1 | #' Convert vector to a onehot representation (binary class matrix)
2 | #'
3 | #' @param y character, factor, or numeric vector
4 | #' @param Y a matrix, as returned by `onehot()` or similar.
5 | #' @param order `NULL`, `FALSE`, or a character vector. If `NULL` (the default),
6 | #' then levels are sorted with `sort()`. If `FALSE`, then levels are taken in
7 | #' order of their first appearance in `y`. If a character vector, then `order`
8 | #' must contain all levels found in `y`.
9 | #' @param named if the returned matrix should have column names
10 | #' @param classes A character vector of class names in the order corresponding
11 | #' to `Y`'s onehot encoding. Typically, `colnames(Y)`. if `NULL`, then the
12 | #' decoder returns the column number.
13 | #' @param n_classes The total number of classes expected in `Y`. Used for input
14 | #' checking in the returned decoder, also, to reconstruct the correct
15 | #' dimensions if the passed in `Y` is missing `dim()` attributes.
16 | #'
17 | #' @return A binary class matrix
18 | #' @export
19 | #' @seealso [keras::to_categorical]
20 | #' @rdname onehot
21 | #'
22 | #' @examples
23 | #' if(require(zeallot)) {
24 | #' y <- letters[1:4]
25 | #' c(Y, decode) %<-% onehot_with_decoder(y)
26 | #' Y
27 | #' decode(Y)
28 | #' identical(y, decode(Y))
29 | #' decode(Y[2,,drop = TRUE])
30 | #' decode(Y[2,,drop = FALSE])
31 | #' decode(Y[2:3,])
32 | #'
33 | #' rm(Y, decode)
34 | #' }
35 | #'
36 | #' # more peicemeal functions
37 | #' Y <- onehot(y)
38 | #' decode_onehot(Y)
39 | #'
40 | #' # if you need to decode a matrix that lost colnames,
41 | #' # make your own decoder that remembers classes
42 | #' my_decode <- onehot_decoder(Y)
43 | #' colnames(Y) <- NULL
44 | #' my_decode(Y)
45 | #' decode_onehot(Y)
46 | #'
47 | #' # factor and numeric vectors also accepted
48 | #' onehot(factor(letters[1:4]))
49 | #' onehot(4:8)
50 | #'
51 | onehot_with_decoder <- function(y, order = NULL, named = TRUE) {
52 |
53 | Y <- onehot(y, order = order, named = TRUE)
54 | decode <- onehot_decoder(classes = colnames(Y),
55 | n_classes = ncol(Y))
56 |
57 | if(!isTRUE(named))
58 | colnames(Y) <- NULL
59 |
60 | list(onehot = Y, decode = decode)
61 | }
62 |
63 |
64 | #' @export
65 | #' @rdname onehot
66 | onehot <- function(y, order = NULL, named = TRUE) {
67 |
68 | if (is.factor(y)) {
69 |
70 | if (!missing(order) && !is.null(order))
71 | warning("value supplied to `order` is ignored since y is a factor")
72 |
73 | order <- levels(y)
74 | ncats <- length(order)
75 | idx_col <- unclass(y)
76 |
77 | } else if (is.character(y) || is.numeric(y)) {
78 |
79 | if (is.null(order))
80 | order <- sort(unique(y))
81 | else if (identical(order, FALSE))
82 | order <- unique(y)
83 | else if (is.character(order) || is.numeric(order))
84 | stopifnot(typeof(y) == typeof(order), unique(y) %in% order)
85 | else
86 | stop("`order` must be NULL, FALSE, or a character vector")
87 |
88 | idx_col <- match(y, order)
89 | ncats <- length(order)
90 |
91 | } else
92 | stop("`y` must be a character, numeric, or factor")
93 |
94 | Y <- array(0, dim = c(DIM(y), ncats))
95 | idx <- cbind(seq_along(y), idx_col, deparse.level = 0L)
96 | Y[idx] <- 1
97 |
98 | if(named)
99 | colnames(Y) <- as.character(order)
100 |
101 | Y
102 | }
103 |
104 |
105 | #' @export
106 | #' @rdname onehot
107 | decode_onehot <- function(Y, classes = colnames(Y),
108 | n_classes = ncol(Y) %||% length(classes)) {
109 | decode <- onehot_decoder(classes = classes, n_classes = n_classes)
110 | decode(Y)
111 | }
112 |
113 | #' @export
114 | #' @rdname onehot
115 | onehot_decoder <- function(Y, classes = colnames(Y), n_classes = length(classes)) {
116 | force(classes)
117 | n_classes <- as.integer(n_classes)
118 | rm(Y)
119 |
120 | if(n_classes <= 0L || is.na(n_classes))
121 | stop("`n_classes` must be a scalar integer greater than 0")
122 |
123 | robust_max.col <- function(m) {
124 | if (is.matrix(m))
125 | stopifnot(identical(ncol(m), n_classes))
126 | else { # dim was probably dropped by [, drop = TRUE]
127 | if (length(m) %% n_classes)
128 | stop("length(Y) must be a multiple of n_classes, ", n_classes,
129 | ", not", length(m))
130 | dim(m) <- c(length(m) %/% n_classes, n_classes)
131 | }
132 |
133 | max.col(m)
134 | }
135 |
136 | if (is.null(classes)) {
137 | function(Y) robust_max.col(Y)
138 | } else {
139 | function(Y) classes[robust_max.col(Y)]
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/R/reshape.R:
--------------------------------------------------------------------------------
1 | #' Reshape an array to send a dimension forward or back
2 | #'
3 | #' @param X an array
4 | #' @param which_dim scalar integer or string, which dim to bring forward.
5 | #' Negative numbers count from the back
6 | #'
7 | #' This is a powered by `base::aperm()`.
8 | #'
9 | #' @return a reshaped array
10 | #' @export
11 | #'
12 | #' @seealso `base::aperm()` `set_dim()` `keras::array_reshape()`
13 | #'
14 | #' @examples
15 | #' x <- array(1:24, 2:4)
16 | #' y <- set_as_rows(x, 3)
17 | #'
18 | #' for (i in seq_along_dim(x, 3))
19 | #' stopifnot( identical(x[,,i], y[i,,]) )
20 | set_as_rows <- function(X, which_dim) {
21 | stopifnot(is.array(X))
22 |
23 | which_dim <- standardize_which_dim(which_dim, X)
24 |
25 | cur_dim_order <- seq_along(dim(X))
26 | new_dim_order <- c(which_dim, cur_dim_order[-which_dim])
27 |
28 | aperm(X, new_dim_order)
29 | }
30 |
31 | # other name ideas:
32 | # bring_dim_forward()
33 |
34 | #' @export
35 | #' @rdname set_as_rows
36 | set_as_cols <- function(X, which_dim) {
37 | stopifnot(is.array(X))
38 | which_dim <- standardize_which_dim(which_dim, X)
39 |
40 | cur_dim_order <- seq_along(dim(X))
41 | new_dim_order <- c(cur_dim_order[-which_dim], which_dim)
42 |
43 | aperm(X, new_dim_order)
44 | }
45 |
--------------------------------------------------------------------------------
/R/seq_along.R:
--------------------------------------------------------------------------------
1 | #' Sequence along a dimension
2 | #'
3 | #' @param x a dataframe, array or vector. For `seq_along_rows`, and
4 | #' `seq_along_cols` sequence along the first and last dimensions,
5 | #' respectively. Atomic vectors are treated as 1 dimensional
6 | #' arrays (i.e., `seq_along_rows` is equivalent to `seq_along` when `x` is an
7 | #' atomic vector or list).
8 | #' @param which_dim a scalar integer or character string, specifying which
9 | #' dimension to generate a sequence for. Negative numbers count from the back.
10 | #'
11 | #' @return a vector of integers 1:nrow(x), safe for use in `for` loops and
12 | #' vectorized equivalents.
13 | #' @export
14 | #' @examples
15 | #' for (r in seq_along_rows(mtcars[1:4,]))
16 | #' print(mtcars[r,])
17 | #'
18 | #' x <- 1:3
19 | #' identical(seq_along_rows(x), seq_along(x))
20 | #'
21 | #' @export
22 | seq_along_dim <- function(x, which_dim)
23 | seq_len( DIM(x)[[standardize_which_dim(which_dim, x)]] )
24 |
25 | # assumes cannonical which_dim, no checking
26 | .seq_along_dim <- function(x, which_dim)
27 | seq_len( DIM(x)[[which_dim]] )
28 |
29 |
30 | #' @rdname seq_along_dim
31 | #' @export
32 | seq_along_rows <- function(x) seq_along_dim(x, 1L)
33 |
34 | #' @rdname seq_along_dim
35 | #' @export
36 | seq_along_cols <- function(x) seq_along_dim(x, -1L)
37 |
--------------------------------------------------------------------------------
/R/shuffle.R:
--------------------------------------------------------------------------------
1 | #' Shuffle along the first dimension multiple arrays in sync
2 | #'
3 | #' @param ... arrays of various dimensions (vectors and data.frames OK too)
4 | #'
5 | #' @return A list of objects passed on to `...`, or if a single object was
6 | #' supplied, then the single object shuffled
7 | #' @export
8 | #'
9 | #' @examples
10 | #' x <- 1:3
11 | #' y <- matrix(1:9, ncol = 3)
12 | #' z <- array(1:27, c(3,3,3))
13 | #'
14 | #' if(require(zeallot)) {
15 | #' c(xs, ys, zs) %<-% shuffle_rows(x, y, z)
16 | #'
17 | #' l <- lapply(seq_along_rows(y), function(r) {
18 | #' list(x = x[r], y = y[r,], z = z[r,,])
19 | #' })
20 | #'
21 | #' ls <- lapply(seq_along_rows(y), function(r) {
22 | #' list(x = xs[r], y = ys[r,], z = zs[r,,])
23 | #' })
24 | #'
25 | #' stopifnot(
26 | #' length(unique(c(l, ls))) == length(l))
27 | #' }
28 | shuffle_rows <- function(...) {
29 | l <- list(...)
30 |
31 | single_obj_in <- identical(length(l), 1L)
32 | single_list_in <- is.list(l[[1]]) && is.null(dim(l[[1]]))
33 |
34 | if(single_list_in) {
35 | single_obj_in <- FALSE
36 | l <- l[[1L]]
37 | }
38 |
39 | nrows <- unique(vapply(l, NROW, 0L))
40 | if(!identical(length(nrows), 1L))
41 | stop("All objects passed to `...` must have the same number of rows")
42 |
43 | idx <- sample.int(nrows)
44 |
45 | for (i in seq_along(l))
46 | l[[i]] <- extract_rows(l[[i]], idx, drop = FALSE)
47 |
48 | if (single_obj_in)
49 | l[[1L]]
50 | else
51 | l
52 | }
53 |
--------------------------------------------------------------------------------
/R/split.R:
--------------------------------------------------------------------------------
1 | #' Split an array along a dimension
2 | #'
3 | #' @param X an array, or list of arrays. An atomic vector without a dimension
4 | #' attribute is treated as a 1 dimensional array (Meaning, atomic vectors
5 | #' without a dim attribute are only accepted if `which_dim` is `1`. Names of
6 | #' the passed list are preserved. If a list of arrays, all the arrays must
7 | #' have the same length of the dimension being split.
8 | #' @param which_dim a scalar string or integer, specifying which dimension to
9 | #' split along. Negative integers count from the back. If a string, it must
10 | #' refer to a named dimension (e.g, one of `names(dimnames(X))`.
11 | #' @param f Specify how to split the dimension. \describe{
12 | #'
13 | #' \item{character, integer, factor}{passed on to `base::split()`. Must be the
14 | #' same length as the dimension being split.}
15 | #'
16 | #' \item{a list of vectors}{Passed on to `base::interaction()` then
17 | #' `base::split()`. Each vector in the list must be the same length as the
18 | #' dimension being split.}
19 | #'
20 | #' \item{a scalar integer}{used to split into that many groups of equal size}
21 | #'
22 | #' \item{a numeric vector where \code{all(f<0)}}{specifies the relative size
23 | #' proportions of the groups being split. \code{sum(f)} must be \code{1}. For
24 | #' example \code{c(0.2, 0.2, 0.6)} will return approximately a 20\%-20\%-60\%
25 | #' split.} }
26 | #' @param drop passed on to `[`.
27 | #' @param depth Scalar number, how many levels to recurse down. Set this if you
28 | #' want to explicitly treat a list as a vector (that is, a one-dimensional
29 | #' array). (You can alternatively set dim attributes with `dim<-` on the list
30 | #' to prevent recursion)
31 | #'
32 | #' `split_along_dim(X, which_dim)` is equivalent to `split_on_dim(X,
33 | #' which_dim, seq_along_dim(X, which_dim))`.
34 | #'
35 | #' @return A list of arrays, or if a list of arrays was passed in, then a list
36 | #' of lists of arrays.
37 | #' @rdname split-array
38 | #' @export
39 | #'
40 | #' @examples
41 | #' X <- array(1:8, c(2,3,4))
42 | #' X
43 | #' split_along_dim(X, 2)
44 | #'
45 | #' # specify f as a factor, akin to base::split()
46 | #' split_on_dim(X, 2, c("a", "a", "b"), drop = FALSE)
47 | #'
48 | #' d <- c(10, 3, 3)
49 | #' X <- array(1:prod(d), d)
50 | #' y <- letters[1:10]
51 | #' Y <- onehot(y)
52 | #'
53 | #' # specify `f`` as relative partition sizes
54 | #' if(require(zeallot) && require(magrittr) && require(purrr)) {
55 | #'
56 | #' c(train, validate, test) %<-% {
57 | #' list(X = X, Y = Y, y = y) %>%
58 | #' shuffle_rows() %>%
59 | #' split_on_rows(c(0.6, 0.2, 0.2)) %>%
60 | #' transpose()
61 | #' }
62 | #'
63 | #' str(test)
64 | #' str(train)
65 | #' str(validate)
66 | #'
67 | #' }
68 | #'
69 | #'
70 | #' # with with array data in a data frame by splitting row-wise
71 | #' if(require(tibble))
72 | #' tibble(y, X = split_along_rows(X))
73 | split_on_dim <- function(X, which_dim,
74 | f = dimnames(X)[[which_dim]],
75 | drop = FALSE, depth = Inf) {
76 |
77 | stopifnot(!is.null(f))
78 |
79 | if(is.list(f))
80 | f <- interaction(f, drop = TRUE)
81 |
82 | if (is.list(X) && is.null(dim(X)) && depth > 0L)
83 | return(lapply(X, function(x)
84 | split_on_dim(x, which_dim, f = f, drop = drop, depth = depth - 1L)))
85 |
86 | which_dim <- standardize_which_dim(which_dim, X)
87 |
88 | id <- .seq_along_dim(X, which_dim)
89 |
90 | if(is.scalar.integerish(f))
91 | f <- cut(id, f, labels = paste0("grp", seq_len(f)))
92 | else if (is.numeric(f) && all(f < 1)) {
93 | stopifnot(sum(f) == 1)
94 | f <- cut(id, c(0, cumsum(f) * length(id)),
95 | labels = names(f) %||% paste0("grp", seq_along(f)))
96 | }
97 |
98 | if (!identical(length(id), length(f)))
99 | stop("`f` must be the same length as the dimension being split on.")
100 |
101 | l <- split(id, f)
102 |
103 | extract_call <- extract_dim_expr(X, which_dim,
104 | idx_var_sym = quote(l[[i]]), drop = drop)
105 | split_it <- new_split_on_fn(extract_call)
106 |
107 | if(length(l) > 5000)
108 | split_it <- cmpfun(split_it)
109 |
110 | out <- split_it(X, l)
111 |
112 | # names(out) <- names(l)
113 | out
114 | }
115 |
116 | SPLIT_ON_FN_TEMPLATE <- alist(X = , l = , {
117 | out <- vector("list", length(l))
118 | for (i in seq_along(l))
119 | out[[i]] <- EXTRACT_EXPR
120 | out
121 | })
122 | new_split_on_fn <- function(extract_expr) {
123 | SPLIT_ON_FN_TEMPLATE[[c(3, 3, 4, 3)]] <- extract_expr
124 | }
125 |
126 | SPLIT_ON_FN_TEMPLATE <- alist(X = , l = , {
127 | for (i in seq_along(l))
128 | l[[i]] <- EXTRACT_EXPR
129 | l
130 | })
131 |
132 | new_split_on_fn <- function(extract_expr) {
133 | SPLIT_ON_FN_TEMPLATE[[c(3, 2, 4, 3)]] <- extract_expr
134 | as.function.default(SPLIT_ON_FN_TEMPLATE, envir = minimal_split_along_fn_env)
135 | }
136 |
137 |
138 |
139 | #' @rdname split-array
140 | #' @export
141 | split_on_rows <- function(X,
142 | f = rownames(X),
143 | drop = FALSE, depth = Inf)
144 | split_on_dim(X, 1L, f = f, drop = drop, depth = depth)
145 |
146 | #' @rdname split-array
147 | #' @export
148 | split_on_cols <- function(X,
149 | f = rownames(X),
150 | drop = FALSE, depth = Inf)
151 | split_on_dim(X, -1L, f = f, drop = drop, depth = depth)
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 | minimal_split_along_fn_env <- list2env(list(
160 | `<-` = `<-`,
161 | `{` = `{`,
162 | `[` = `[`,
163 | `[[<-` = `[[<-`,
164 | `[[` = `[[`,
165 | vector = vector,
166 | `for` = `for`,
167 | seq_len = seq_len,
168 | seq_along = seq_along
169 | ))
170 |
171 |
172 | SPLIT_ALONG_FN_TEMPLATE <- alist(X = , {
173 | out <- vector('list', LENGTH_OUT)
174 | for (i in seq_len(LENGTH_OUT))
175 | out[[i]] <- EXTRACT_CALL
176 | out
177 | })
178 |
179 |
180 | new_split_along_fn <- function(extract_call, length_out) {
181 | SPLIT_ALONG_FN_TEMPLATE[[c(2L, 3L, 4L, 3L)]] <- extract_call
182 | SPLIT_ALONG_FN_TEMPLATE[[c(2L, 2L, 3L, 3L)]] <- length_out
183 | SPLIT_ALONG_FN_TEMPLATE[[c(2L, 3L, 3L, 2L)]] <- length_out
184 |
185 | as.function.default(SPLIT_ALONG_FN_TEMPLATE,
186 | envir = minimal_split_along_fn_env)
187 | }
188 |
189 | #' @rdname split-array
190 | #' @export
191 | #' @importFrom compiler cmpfun
192 | split_along_dim <- function(X, which_dim, depth = Inf) {
193 |
194 | # don't recurse on data.frame or other overloaded array-type classes
195 | if (is.list(X) && is.null(dim(X)) && depth > 0L)
196 | return(lapply(X, function(x)
197 | split_along_dim(x, which_dim, depth = depth - 1L)))
198 |
199 | which_dim <- standardize_which_dim(which_dim, X, multiple_OK = TRUE)
200 | if(ndim(X) == 1L)
201 | X <- expand_dims(X)
202 | X <- as.array(X)
203 |
204 | # TODO: consider adding support for `drop = TRUE` old behavior
205 | X <- asplit(as.array(X), which_dim)
206 | X
207 | }
208 |
209 |
210 |
211 | #' @rdname split-array
212 | #' @export
213 | split_along_rows <- function(X, depth = Inf)
214 | split_along_dim(X, 1L, depth = depth)
215 |
216 | #' @rdname split-array
217 | #' @export
218 | split_along_cols <- function(X, depth = Inf)
219 | split_along_dim(X, -1L, depth = depth)
220 |
221 |
222 | # TODO:
223 | if(FALSE) {
224 | as_listarray <- function() {}
225 | unlist.listarray <- function() {}
226 | }
227 |
228 |
229 |
--------------------------------------------------------------------------------
/R/standardize.R:
--------------------------------------------------------------------------------
1 |
2 | standardize_which_dim <- function(which_dim, X,
3 | n_dim = ndim(X),
4 | names_dimnames_X = names(dimnames(X)),
5 | multiple_OK = FALSE
6 | ) {
7 | # 3 valid inputs
8 | # a) string for a name
9 | # b) negative number for counting backwards
10 | # c) positive integer (canonical)
11 | # outputs:
12 | # case c always
13 |
14 | if (isTRUE(multiple_OK))
15 | return(vapply(which_dim, function(d)
16 | standardize_which_dim(d, X, n_dim, names_dimnames_X, multiple_OK = FALSE),
17 | 1L))
18 |
19 | if (is.character(which_dim)) {
20 | stopifnot(is.scalar(which_dim))
21 | which_dim <- match(which_dim, names_dimnames_X)
22 | if(is.na(which_dim))
23 | stop("'which_dim %in% names(dimnames(X))' must be TRUE")
24 |
25 | } else if (is.scalar.integerish(which_dim)) {
26 | which_dim <- as.integer(which_dim)
27 |
28 | stopifnot(abs(which_dim) <= n_dim)
29 |
30 | if(which_dim < 0L)
31 | which_dim <- n_dim + which_dim + 1L
32 |
33 | } else
34 | stop("`which_dim` must be a positive or negative integer, or character string")
35 |
36 | which_dim
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/R/utils.R:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #' Length of `DIM()`
7 | #'
8 | #' Returns the number of dimensions, or 1 for an atomic vector.
9 | #' @param x a matrix or atomic vector
10 | #' @export
11 | ndim <- function(x) {
12 | if (is.null(dx <- dim(x)))
13 | 1L
14 | else
15 | length(dx)
16 | }
17 |
18 |
19 |
20 | #' Helpers for working with 1-d arrays
21 | #'
22 | #' `DIM()` is to `dim()` as `NROW()` is to `nrow()`. That is, it is identical to
23 | #' `dim()` in most cases except if the input is a bare atomic vector with no
24 | #' `dim` attribute, in which case, the length of the vector is returned instead
25 | #' of `NULL`.
26 | #'
27 | #' @param x an R vector, potentially with a dim attribute
28 | #' @rdname DIM
29 | #'
30 | #' @export
31 | #' @return For `DIM`, the `dim` attribute, or if that's not found, then `length(x)`
32 | #' @examples
33 | #' x <- 1:3
34 | #' dim(x)
35 | #' dim(array(x))
36 | #'
37 | #' DIM(x)
38 | #' DIM(array(x))
39 | #'
40 | DIM <- function(x) dim(x) %||% length(x)
41 |
42 |
43 | #' DROP
44 | #'
45 | #' `DROP` first calls `base::drop` and then completely removes the `dim`
46 | #' attribute if the result is a 1-d array
47 | #'
48 | #'
49 | #' @return For `DROP` an array with 2 or more axes, or a vector with no `dim`
50 | #' attributes.
51 | #' @export
52 | #' @rdname DIM
53 | #'
54 | #' @examples
55 | #' x <- array(1:3)
56 | #' str(drop(x))
57 | #' str(DROP(x))
58 | DROP <- function(x) {
59 | x <- drop(x)
60 | if(identical(length(DIM(x)), 1L))
61 | dim(x) <- NULL
62 | x
63 | }
64 |
65 |
66 | `%||%` <- function (x, y) {
67 | if (is.null(x))
68 | y
69 | else
70 | x
71 | }
72 |
73 | #' @importFrom compiler cmpfun
74 |
75 | parse1 <- function(x) parse(text = x, keep.source = FALSE)[[1]]
76 |
77 | is.negative <- function(x) x < 0
78 |
79 | is.integerish <- function(x, n = NULL, allow_na = FALSE) {
80 | if (!is.null(n) && n != length(x))
81 | return(FALSE)
82 | if (!allow_na && any(is.na(x) | is.infinite(x)))
83 | return(FALSE)
84 | if (identical(typeof_x <- typeof(x), "integer"))
85 | return(TRUE)
86 | if (identical(typeof_x, "double"))
87 | return(all(x == as.integer(x), na.rm = TRUE))
88 | FALSE
89 | }
90 |
91 |
92 | is.scalar <- function(x) identical(length(x), 1L)
93 |
94 | is.scalar.integerish <- function(x)
95 | is.scalar(x) && is.integerish(x)
96 |
97 |
98 | `%not_in%` <- function(x, y) match(x, y, nomatch = 0L) == 0L
99 |
100 | check.is.integerish <- function(x, n = NULL) {
101 | nm <- deparse(substitute(x))
102 | if(!(is.integerish(x, n))) {
103 | msg <- paste(nm, "must be an integer")
104 | if (!is.null(n))
105 | msg <- paste(msg, "of length", n)
106 | stop(msg, call. = FALSE)
107 | }
108 | }
109 |
110 | dropNULLs <- function(x) x[!vapply(x, is.null, TRUE)]
111 |
112 |
113 | quick_cbind <- function(lst) {
114 | x <- unlist(lst)
115 | dim(x) <- c(length(lst[[1]]), length(lst))
116 | x
117 | }
118 |
119 | # arr <- function(...) array(seq_len(prod(unlist(c(...)))), unlist(c(...)))
120 |
--------------------------------------------------------------------------------
/R/zzz.R:
--------------------------------------------------------------------------------
1 |
2 | eval <- NULL
3 |
4 | .onLoad <- function(libname, pkgname) {
5 | if(requireNamespace("rlang", quietly = TRUE))
6 | eval <<- rlang::eval_bare
7 | else
8 | eval <<- base::eval
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/README.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | output: github_document
3 | ---
4 |
5 |
6 |
7 | ```{r setup, include = FALSE}
8 | knitr::opts_chunk$set(
9 | collapse = TRUE,
10 | comment = "#>",
11 | fig.path = "man/figures/README-",
12 | out.width = "100%"
13 | )
14 | ```
15 | # listarrays
16 |
17 | [](https://cran.r-project.org/package=listarrays)
18 | [](https://r-pkg.org/pkg/listarrays)
19 |
20 | A toolbox for working with R arrays in a functional programming style. Flexibly
21 | split, bind, reshape, modify, subset, and name arrays.
22 |
23 | The package provides:
24 |
25 | + `split_on_dim()` and `split_along_dim()` which take an array and return a list.
26 |
27 | + `bind_on_dim()` and `bind_as_dim()` take a list and return an array.
28 |
29 | + `modify_along_dim()` takes an array, calls the passed function `.f()` on each
30 | subset of the specified dimension, and returns an array of the same shape.
31 | (think of this as a safer and sometimes faster alternative to `base::apply()`
32 | that is guaranteed to return an array of the same shape as it received)
33 |
34 | + `extract_dim()` a wrapper around `[` that allows you to specify the dimension
35 | being subset as a function argument. For example, `extract_dim(X, 1, idx)`
36 | will extract `idx` on the first dimension, regardless how many dimensions are in
37 | the array `X`. Contrast this with the base alternative `X[idx,,]`, where you
38 | have to match the number of commas `,` to the number of dimensions in `X`.
39 |
40 | + Many of the functions have two variants `*_rows()` and `*_cols()` for the two
41 | most common case of the first and last dimension. For example
42 | `split_on_rows()` which is equivalent to `split_on_dim(X, 1)` and
43 | `split_on_cols()` which is equivalent to `split_on_dim(X, -1)`
44 |
45 | * `set_dim()` and `set_dimnames()`, pipe-friendly and more flexible
46 | versions of `dim<-` and `dimnames<-`
47 |
48 | * `dim2()<-`, `set_dim2()`, `array2()`, which reshape or fills arrays using
49 | row-major (C-style) semantics
50 |
51 | * A handful of lower-level helpers that abstract out patterns commonly
52 | encountered while working with arrays, for example `expand_dims()`
53 | (the inverse of `base::drop()`, or `seq_along_rows()` (a
54 | combination of `seq_along()` and `nrow()`).
55 |
56 | * A set of functions that help encode atomic vectors as `onehot()` binary
57 | matrix's and `decode_onehot()` back into atomic vectors. (for example if
58 | training a neural network with keras)
59 |
60 | * Many of the functions work recursively if provided a list of arrays.
61 |
62 |
63 | ## Installation
64 |
65 | You can install listarrays from CRAN with:
66 | ```{r, eval=FALSE}
67 | install.packages("listarrays")
68 | ```
69 |
70 | Or install the development version from github with:
71 | ``` {r, eval=FALSE}
72 | devtools::install_github("t-kalinowski/listarrays")
73 | ```
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # listarrays
5 |
6 | [](https://cran.r-project.org/package=listarrays)
8 | [](https://r-pkg.org/pkg/listarrays)
10 |
11 | A toolbox for working with R arrays in a functional programming style.
12 | Flexibly split, bind, reshape, modify, subset, and name arrays.
13 |
14 | The package provides:
15 |
16 | - `split_on_dim()` and `split_along_dim()` which take an array and
17 | return a list.
18 |
19 | - `bind_on_dim()` and `bind_as_dim()` take a list and return an array.
20 |
21 | - `modify_along_dim()` takes an array, calls the passed function
22 | `.f()` on each subset of the specified dimension, and returns an
23 | array of the same shape. (think of this as a safer and sometimes
24 | faster alternative to `base::apply()` that is guaranteed to return
25 | an array of the same shape as it received)
26 |
27 | - `extract_dim()` a wrapper around `[` that allows you to specify the
28 | dimension being subset as a function argument. For example,
29 | `extract_dim(X, 1, idx)` will extract `idx` on the first dimension,
30 | regardless how many dimensions are in the array `X`. Contrast this
31 | with the base alternative `X[idx,,]`, where you have to match the
32 | number of commas `,` to the number of dimensions in `X`.
33 |
34 | - Many of the functions have two variants `*_rows()` and `*_cols()`
35 | for the two most common case of the first and last dimension. For
36 | example `split_on_rows()` which is equivalent to
37 | `split_on_dim(X, 1)` and `split_on_cols()` which is equivalent to
38 | `split_on_dim(X, -1)`
39 |
40 | - `set_dim()` and `set_dimnames()`, pipe-friendly and more flexible
41 | versions of `dim<-` and `dimnames<-`
42 |
43 | - `dim2()<-`, `set_dim2()`, `array2()`, which reshape or fills arrays
44 | using row-major (C-style) semantics
45 |
46 | - A handful of lower-level helpers that abstract out patterns commonly
47 | encountered while working with arrays, for example `expand_dims()`
48 | (the inverse of `base::drop()`, or `seq_along_rows()` (a combination
49 | of `seq_along()` and `nrow()`).
50 |
51 | - A set of functions that help encode atomic vectors as `onehot()`
52 | binary matrix’s and `decode_onehot()` back into atomic vectors. (for
53 | example if training a neural network with keras)
54 |
55 | - Many of the functions work recursively if provided a list of arrays.
56 |
57 | ## Installation
58 |
59 | You can install listarrays from CRAN with:
60 |
61 | ``` r
62 | install.packages("listarrays")
63 | ```
64 |
65 | Or install the development version from github with:
66 |
67 | ``` r
68 | devtools::install_github("t-kalinowski/listarrays")
69 | ```
70 |
--------------------------------------------------------------------------------
/_pkgdown.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/t-kalinowski/listarrays/b38f44fe776a9fd7f48ce096c5f5922550ea84a6/_pkgdown.yml
--------------------------------------------------------------------------------
/cran-comments.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/t-kalinowski/listarrays/b38f44fe776a9fd7f48ce096c5f5922550ea84a6/cran-comments.md
--------------------------------------------------------------------------------
/docs/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Page not found (404) • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
114 |
115 | Content not found. Please use links in the navbar.
116 |
117 |
118 |
119 |
124 |
125 |
126 |
127 |
128 |
129 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/docs/authors.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Authors • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
114 |
115 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 |
6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */
7 |
8 | /* All levels of nav */
9 | nav[data-toggle='toc'] .nav > li > a {
10 | display: block;
11 | padding: 4px 20px;
12 | font-size: 13px;
13 | font-weight: 500;
14 | color: #767676;
15 | }
16 | nav[data-toggle='toc'] .nav > li > a:hover,
17 | nav[data-toggle='toc'] .nav > li > a:focus {
18 | padding-left: 19px;
19 | color: #563d7c;
20 | text-decoration: none;
21 | background-color: transparent;
22 | border-left: 1px solid #563d7c;
23 | }
24 | nav[data-toggle='toc'] .nav > .active > a,
25 | nav[data-toggle='toc'] .nav > .active:hover > a,
26 | nav[data-toggle='toc'] .nav > .active:focus > a {
27 | padding-left: 18px;
28 | font-weight: bold;
29 | color: #563d7c;
30 | background-color: transparent;
31 | border-left: 2px solid #563d7c;
32 | }
33 |
34 | /* Nav: second level (shown on .active) */
35 | nav[data-toggle='toc'] .nav .nav {
36 | display: none; /* Hide by default, but at >768px, show it */
37 | padding-bottom: 10px;
38 | }
39 | nav[data-toggle='toc'] .nav .nav > li > a {
40 | padding-top: 1px;
41 | padding-bottom: 1px;
42 | padding-left: 30px;
43 | font-size: 12px;
44 | font-weight: normal;
45 | }
46 | nav[data-toggle='toc'] .nav .nav > li > a:hover,
47 | nav[data-toggle='toc'] .nav .nav > li > a:focus {
48 | padding-left: 29px;
49 | }
50 | nav[data-toggle='toc'] .nav .nav > .active > a,
51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a,
52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a {
53 | padding-left: 28px;
54 | font-weight: 500;
55 | }
56 |
57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */
58 | nav[data-toggle='toc'] .nav > .active > ul {
59 | display: block;
60 | }
61 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 | (function() {
6 | 'use strict';
7 |
8 | window.Toc = {
9 | helpers: {
10 | // return all matching elements in the set, or their descendants
11 | findOrFilter: function($el, selector) {
12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
13 | // http://stackoverflow.com/a/12731439/358804
14 | var $descendants = $el.find(selector);
15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])');
16 | },
17 |
18 | generateUniqueIdBase: function(el) {
19 | var text = $(el).text();
20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-');
21 | return anchor || el.tagName.toLowerCase();
22 | },
23 |
24 | generateUniqueId: function(el) {
25 | var anchorBase = this.generateUniqueIdBase(el);
26 | for (var i = 0; ; i++) {
27 | var anchor = anchorBase;
28 | if (i > 0) {
29 | // add suffix
30 | anchor += '-' + i;
31 | }
32 | // check if ID already exists
33 | if (!document.getElementById(anchor)) {
34 | return anchor;
35 | }
36 | }
37 | },
38 |
39 | generateAnchor: function(el) {
40 | if (el.id) {
41 | return el.id;
42 | } else {
43 | var anchor = this.generateUniqueId(el);
44 | el.id = anchor;
45 | return anchor;
46 | }
47 | },
48 |
49 | createNavList: function() {
50 | return $('');
51 | },
52 |
53 | createChildNavList: function($parent) {
54 | var $childList = this.createNavList();
55 | $parent.append($childList);
56 | return $childList;
57 | },
58 |
59 | generateNavEl: function(anchor, text) {
60 | var $a = $(' ');
61 | $a.attr('href', '#' + anchor);
62 | $a.text(text);
63 | var $li = $(' ');
64 | $li.append($a);
65 | return $li;
66 | },
67 |
68 | generateNavItem: function(headingEl) {
69 | var anchor = this.generateAnchor(headingEl);
70 | var $heading = $(headingEl);
71 | var text = $heading.data('toc-text') || $heading.text();
72 | return this.generateNavEl(anchor, text);
73 | },
74 |
75 | // Find the first heading level (``, then ``, etc.) that has more than one element. Defaults to 1 (for ``).
76 | getTopLevel: function($scope) {
77 | for (var i = 1; i <= 6; i++) {
78 | var $headings = this.findOrFilter($scope, 'h' + i);
79 | if ($headings.length > 1) {
80 | return i;
81 | }
82 | }
83 |
84 | return 1;
85 | },
86 |
87 | // returns the elements for the top level, and the next below it
88 | getHeadings: function($scope, topLevel) {
89 | var topSelector = 'h' + topLevel;
90 |
91 | var secondaryLevel = topLevel + 1;
92 | var secondarySelector = 'h' + secondaryLevel;
93 |
94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector);
95 | },
96 |
97 | getNavLevel: function(el) {
98 | return parseInt(el.tagName.charAt(1), 10);
99 | },
100 |
101 | populateNav: function($topContext, topLevel, $headings) {
102 | var $context = $topContext;
103 | var $prevNav;
104 |
105 | var helpers = this;
106 | $headings.each(function(i, el) {
107 | var $newNav = helpers.generateNavItem(el);
108 | var navLevel = helpers.getNavLevel(el);
109 |
110 | // determine the proper $context
111 | if (navLevel === topLevel) {
112 | // use top level
113 | $context = $topContext;
114 | } else if ($prevNav && $context === $topContext) {
115 | // create a new level of the tree and switch to it
116 | $context = helpers.createChildNavList($prevNav);
117 | } // else use the current $context
118 |
119 | $context.append($newNav);
120 |
121 | $prevNav = $newNav;
122 | });
123 | },
124 |
125 | parseOps: function(arg) {
126 | var opts;
127 | if (arg.jquery) {
128 | opts = {
129 | $nav: arg
130 | };
131 | } else {
132 | opts = arg;
133 | }
134 | opts.$scope = opts.$scope || $(document.body);
135 | return opts;
136 | }
137 | },
138 |
139 | // accepts a jQuery object, or an options object
140 | init: function(opts) {
141 | opts = this.helpers.parseOps(opts);
142 |
143 | // ensure that the data attribute is in place for styling
144 | opts.$nav.attr('data-toggle', 'toc');
145 |
146 | var $topContext = this.helpers.createChildNavList(opts.$nav);
147 | var topLevel = this.helpers.getTopLevel(opts.$scope);
148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel);
149 | this.helpers.populateNav($topContext, topLevel, $headings);
150 | }
151 | };
152 |
153 | $(function() {
154 | $('nav[data-toggle="toc"]').each(function(i, el) {
155 | var $nav = $(el);
156 | Toc.init($nav);
157 | });
158 | });
159 | })();
160 |
--------------------------------------------------------------------------------
/docs/docsearch.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | // register a handler to move the focus to the search bar
4 | // upon pressing shift + "/" (i.e. "?")
5 | $(document).on('keydown', function(e) {
6 | if (e.shiftKey && e.keyCode == 191) {
7 | e.preventDefault();
8 | $("#search-input").focus();
9 | }
10 | });
11 |
12 | $(document).ready(function() {
13 | // do keyword highlighting
14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */
15 | var mark = function() {
16 |
17 | var referrer = document.URL ;
18 | var paramKey = "q" ;
19 |
20 | if (referrer.indexOf("?") !== -1) {
21 | var qs = referrer.substr(referrer.indexOf('?') + 1);
22 | var qs_noanchor = qs.split('#')[0];
23 | var qsa = qs_noanchor.split('&');
24 | var keyword = "";
25 |
26 | for (var i = 0; i < qsa.length; i++) {
27 | var currentParam = qsa[i].split('=');
28 |
29 | if (currentParam.length !== 2) {
30 | continue;
31 | }
32 |
33 | if (currentParam[0] == paramKey) {
34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20"));
35 | }
36 | }
37 |
38 | if (keyword !== "") {
39 | $(".contents").unmark({
40 | done: function() {
41 | $(".contents").mark(keyword);
42 | }
43 | });
44 | }
45 | }
46 | };
47 |
48 | mark();
49 | });
50 | });
51 |
52 | /* Search term highlighting ------------------------------*/
53 |
54 | function matchedWords(hit) {
55 | var words = [];
56 |
57 | var hierarchy = hit._highlightResult.hierarchy;
58 | // loop to fetch from lvl0, lvl1, etc.
59 | for (var idx in hierarchy) {
60 | words = words.concat(hierarchy[idx].matchedWords);
61 | }
62 |
63 | var content = hit._highlightResult.content;
64 | if (content) {
65 | words = words.concat(content.matchedWords);
66 | }
67 |
68 | // return unique words
69 | var words_uniq = [...new Set(words)];
70 | return words_uniq;
71 | }
72 |
73 | function updateHitURL(hit) {
74 |
75 | var words = matchedWords(hit);
76 | var url = "";
77 |
78 | if (hit.anchor) {
79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor;
80 | } else {
81 | url = hit.url + '?q=' + escape(words.join(" "));
82 | }
83 |
84 | return url;
85 | }
86 |
--------------------------------------------------------------------------------
/docs/extra.css:
--------------------------------------------------------------------------------
1 |
2 | .dl-horizontal dt {
3 | white-space: normal;
4 | }
--------------------------------------------------------------------------------
/docs/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/pkgdown.css:
--------------------------------------------------------------------------------
1 | /* Sticky footer */
2 |
3 | /**
4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/
5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css
6 | *
7 | * .Site -> body > .container
8 | * .Site-content -> body > .container .row
9 | * .footer -> footer
10 | *
11 | * Key idea seems to be to ensure that .container and __all its parents__
12 | * have height set to 100%
13 | *
14 | */
15 |
16 | html, body {
17 | height: 100%;
18 | }
19 |
20 | body {
21 | position: relative;
22 | }
23 |
24 | body > .container {
25 | display: flex;
26 | height: 100%;
27 | flex-direction: column;
28 | }
29 |
30 | body > .container .row {
31 | flex: 1 0 auto;
32 | }
33 |
34 | footer {
35 | margin-top: 45px;
36 | padding: 35px 0 36px;
37 | border-top: 1px solid #e5e5e5;
38 | color: #666;
39 | display: flex;
40 | flex-shrink: 0;
41 | }
42 | footer p {
43 | margin-bottom: 0;
44 | }
45 | footer div {
46 | flex: 1;
47 | }
48 | footer .pkgdown {
49 | text-align: right;
50 | }
51 | footer p {
52 | margin-bottom: 0;
53 | }
54 |
55 | img.icon {
56 | float: right;
57 | }
58 |
59 | img {
60 | max-width: 100%;
61 | }
62 |
63 | /* Fix bug in bootstrap (only seen in firefox) */
64 | summary {
65 | display: list-item;
66 | }
67 |
68 | /* Typographic tweaking ---------------------------------*/
69 |
70 | .contents .page-header {
71 | margin-top: calc(-60px + 1em);
72 | }
73 |
74 | dd {
75 | margin-left: 3em;
76 | }
77 |
78 | /* Section anchors ---------------------------------*/
79 |
80 | a.anchor {
81 | margin-left: -30px;
82 | display:inline-block;
83 | width: 30px;
84 | height: 30px;
85 | visibility: hidden;
86 |
87 | background-image: url(./link.svg);
88 | background-repeat: no-repeat;
89 | background-size: 20px 20px;
90 | background-position: center center;
91 | }
92 |
93 | .hasAnchor:hover a.anchor {
94 | visibility: visible;
95 | }
96 |
97 | @media (max-width: 767px) {
98 | .hasAnchor:hover a.anchor {
99 | visibility: hidden;
100 | }
101 | }
102 |
103 |
104 | /* Fixes for fixed navbar --------------------------*/
105 |
106 | .contents h1, .contents h2, .contents h3, .contents h4 {
107 | padding-top: 60px;
108 | margin-top: -40px;
109 | }
110 |
111 | /* Navbar submenu --------------------------*/
112 |
113 | .dropdown-submenu {
114 | position: relative;
115 | }
116 |
117 | .dropdown-submenu>.dropdown-menu {
118 | top: 0;
119 | left: 100%;
120 | margin-top: -6px;
121 | margin-left: -1px;
122 | border-radius: 0 6px 6px 6px;
123 | }
124 |
125 | .dropdown-submenu:hover>.dropdown-menu {
126 | display: block;
127 | }
128 |
129 | .dropdown-submenu>a:after {
130 | display: block;
131 | content: " ";
132 | float: right;
133 | width: 0;
134 | height: 0;
135 | border-color: transparent;
136 | border-style: solid;
137 | border-width: 5px 0 5px 5px;
138 | border-left-color: #cccccc;
139 | margin-top: 5px;
140 | margin-right: -10px;
141 | }
142 |
143 | .dropdown-submenu:hover>a:after {
144 | border-left-color: #ffffff;
145 | }
146 |
147 | .dropdown-submenu.pull-left {
148 | float: none;
149 | }
150 |
151 | .dropdown-submenu.pull-left>.dropdown-menu {
152 | left: -100%;
153 | margin-left: 10px;
154 | border-radius: 6px 0 6px 6px;
155 | }
156 |
157 | /* Sidebar --------------------------*/
158 |
159 | #pkgdown-sidebar {
160 | margin-top: 30px;
161 | position: -webkit-sticky;
162 | position: sticky;
163 | top: 70px;
164 | }
165 |
166 | #pkgdown-sidebar h2 {
167 | font-size: 1.5em;
168 | margin-top: 1em;
169 | }
170 |
171 | #pkgdown-sidebar h2:first-child {
172 | margin-top: 0;
173 | }
174 |
175 | #pkgdown-sidebar .list-unstyled li {
176 | margin-bottom: 0.5em;
177 | }
178 |
179 | /* bootstrap-toc tweaks ------------------------------------------------------*/
180 |
181 | /* All levels of nav */
182 |
183 | nav[data-toggle='toc'] .nav > li > a {
184 | padding: 4px 20px 4px 6px;
185 | font-size: 1.5rem;
186 | font-weight: 400;
187 | color: inherit;
188 | }
189 |
190 | nav[data-toggle='toc'] .nav > li > a:hover,
191 | nav[data-toggle='toc'] .nav > li > a:focus {
192 | padding-left: 5px;
193 | color: inherit;
194 | border-left: 1px solid #878787;
195 | }
196 |
197 | nav[data-toggle='toc'] .nav > .active > a,
198 | nav[data-toggle='toc'] .nav > .active:hover > a,
199 | nav[data-toggle='toc'] .nav > .active:focus > a {
200 | padding-left: 5px;
201 | font-size: 1.5rem;
202 | font-weight: 400;
203 | color: inherit;
204 | border-left: 2px solid #878787;
205 | }
206 |
207 | /* Nav: second level (shown on .active) */
208 |
209 | nav[data-toggle='toc'] .nav .nav {
210 | display: none; /* Hide by default, but at >768px, show it */
211 | padding-bottom: 10px;
212 | }
213 |
214 | nav[data-toggle='toc'] .nav .nav > li > a {
215 | padding-left: 16px;
216 | font-size: 1.35rem;
217 | }
218 |
219 | nav[data-toggle='toc'] .nav .nav > li > a:hover,
220 | nav[data-toggle='toc'] .nav .nav > li > a:focus {
221 | padding-left: 15px;
222 | }
223 |
224 | nav[data-toggle='toc'] .nav .nav > .active > a,
225 | nav[data-toggle='toc'] .nav .nav > .active:hover > a,
226 | nav[data-toggle='toc'] .nav .nav > .active:focus > a {
227 | padding-left: 15px;
228 | font-weight: 500;
229 | font-size: 1.35rem;
230 | }
231 |
232 | /* orcid ------------------------------------------------------------------- */
233 |
234 | .orcid {
235 | font-size: 16px;
236 | color: #A6CE39;
237 | /* margins are required by official ORCID trademark and display guidelines */
238 | margin-left:4px;
239 | margin-right:4px;
240 | vertical-align: middle;
241 | }
242 |
243 | /* Reference index & topics ----------------------------------------------- */
244 |
245 | .ref-index th {font-weight: normal;}
246 |
247 | .ref-index td {vertical-align: top;}
248 | .ref-index .icon {width: 40px;}
249 | .ref-index .alias {width: 40%;}
250 | .ref-index-icons .alias {width: calc(40% - 40px);}
251 | .ref-index .title {width: 60%;}
252 |
253 | .ref-arguments th {text-align: right; padding-right: 10px;}
254 | .ref-arguments th, .ref-arguments td {vertical-align: top;}
255 | .ref-arguments .name {width: 20%;}
256 | .ref-arguments .desc {width: 80%;}
257 |
258 | /* Nice scrolling for wide elements --------------------------------------- */
259 |
260 | table {
261 | display: block;
262 | overflow: auto;
263 | }
264 |
265 | /* Syntax highlighting ---------------------------------------------------- */
266 |
267 | pre {
268 | word-wrap: normal;
269 | word-break: normal;
270 | border: 1px solid #eee;
271 | }
272 |
273 | pre, code {
274 | background-color: #f8f8f8;
275 | color: #333;
276 | }
277 |
278 | pre code {
279 | overflow: auto;
280 | word-wrap: normal;
281 | white-space: pre;
282 | }
283 |
284 | pre .img {
285 | margin: 5px 0;
286 | }
287 |
288 | pre .img img {
289 | background-color: #fff;
290 | display: block;
291 | height: auto;
292 | }
293 |
294 | code a, pre a {
295 | color: #375f84;
296 | }
297 |
298 | a.sourceLine:hover {
299 | text-decoration: none;
300 | }
301 |
302 | .fl {color: #1514b5;}
303 | .fu {color: #000000;} /* function */
304 | .ch,.st {color: #036a07;} /* string */
305 | .kw {color: #264D66;} /* keyword */
306 | .co {color: #888888;} /* comment */
307 |
308 | .message { color: black; font-weight: bolder;}
309 | .error { color: orange; font-weight: bolder;}
310 | .warning { color: #6A0366; font-weight: bolder;}
311 |
312 | /* Clipboard --------------------------*/
313 |
314 | .hasCopyButton {
315 | position: relative;
316 | }
317 |
318 | .btn-copy-ex {
319 | position: absolute;
320 | right: 0;
321 | top: 0;
322 | visibility: hidden;
323 | }
324 |
325 | .hasCopyButton:hover button.btn-copy-ex {
326 | visibility: visible;
327 | }
328 |
329 | /* headroom.js ------------------------ */
330 |
331 | .headroom {
332 | will-change: transform;
333 | transition: transform 200ms linear;
334 | }
335 | .headroom--pinned {
336 | transform: translateY(0%);
337 | }
338 | .headroom--unpinned {
339 | transform: translateY(-100%);
340 | }
341 |
342 | /* mark.js ----------------------------*/
343 |
344 | mark {
345 | background-color: rgba(255, 255, 51, 0.5);
346 | border-bottom: 2px solid rgba(255, 153, 51, 0.3);
347 | padding: 1px;
348 | }
349 |
350 | /* vertical spacing after htmlwidgets */
351 | .html-widget {
352 | margin-bottom: 10px;
353 | }
354 |
355 | /* fontawesome ------------------------ */
356 |
357 | .fab {
358 | font-family: "Font Awesome 5 Brands" !important;
359 | }
360 |
361 | /* don't display links in code chunks when printing */
362 | /* source: https://stackoverflow.com/a/10781533 */
363 | @media print {
364 | code a:link:after, code a:visited:after {
365 | content: "";
366 | }
367 | }
368 |
--------------------------------------------------------------------------------
/docs/pkgdown.js:
--------------------------------------------------------------------------------
1 | /* http://gregfranko.com/blog/jquery-best-practices/ */
2 | (function($) {
3 | $(function() {
4 |
5 | $('.navbar-fixed-top').headroom();
6 |
7 | $('body').css('padding-top', $('.navbar').height() + 10);
8 | $(window).resize(function(){
9 | $('body').css('padding-top', $('.navbar').height() + 10);
10 | });
11 |
12 | $('[data-toggle="tooltip"]').tooltip();
13 |
14 | var cur_path = paths(location.pathname);
15 | var links = $("#navbar ul li a");
16 | var max_length = -1;
17 | var pos = -1;
18 | for (var i = 0; i < links.length; i++) {
19 | if (links[i].getAttribute("href") === "#")
20 | continue;
21 | // Ignore external links
22 | if (links[i].host !== location.host)
23 | continue;
24 |
25 | var nav_path = paths(links[i].pathname);
26 |
27 | var length = prefix_length(nav_path, cur_path);
28 | if (length > max_length) {
29 | max_length = length;
30 | pos = i;
31 | }
32 | }
33 |
34 | // Add class to parent , and enclosing if in dropdown
35 | if (pos >= 0) {
36 | var menu_anchor = $(links[pos]);
37 | menu_anchor.parent().addClass("active");
38 | menu_anchor.closest("li.dropdown").addClass("active");
39 | }
40 | });
41 |
42 | function paths(pathname) {
43 | var pieces = pathname.split("/");
44 | pieces.shift(); // always starts with /
45 |
46 | var end = pieces[pieces.length - 1];
47 | if (end === "index.html" || end === "")
48 | pieces.pop();
49 | return(pieces);
50 | }
51 |
52 | // Returns -1 if not found
53 | function prefix_length(needle, haystack) {
54 | if (needle.length > haystack.length)
55 | return(-1);
56 |
57 | // Special case for length-0 haystack, since for loop won't run
58 | if (haystack.length === 0) {
59 | return(needle.length === 0 ? 0 : -1);
60 | }
61 |
62 | for (var i = 0; i < haystack.length; i++) {
63 | if (needle[i] != haystack[i])
64 | return(i);
65 | }
66 |
67 | return(haystack.length);
68 | }
69 |
70 | /* Clipboard --------------------------*/
71 |
72 | function changeTooltipMessage(element, msg) {
73 | var tooltipOriginalTitle=element.getAttribute('data-original-title');
74 | element.setAttribute('data-original-title', msg);
75 | $(element).tooltip('show');
76 | element.setAttribute('data-original-title', tooltipOriginalTitle);
77 | }
78 |
79 | if(ClipboardJS.isSupported()) {
80 | $(document).ready(function() {
81 | var copyButton = " ";
82 |
83 | $(".examples, div.sourceCode").addClass("hasCopyButton");
84 |
85 | // Insert copy buttons:
86 | $(copyButton).prependTo(".hasCopyButton");
87 |
88 | // Initialize tooltips:
89 | $('.btn-copy-ex').tooltip({container: 'body'});
90 |
91 | // Initialize clipboard:
92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', {
93 | text: function(trigger) {
94 | return trigger.parentNode.textContent;
95 | }
96 | });
97 |
98 | clipboardBtnCopies.on('success', function(e) {
99 | changeTooltipMessage(e.trigger, 'Copied!');
100 | e.clearSelection();
101 | });
102 |
103 | clipboardBtnCopies.on('error', function() {
104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy');
105 | });
106 | });
107 | }
108 | })(window.jQuery || window.$)
109 |
--------------------------------------------------------------------------------
/docs/pkgdown.yml:
--------------------------------------------------------------------------------
1 | pandoc: '2.5'
2 | pkgdown: 1.5.1
3 | pkgdown_sha: ~
4 | articles: []
5 | last_built: 2020-06-02T03:22Z
6 |
7 |
--------------------------------------------------------------------------------
/docs/reference/DIM.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Helpers for working with 1-d arrays — DIM • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
122 |
123 |
124 |
DIM()
is to dim()
as NROW()
is to nrow()
. That is, it is identical to
125 | dim()
in most cases except if the input is a bare atomic vector with no
126 | dim
attribute, in which case, the length of the vector is returned instead
127 | of NULL
.
128 |
DROP
first calls base::drop
and then completely removes the dim
129 | attribute if the result is a 1-d array
130 |
131 |
132 |
DIM (x )
133 |
134 | DROP (x )
135 |
136 |
Arguments
137 |
138 |
139 |
140 | x
141 | an R vector, potentially with a dim attribute
142 |
143 |
144 |
145 |
Value
146 |
147 |
For DIM
, the dim
attribute, or if that's not found, then length(x)
148 |
For DROP
an array with 2 or more axes, or a vector with no dim
149 | attributes.
150 |
151 |
Examples
152 |
#> NULL
#> [1] 3
154 | DIM (x )
#> [1] 3
#> [1] 3
#> int [1:3(1d)] 1 2 3
#> int [1:3] 1 2 3
157 |
158 |
163 |
164 |
165 |
166 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
--------------------------------------------------------------------------------
/docs/reference/array2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Make or reshape an array with C-style (row-major) semantics — array2 • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
119 |
120 |
121 |
These functions reshape or make an array using C-style, row-major semantics.
122 | The returned array is still R's native F-style, (meaning, the underlying
123 | vector has been reordered).
124 |
125 |
126 |
array2 (data , dim = length (data ), dimnames = NULL )
127 |
128 | matrix2 (... )
129 |
130 | dim2 (x ) <- value
131 |
132 | set_dim2 (... )
133 |
134 |
Arguments
135 |
136 |
137 |
138 | data
139 | what to fill the array with
140 |
141 |
142 | dim
143 | numeric vector of dimensions
144 |
145 |
146 | dimnames
147 | a list of dimnames, must be the same length as dims
148 |
149 |
150 | ...
151 | passed on to set_dim()
152 |
153 |
154 | x
155 | object to set dimensions on (array or atomic vector)
156 |
157 |
158 | value
159 | a numeric (integerish) vector of new dimensions
160 |
161 |
162 |
163 |
Details
164 |
165 |
Other than the C-style semantics, these functions behave identically to their
166 | counterparts (array2()
behaves identically to array()
, `dim2<-`()
167 | to `dim<-`()
). set_dim2()
is just a wrapper around set_dim(..., order = "C")
.
168 |
See examples for a drop-in pure R replacement to reticulate::array_reshape()
169 |
170 |
Examples
171 |
#> [,1] [,2]
172 | #> [1,] 1 3
173 | #> [2,] 2 4
#> [,1] [,2]
174 | #> [1,] 1 2
175 | #> [2,] 3 4
#> [,1] [,2]
179 | #> [1,] 1 2
180 | #> [2,] 3 4
181 |
182 |
187 |
188 |
189 |
190 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/docs/reference/drop_dimnames.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Drop dimnames — drop_dimnames • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
118 |
119 |
120 |
A pipe-friendly wrapper for dim(x) <- NULL
and dimnames(x) <- NULL
or, if
121 | which_dim
is not NULL
, dimnames(x)[which_dim] <- list(NULL)
122 |
123 |
124 |
drop_dimnames (x , which_dim = NULL , keep_axis_names = FALSE )
125 |
126 | drop_dim (x )
127 |
128 | drop_dim2 (x )
129 |
130 |
Arguments
131 |
132 |
133 |
134 | x
135 | an object, potentially with dimnames
136 |
137 |
138 | which_dim
139 | If NULL
(the default) then all dimnames are dropped. If
140 | integer vector, then dimnames only at the specified dimensions are dropped.
141 |
142 |
143 | keep_axis_names
144 | TRUE or FALSE, whether to preserve the axis names when
145 | dropping the dimnames
146 |
147 |
148 |
149 |
150 |
151 |
156 |
157 |
158 |
159 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/docs/reference/expand_dims.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Expand the shape of an array — expand_dims • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
119 |
120 |
121 |
This is the inverse operation of base::drop()
.
122 | It is analogous to python's numpy.expand_dims()
, but vectorized on
123 | which_dim
.
124 |
125 |
126 |
expand_dims (x , which_dim = -1L )
127 |
128 |
Arguments
129 |
130 |
131 |
132 | x
133 | an array. Bare vectors are treated as 1-d arrays.
134 |
135 |
136 | which_dim
137 | numeric. Desired index position of the new axis or axes in
138 | the returned array. Negative numbers count from the back. Can be any
139 | length.Throws a warning if any duplicates are provided.
140 |
141 |
142 |
143 |
Value
144 |
145 |
the array x
with new dim
146 |
147 |
Examples
148 |
#> [1] 2 3 4
#> [1] 2 3 4 1
#> [1] 2 1 3 4
#> [1] 1 1 2 3 4
#> [1] 1 2 3 4 1
#> [1] 2 3 4 1 1 1
#> [1] 2 3 4 1 1 1
#> Error in expand_dims(x, -6) :
152 | #> Implicit additional dims for expansion with negative indexes not supported
#> [1] 1 1 1 2 3 4
155 |
156 |
161 |
162 |
163 |
164 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/docs/reference/modify_along_dim.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Modify an array by mapping over 1 or more dimensions — modify_along_dim • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
119 |
120 |
121 |
This function can be thought of as a version of base::apply()
that is
122 | guaranteed to return a object of the same dimensions as it was input. It also
123 | generally preserves attributes, as it's built on top of [<-
.
124 |
125 |
126 |
modify_along_dim (X , which_dim , .f , ... )
127 |
128 | modify_along_rows (X , .f , ... )
129 |
130 | modify_along_cols (X , .f , ... )
131 |
132 |
Arguments
133 |
134 |
135 |
136 | X
137 | An array, or a list of arrays
138 |
139 |
140 | which_dim
141 | integer vector of dimensions to modify at
142 |
143 |
144 | .f
145 | a function or formula defining a function(same semantics as
146 | purrr::map()
). The function must return either an array the same shape
147 | as it was passed, a vector of the same length, or a scalar, although the
148 | type of the returned object does not need to be the same as was passed in.
149 |
150 |
151 | ...
152 | passed on to .f()
153 |
154 |
155 |
156 |
Value
157 |
158 |
An array, or if X
was a list, a list of arrays of the same shape as
159 | was passed in.
160 |
161 |
Examples
162 |
#> , , 1
164 | #>
165 | #> [,1] [,2]
166 | #> [1,] 1.5 1.5
167 | #>
168 | #> , , 2
169 | #>
170 | #> [,1] [,2]
171 | #> [1,] 3.5 3.5
172 | #>
173 | #> , , 3
174 | #>
175 | #> [,1] [,2]
176 | #> [1,] 5.5 5.5
177 | #>
#> , , 1
178 | #>
179 | #> [,1] [,2]
180 | #> [1,] 0.6666667 1.333333
181 | #>
182 | #> , , 2
183 | #>
184 | #> [,1] [,2]
185 | #> [1,] 0.8571429 1.142857
186 | #>
187 | #> , , 3
188 | #>
189 | #> [,1] [,2]
190 | #> [1,] 0.9090909 1.090909
191 | #>
192 |
193 |
198 |
199 |
200 |
201 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
--------------------------------------------------------------------------------
/docs/reference/ndim.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Length of DIM()
— ndim • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
117 |
118 |
119 |
Returns the number of dimensions, or 1 for an atomic vector.
120 |
121 |
122 |
ndim (x )
123 |
124 |
Arguments
125 |
126 |
127 |
128 | x
129 | a matrix or atomic vector
130 |
131 |
132 |
133 |
134 |
135 |
140 |
141 |
142 |
143 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/docs/reference/seq_along_dim.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Sequence along a dimension — seq_along_dim • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
117 |
118 |
119 |
Sequence along a dimension
120 |
121 |
122 |
seq_along_dim (x , which_dim )
123 |
124 | seq_along_rows (x )
125 |
126 | seq_along_cols (x )
127 |
128 |
Arguments
129 |
130 |
131 |
132 | x
133 | a dataframe, array or vector. For seq_along_rows
, and
134 | seq_along_cols
sequence along the first and last dimensions,
135 | respectively. Atomic vectors are treated as 1 dimensional
136 | arrays (i.e., seq_along_rows
is equivalent to seq_along
when x
is an
137 | atomic vector or list).
138 |
139 |
140 | which_dim
141 | a scalar integer or character string, specifying which
142 | dimension to generate a sequence for. Negative numbers count from the back.
143 |
144 |
145 |
146 |
Value
147 |
148 |
a vector of integers 1:nrow(x), safe for use in for
loops and
149 | vectorized equivalents.
150 |
151 |
Examples
152 |
#> mpg cyl disp hp drat wt qsec vs am gear carb
154 | #> Mazda RX4 21 6 160 110 3.9 2.62 16.46 0 1 4 4
155 | #> mpg cyl disp hp drat wt qsec vs am gear carb
156 | #> Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
157 | #> mpg cyl disp hp drat wt qsec vs am gear carb
158 | #> Datsun 710 22.8 4 108 93 3.85 2.32 18.61 1 1 4 1
159 | #> mpg cyl disp hp drat wt qsec vs am gear carb
160 | #> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#> [1] TRUE
163 |
164 |
165 |
170 |
171 |
172 |
173 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
--------------------------------------------------------------------------------
/docs/reference/set_as_rows.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Reshape an array to send a dimension forward or back — set_as_rows • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
117 |
118 |
119 |
Reshape an array to send a dimension forward or back
120 |
121 |
122 |
set_as_rows (X , which_dim )
123 |
124 | set_as_cols (X , which_dim )
125 |
126 |
Arguments
127 |
128 |
129 |
130 | X
131 | an array
132 |
133 |
134 | which_dim
135 | scalar integer or string, which dim to bring forward.
136 | Negative numbers count from the back
137 | This is a powered by base::aperm()
.
138 |
139 |
140 |
141 |
Value
142 |
143 |
a reshaped array
144 |
See also
145 |
146 |
147 |
148 |
Examples
149 |
154 |
155 |
160 |
161 |
162 |
163 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
--------------------------------------------------------------------------------
/docs/reference/shuffle_rows.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Shuffle along the first dimension multiple arrays in sync — shuffle_rows • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
117 |
118 |
119 |
Shuffle along the first dimension multiple arrays in sync
120 |
121 |
122 |
shuffle_rows (... )
123 |
124 |
Arguments
125 |
126 |
127 |
128 | ...
129 | arrays of various dimensions (vectors and data.frames OK too)
130 |
131 |
132 |
133 |
Value
134 |
135 |
A list of objects passed on to ...
, or if a single object was
136 | supplied, then the single object shuffled
137 |
138 |
Examples
139 |
157 |
158 |
163 |
164 |
165 |
166 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
--------------------------------------------------------------------------------
/docs/reference/t.array.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | transpose an array — t.array • listarrays
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
117 |
118 |
119 |
transpose an array
120 |
121 |
122 |
# S3 method for array
123 | t (x )
124 |
125 |
Arguments
126 |
127 |
128 |
129 | x
130 | an array
131 | This reverses the dimensions of an array
132 |
133 |
134 |
135 |
136 |
Examples
137 |
142 |
143 |
148 |
149 |
150 |
151 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/listarrays.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | AutoAppendNewline: Yes
16 | StripTrailingWhitespace: Yes
17 |
18 | BuildType: Package
19 | PackageUseDevtools: Yes
20 | PackageInstallArgs: --no-multiarch --with-keep.source
21 | PackageRoxygenize: rd,collate,namespace
22 |
23 | QuitChildProcessesOnExit: Yes
24 |
--------------------------------------------------------------------------------
/man/DIM.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{DIM}
4 | \alias{DIM}
5 | \alias{DROP}
6 | \title{Helpers for working with 1-d arrays}
7 | \usage{
8 | DIM(x)
9 |
10 | DROP(x)
11 | }
12 | \arguments{
13 | \item{x}{an R vector, potentially with a dim attribute}
14 | }
15 | \value{
16 | For \code{DIM}, the \code{dim} attribute, or if that's not found, then \code{length(x)}
17 |
18 | For \code{DROP} an array with 2 or more axes, or a vector with no \code{dim}
19 | attributes.
20 | }
21 | \description{
22 | \code{DIM()} is to \code{dim()} as \code{NROW()} is to \code{nrow()}. That is, it is identical to
23 | \code{dim()} in most cases except if the input is a bare atomic vector with no
24 | \code{dim} attribute, in which case, the length of the vector is returned instead
25 | of \code{NULL}.
26 |
27 | \code{DROP} first calls \code{base::drop} and then completely removes the \code{dim}
28 | attribute if the result is a 1-d array
29 | }
30 | \examples{
31 | x <- 1:3
32 | dim(x)
33 | dim(array(x))
34 |
35 | DIM(x)
36 | DIM(array(x))
37 |
38 | x <- array(1:3)
39 | str(drop(x))
40 | str(DROP(x))
41 | }
42 |
--------------------------------------------------------------------------------
/man/array2.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/dim2.R
3 | \name{array2}
4 | \alias{array2}
5 | \alias{matrix2}
6 | \alias{dim2<-}
7 | \alias{set_dim2}
8 | \title{Make or reshape an array with C-style (row-major) semantics}
9 | \usage{
10 | array2(data, dim = length(data), dimnames = NULL)
11 |
12 | matrix2(...)
13 |
14 | dim2(x) <- value
15 |
16 | set_dim2(...)
17 | }
18 | \arguments{
19 | \item{data}{what to fill the array with}
20 |
21 | \item{dim}{numeric vector of dimensions}
22 |
23 | \item{dimnames}{a list of dimnames, must be the same length as \code{dims}}
24 |
25 | \item{...}{passed on to \code{set_dim()}}
26 |
27 | \item{x}{object to set dimensions on (array or atomic vector)}
28 |
29 | \item{value}{a numeric (integerish) vector of new dimensions}
30 | }
31 | \description{
32 | These functions reshape or make an array using C-style, row-major semantics.
33 | The returned array is still R's native F-style, (meaning, the underlying
34 | vector has been reordered).
35 | }
36 | \details{
37 | Other than the C-style semantics, these functions behave identically to their
38 | counterparts (\code{array2()} behaves identically to \code{array()}, \code{`dim2<-`()}
39 | to \code{`dim<-`()}). \code{set_dim2()} is just a wrapper around \code{set_dim(..., order = "C")}.
40 |
41 | See examples for a drop-in pure R replacement to \code{reticulate::array_reshape()}
42 | }
43 | \examples{
44 | array(1:4, c(2,2))
45 | array2(1:4, c(2,2))
46 |
47 | # for a drop-in replacement to reticulate::array_reshape
48 | array_reshape <- listarrays:::array_reshape
49 | array_reshape(1:4, c(2,2))
50 | }
51 |
--------------------------------------------------------------------------------
/man/bind-arrays.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/bind.R
3 | \name{bind_as_dim}
4 | \alias{bind_as_dim}
5 | \alias{bind_as_rows}
6 | \alias{bind_as_cols}
7 | \alias{bind_on_dim}
8 | \alias{bind_on_rows}
9 | \alias{bind_on_cols}
10 | \title{Bind arrays along a specified dimension}
11 | \usage{
12 | bind_as_dim(list_of_arrays, which_dim)
13 |
14 | bind_as_rows(...)
15 |
16 | bind_as_cols(...)
17 |
18 | bind_on_dim(list_of_arrays, which_dim)
19 |
20 | bind_on_rows(...)
21 |
22 | bind_on_cols(...)
23 | }
24 | \arguments{
25 | \item{list_of_arrays}{a list of arrays. All arrays must be of the same
26 | dimension. NULL's in place of arrays are automatically dropped.}
27 |
28 | \item{which_dim}{Scalar integer specifying the index position of where to
29 | introduce the new dimension to introduce. Negative numbers count from the
30 | back. For example, given a 3 dimensional array, \code{-1}, is equivalent to \code{3},
31 | \code{-2} to \code{2} and \code{-3} to \code{1}.}
32 |
33 | \item{...}{Arrays to be bound, specified individually or supplied as a single
34 | list}
35 | }
36 | \value{
37 | An array, with one additional dimension.
38 | }
39 | \description{
40 | \verb{bind_as_*} introduces a new dimension, such that each element in
41 | \code{list_of_arrays} corresponds to one index position along the new dimension in
42 | the returned array. \verb{bind_on_*} binds all elements along an existing
43 | dimension, (meaning, the returned array has the same number of dimensions as
44 | each of the arrays in the list).
45 | }
46 | \details{
47 | \verb{bind_*_rows()} is a wrapper for the common case of \verb{bind_*_dim(X, 1)}.
48 | \verb{bind_*_cols()} is a wrapper for the common case of \verb{bind_*_dim(X, -1)}.
49 | }
50 | \examples{
51 | list_of_arrays <- replicate(10, array(1:8, dim = c(2,3,4)), FALSE)
52 |
53 | dim(list_of_arrays[[1]])
54 |
55 | # bind on a new dimension
56 | combined_as <- bind_as_rows(list_of_arrays)
57 | dim(combined_as)
58 | dim(combined_as)[1] == length(list_of_arrays)
59 |
60 | # each element in `list_of_arrays` corresponds to one "row"
61 | # (i.e., one entry in along the first dimension)
62 | for(i in seq_along(list_of_arrays))
63 | stopifnot(identical(combined_as[i,,,], list_of_arrays[[i]]))
64 |
65 | # bind on an existing dimension
66 | combined_on <- bind_on_rows(list_of_arrays)
67 | dim(combined_on)
68 | dim(combined_on)[1] == sum(sapply(list_of_arrays, function(x) dim(x)[1]))
69 | identical(list_of_arrays[[1]], combined_on[1:2,,])
70 | for (i in seq_along(list_of_arrays))
71 | stopifnot(identical(
72 | list_of_arrays[[i]], combined_on[ (1:2) + (i-1)*2,,]
73 | ))
74 |
75 | # bind on any dimension
76 | combined <- bind_as_dim(list_of_arrays, 3)
77 | dim(combined)
78 | for(i in seq_along(list_of_arrays))
79 | stopifnot(identical(combined[,,i,], list_of_arrays[[i]]))
80 | }
81 |
--------------------------------------------------------------------------------
/man/drop_dimnames.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/dimnames.R
3 | \name{drop_dimnames}
4 | \alias{drop_dimnames}
5 | \alias{drop_dim}
6 | \alias{drop_dim2}
7 | \title{Drop dimnames}
8 | \usage{
9 | drop_dimnames(x, which_dim = NULL, keep_axis_names = FALSE)
10 |
11 | drop_dim(x)
12 |
13 | drop_dim2(x)
14 | }
15 | \arguments{
16 | \item{x}{an object, potentially with dimnames}
17 |
18 | \item{which_dim}{If \code{NULL} (the default) then all dimnames are dropped. If
19 | integer vector, then dimnames only at the specified dimensions are dropped.}
20 |
21 | \item{keep_axis_names}{TRUE or FALSE, whether to preserve the axis names when
22 | dropping the dimnames}
23 | }
24 | \description{
25 | A pipe-friendly wrapper for \code{dim(x) <- NULL} and \code{dimnames(x) <- NULL} or, if
26 | \code{which_dim} is not \code{NULL}, \code{dimnames(x)[which_dim] <- list(NULL)}
27 | }
28 |
--------------------------------------------------------------------------------
/man/expand_dims.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/dim.R
3 | \name{expand_dims}
4 | \alias{expand_dims}
5 | \title{Expand the shape of an array}
6 | \usage{
7 | expand_dims(x, which_dim = -1L)
8 | }
9 | \arguments{
10 | \item{x}{an array. Bare vectors are treated as 1-d arrays.}
11 |
12 | \item{which_dim}{numeric. Desired index position of the new axis or axes in
13 | the returned array. Negative numbers count from the back. Can be any
14 | length.Throws a warning if any duplicates are provided.}
15 | }
16 | \value{
17 | the array \code{x} with new dim
18 | }
19 | \description{
20 | This is the inverse operation of \code{base::drop()}.
21 | It is analogous to python's \code{numpy.expand_dims()}, but vectorized on
22 | \code{which_dim}.
23 | }
24 | \examples{
25 | x <- array(1:24, 2:4)
26 | dim(x)
27 | dim(expand_dims(x))
28 | dim(expand_dims(x, 2))
29 | dim(expand_dims(x, c(1,2)))
30 | dim(expand_dims(x, c(1,-1)))
31 | dim(expand_dims(x, 6)) # implicitly also expands dims 4,5
32 | dim(expand_dims(x, 4:6))
33 |
34 | # error, implicit expansion with negative indexes not supported
35 | try(expand_dims(x, -6))
36 |
37 | # supply them explicitly instead
38 | dim(expand_dims(x, -(4:6)))
39 | }
40 |
--------------------------------------------------------------------------------
/man/extract_dim.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/extract.R
3 | \name{extract_dim}
4 | \alias{extract_dim}
5 | \alias{extract_rows}
6 | \alias{extract_cols}
7 | \title{Extract with \code{[} on a specified dimension}
8 | \usage{
9 | extract_dim(X, which_dim, idx, drop = NULL, depth = Inf)
10 |
11 | extract_rows(X, idx, drop = NULL, depth = Inf)
12 |
13 | extract_cols(X, idx, drop = NULL, depth = Inf)
14 | }
15 | \arguments{
16 | \item{X}{Typically, an array, but any object with a \code{[} method is accepted
17 | (e.g., dataframe, vectors)}
18 |
19 | \item{which_dim}{A scalar integer or character, specifying the dimension to
20 | extract from}
21 |
22 | \item{idx}{A numeric, boolean, or character vector to perform subsetting
23 | with.}
24 |
25 | \item{drop}{Passed on to \code{[}. If \code{NULL} (the default), then drop is omitted
26 | from the argument, and the default is used (defaults to TRUE for most
27 | objects, including arrays)}
28 |
29 | \item{depth}{Scalar number, how many levels to recurse down if \code{X} is a list
30 | of arrays. Set this if you want to explicitly treat a list as a vector
31 | (that is, a one-dimensional array). (You can alternatively set a dim
32 | attribute with \verb{dim<-} on the list to prevent recursion)}
33 | }
34 | \description{
35 | Extract with \code{[} on a specified dimension
36 | }
37 | \examples{
38 | # extract_rows is useful to keep the same code path for arrays of various sizes
39 | X <- array(1:8, c(4, 3, 2))
40 | y <- c("a", "b", "c", "d")
41 | (Y <- onehot(y))
42 |
43 | extract_rows(X, 2)
44 | extract_rows(Y, 2)
45 | extract_rows(y, 2)
46 |
47 | library(zeallot)
48 | c(X2, Y2, y2) \%<-\% extract_rows(list(X, Y, y), 2)
49 | X2
50 | Y2
51 | y2
52 | }
53 |
--------------------------------------------------------------------------------
/man/map_along_dim.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/map.R
3 | \name{map_along_dim}
4 | \alias{map_along_dim}
5 | \alias{map_along_rows}
6 | \alias{map_along_cols}
7 | \title{Apply a function across subsets along an array dimension}
8 | \usage{
9 | map_along_dim(X, .dim, .f, ...)
10 |
11 | map_along_rows(X, .f, ...)
12 |
13 | map_along_cols(X, .f, ...)
14 | }
15 | \arguments{
16 | \item{X}{an R array}
17 |
18 | \item{.dim}{which dimension to map along. Passed on to \code{\link[=split_along_dim]{split_along_dim()}},
19 | and accepts all the same inputs. Valid inputs include
20 | \itemize{
21 | \item positive integers (index position(s) of dimension),
22 | \item negative integers (index positions(s) of dimensions, counting from the back), or
23 | \item character vector (corresponding to array dimnames)
24 | }}
25 |
26 | \item{.f}{A function, string of a function name, or \code{purrr} style compact lambda syntax (e.g, \code{~.x + 1})}
27 |
28 | \item{...}{passed on to \code{.f()}}
29 | }
30 | \value{
31 | An R list
32 | }
33 | \description{
34 | \code{map_along_dim(X, dim, func)} is a simple wrapper around \code{split_along_dim(X, dim) \%>\% map(func)}. It is conceptually and functionally equivalent to
35 | \code{base::apply()}, with the following key differences:
36 | \itemize{
37 | \item it is guaranteed to return a list (\code{base::apply()} attempts to simplify the
38 | output to an array, sometimes unsuccessfully, making the output unstable)
39 | \item it accepts the compact lambda notation \code{~.x} just like in \code{\link[purrr:map]{purrr::map}}
40 | (and \code{\link[=modify_along_dim]{modify_along_dim()}})
41 | }
42 | }
43 | \examples{
44 | X <- matrix2(letters[1:15], ncol = 3)
45 |
46 | apply(X, 1, function(x) paste(x, collapse = "")) # simplifies to a vector
47 | map_along_dim(X, 1, ~paste(.x, collapse = "")) # returns a list
48 |
49 | identical(
50 | map_along_rows(X, identity),
51 | map_along_dim(X, 1, identity)) # TRUE
52 |
53 | identical(
54 | map_along_cols(X, identity),
55 | map_along_dim(X, -1, identity)) # TRUE
56 | }
57 |
--------------------------------------------------------------------------------
/man/modify_along_dim.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/modify.R
3 | \name{modify_along_dim}
4 | \alias{modify_along_dim}
5 | \alias{modify_along_rows}
6 | \alias{modify_along_cols}
7 | \title{Modify an array by mapping over 1 or more dimensions}
8 | \usage{
9 | modify_along_dim(X, which_dim, .f, ...)
10 |
11 | modify_along_rows(X, .f, ...)
12 |
13 | modify_along_cols(X, .f, ...)
14 | }
15 | \arguments{
16 | \item{X}{An array, or a list of arrays}
17 |
18 | \item{which_dim}{integer vector of dimensions to modify at}
19 |
20 | \item{.f}{a function or formula defining a function(same semantics as
21 | \code{\link[purrr:map]{purrr::map()}}). The function must return either an array the same shape
22 | as it was passed, a vector of the same length, or a scalar, although the
23 | type of the returned object does not need to be the same as was passed in.}
24 |
25 | \item{...}{passed on to \code{.f()}}
26 | }
27 | \value{
28 | An array, or if \code{X} was a list, a list of arrays of the same shape as
29 | was passed in.
30 | }
31 | \description{
32 | This function can be thought of as a version of \code{base::apply()} that is
33 | guaranteed to return a object of the same dimensions as it was input. It also
34 | generally preserves attributes, as it's built on top of \verb{[<-}.
35 | }
36 | \examples{
37 | x <- array(1:6, 1:3)
38 | modify_along_dim(x, 3, ~mean(.x))
39 | modify_along_dim(x, 3, ~.x/mean(.x))
40 | }
41 |
--------------------------------------------------------------------------------
/man/ndim.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{ndim}
4 | \alias{ndim}
5 | \title{Length of \code{DIM()}}
6 | \usage{
7 | ndim(x)
8 | }
9 | \arguments{
10 | \item{x}{a matrix or atomic vector}
11 | }
12 | \description{
13 | Returns the number of dimensions, or 1 for an atomic vector.
14 | }
15 |
--------------------------------------------------------------------------------
/man/onehot.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/onehot.R
3 | \name{onehot_with_decoder}
4 | \alias{onehot_with_decoder}
5 | \alias{onehot}
6 | \alias{decode_onehot}
7 | \alias{onehot_decoder}
8 | \title{Convert vector to a onehot representation (binary class matrix)}
9 | \usage{
10 | onehot_with_decoder(y, order = NULL, named = TRUE)
11 |
12 | onehot(y, order = NULL, named = TRUE)
13 |
14 | decode_onehot(
15 | Y,
16 | classes = colnames(Y),
17 | n_classes = ncol(Y) \%||\% length(classes)
18 | )
19 |
20 | onehot_decoder(Y, classes = colnames(Y), n_classes = length(classes))
21 | }
22 | \arguments{
23 | \item{y}{character, factor, or numeric vector}
24 |
25 | \item{order}{\code{NULL}, \code{FALSE}, or a character vector. If \code{NULL} (the default),
26 | then levels are sorted with \code{sort()}. If \code{FALSE}, then levels are taken in
27 | order of their first appearance in \code{y}. If a character vector, then \code{order}
28 | must contain all levels found in \code{y}.}
29 |
30 | \item{named}{if the returned matrix should have column names}
31 |
32 | \item{Y}{a matrix, as returned by \code{onehot()} or similar.}
33 |
34 | \item{classes}{A character vector of class names in the order corresponding
35 | to \code{Y}'s onehot encoding. Typically, \code{colnames(Y)}. if \code{NULL}, then the
36 | decoder returns the column number.}
37 |
38 | \item{n_classes}{The total number of classes expected in \code{Y}. Used for input
39 | checking in the returned decoder, also, to reconstruct the correct
40 | dimensions if the passed in \code{Y} is missing \code{dim()} attributes.}
41 | }
42 | \value{
43 | A binary class matrix
44 | }
45 | \description{
46 | Convert vector to a onehot representation (binary class matrix)
47 | }
48 | \examples{
49 | if(require(zeallot)) {
50 | y <- letters[1:4]
51 | c(Y, decode) \%<-\% onehot_with_decoder(y)
52 | Y
53 | decode(Y)
54 | identical(y, decode(Y))
55 | decode(Y[2,,drop = TRUE])
56 | decode(Y[2,,drop = FALSE])
57 | decode(Y[2:3,])
58 |
59 | rm(Y, decode)
60 | }
61 |
62 | # more peicemeal functions
63 | Y <- onehot(y)
64 | decode_onehot(Y)
65 |
66 | # if you need to decode a matrix that lost colnames,
67 | # make your own decoder that remembers classes
68 | my_decode <- onehot_decoder(Y)
69 | colnames(Y) <- NULL
70 | my_decode(Y)
71 | decode_onehot(Y)
72 |
73 | # factor and numeric vectors also accepted
74 | onehot(factor(letters[1:4]))
75 | onehot(4:8)
76 |
77 | }
78 | \seealso{
79 | \link[keras:to_categorical]{keras::to_categorical}
80 | }
81 |
--------------------------------------------------------------------------------
/man/seq_along_dim.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/seq_along.R
3 | \name{seq_along_dim}
4 | \alias{seq_along_dim}
5 | \alias{seq_along_rows}
6 | \alias{seq_along_cols}
7 | \title{Sequence along a dimension}
8 | \usage{
9 | seq_along_dim(x, which_dim)
10 |
11 | seq_along_rows(x)
12 |
13 | seq_along_cols(x)
14 | }
15 | \arguments{
16 | \item{x}{a dataframe, array or vector. For \code{seq_along_rows}, and
17 | \code{seq_along_cols} sequence along the first and last dimensions,
18 | respectively. Atomic vectors are treated as 1 dimensional
19 | arrays (i.e., \code{seq_along_rows} is equivalent to \code{seq_along} when \code{x} is an
20 | atomic vector or list).}
21 |
22 | \item{which_dim}{a scalar integer or character string, specifying which
23 | dimension to generate a sequence for. Negative numbers count from the back.}
24 | }
25 | \value{
26 | a vector of integers 1:nrow(x), safe for use in \code{for} loops and
27 | vectorized equivalents.
28 | }
29 | \description{
30 | Sequence along a dimension
31 | }
32 | \examples{
33 | for (r in seq_along_rows(mtcars[1:4,]))
34 | print(mtcars[r,])
35 |
36 | x <- 1:3
37 | identical(seq_along_rows(x), seq_along(x))
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/man/set_as_rows.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/reshape.R
3 | \name{set_as_rows}
4 | \alias{set_as_rows}
5 | \alias{set_as_cols}
6 | \title{Reshape an array to send a dimension forward or back}
7 | \usage{
8 | set_as_rows(X, which_dim)
9 |
10 | set_as_cols(X, which_dim)
11 | }
12 | \arguments{
13 | \item{X}{an array}
14 |
15 | \item{which_dim}{scalar integer or string, which dim to bring forward.
16 | Negative numbers count from the back
17 |
18 | This is a powered by \code{base::aperm()}.}
19 | }
20 | \value{
21 | a reshaped array
22 | }
23 | \description{
24 | Reshape an array to send a dimension forward or back
25 | }
26 | \examples{
27 | x <- array(1:24, 2:4)
28 | y <- set_as_rows(x, 3)
29 |
30 | for (i in seq_along_dim(x, 3))
31 | stopifnot( identical(x[,,i], y[i,,]) )
32 | }
33 | \seealso{
34 | \code{base::aperm()} \code{set_dim()} \code{keras::array_reshape()}
35 | }
36 |
--------------------------------------------------------------------------------
/man/set_dim.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/dim.R
3 | \name{set_dim}
4 | \alias{set_dim}
5 | \title{Reshape an array}
6 | \usage{
7 | set_dim(
8 | x,
9 | new_dim,
10 | pad = getOption("listarrays.autopad_arrays_with", NULL),
11 | order = c("F", "C"),
12 | verbose = getOption("verbose")
13 | )
14 | }
15 | \arguments{
16 | \item{x}{A vector or array to set dimensions on}
17 |
18 | \item{new_dim}{The desired dimensions (an integer(ish) vector)}
19 |
20 | \item{pad}{The value to pad the vector with. \code{NULL} (the default) performs no
21 | padding.}
22 |
23 | \item{order}{whether to use row-major (C) or column major (F) style
24 | semantics. The default, "F", corresponds to the default behavior of R's
25 | \verb{dim<-()}, while "C" corresponds to the default behavior of
26 | \code{reticulate::array_reshape()}, numpy, reshaping semantics commonly
27 | encountered in the python world.}
28 |
29 | \item{verbose}{Whether to emit a message if padding. By default, \code{FALSE}.}
30 | }
31 | \value{
32 | Object with dimensions set
33 | }
34 | \description{
35 | Pipe friendly \verb{dim<-()}, with option to pad to necessary length. Also allows
36 | for filling the array using C style row-major semantics.
37 | }
38 | \examples{
39 | set_dim(1:10, c(2, 5))
40 | try( set_dim(1:7, c(2, 5)) ) # error by default, just like `dim<-`()
41 | set_dim(1:7, c(2, 5), pad = 99)
42 | set_dim(1:7, c(2, 5), pad = 99, order = "C") # fills row-wise
43 |
44 | y <- x <- 1:4
45 | # base::dim<- fills the array column wise
46 | dim(x) <- c(2, 2)
47 | x
48 |
49 | # dim2 will fill the array row-wise
50 | dim2(y) <- c(2, 2)
51 | y
52 |
53 | identical(x, set_dim(1:4, c(2,2)))
54 | identical(y, set_dim(1:4, c(2,2), order = "C"))
55 |
56 | \dontrun{
57 | py_reshaped <- reticulate::array_reshape(1:4, c(2,2))
58 | storage.mode(py_reshaped) <- "integer" # reticulate coerces to double
59 | identical(y, py_reshaped)
60 | # if needed, see listarrays:::array_reshape() for
61 | # a drop-in pure R replacement for reticulate::array_reshape()
62 | }
63 | }
64 | \seealso{
65 | \code{set_dim2()}, \code{`dim<-`()}, \code{reticulate::array_reshape()}
66 | }
67 |
--------------------------------------------------------------------------------
/man/set_dimnames.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/dimnames.R
3 | \name{set_dimnames}
4 | \alias{set_dimnames}
5 | \title{Set dimnames}
6 | \usage{
7 | set_dimnames(x, nm, which_dim = NULL)
8 | }
9 | \arguments{
10 | \item{x}{an array}
11 |
12 | \item{nm}{A list or character vector.}
13 |
14 | \item{which_dim}{a character vector or numeric vector or \code{NULL}}
15 | }
16 | \value{
17 | x, with modified dimnames and or axisnames
18 | }
19 | \description{
20 | A more flexible and pipe-friendly version of \verb{dimnames<-}.
21 | }
22 | \details{
23 | This function is quite flexible. See examples for the complete
24 | picture.
25 | }
26 | \note{
27 | The word "dimnames" is slightly overloaded. Most commonly it refers to
28 | the names of entries along a particular axis (e.g., date1, date2, date3,
29 | ...), but occasionally it is also used to refer to the names of the array
30 | axes themselves (e.g, dates, temperature, pressure, ...). To disambiguate,
31 | in the examples 'dimnames' always refers to the first case, while 'axis
32 | names' refers to the second. \code{set_dimnames()} can be used to set either or both
33 | axis names and dimnames.
34 | }
35 | \examples{
36 | x <- array(1:8, 2:4)
37 |
38 | # to set axis names, leave which_dim=NULL and pass a character vector
39 | dimnames(set_dimnames(x, c("a", "b", "c")))
40 |
41 | # to set names along a single axis, specify which_dim
42 | dimnames(set_dimnames(x, c("a", "b", "c"), 2))
43 |
44 | # to set an axis name and names along the axis, pass a named list
45 | dimnames(set_dimnames(x, list(axis2 = c("a", "b", "c")), 2))
46 | dimnames(set_dimnames(x, list(axis2 = c("a", "b", "c"),
47 | axis3 = 1:4), which_dim = 2:3))
48 |
49 | # if the array already has axis names, those are used when possible
50 | nx <- set_dimnames(x, paste0("axis", 1:3))
51 | dimnames(nx)
52 | dimnames(set_dimnames(nx, list(axis2 = c("x", "y", "z"))))
53 | dimnames(set_dimnames(nx, c("x", "y", "z"), which_dim = "axis2"))
54 |
55 |
56 | # pass NULL to drop all dimnames, or just names along a single dimension
57 | nx2 <- set_dimnames(nx, c("x", "y", "z"), which_dim = "axis2")
58 | nx2 <- set_dimnames(nx2, LETTERS[1:4], which_dim = "axis3")
59 | dimnames(nx2)
60 | dimnames(set_dimnames(nx2, NULL))
61 | dimnames(set_dimnames(nx2, NULL, 2))
62 | dimnames(set_dimnames(nx2, NULL, c(2, 3)))
63 | # to preserve an axis name and only drop the dimnames, wrap the NULL in a list()
64 | dimnames(set_dimnames(nx2, list(NULL)))
65 | dimnames(set_dimnames(nx2, list(NULL), 2))
66 | dimnames(set_dimnames(nx2, list(axis2 = NULL)))
67 | dimnames(set_dimnames(nx2, list(axis2 = NULL, axis3 = NULL)))
68 | dimnames(set_dimnames(nx2, list(NULL), 2:3))
69 | }
70 |
--------------------------------------------------------------------------------
/man/shuffle_rows.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/shuffle.R
3 | \name{shuffle_rows}
4 | \alias{shuffle_rows}
5 | \title{Shuffle along the first dimension multiple arrays in sync}
6 | \usage{
7 | shuffle_rows(...)
8 | }
9 | \arguments{
10 | \item{...}{arrays of various dimensions (vectors and data.frames OK too)}
11 | }
12 | \value{
13 | A list of objects passed on to \code{...}, or if a single object was
14 | supplied, then the single object shuffled
15 | }
16 | \description{
17 | Shuffle along the first dimension multiple arrays in sync
18 | }
19 | \examples{
20 | x <- 1:3
21 | y <- matrix(1:9, ncol = 3)
22 | z <- array(1:27, c(3,3,3))
23 |
24 | if(require(zeallot)) {
25 | c(xs, ys, zs) \%<-\% shuffle_rows(x, y, z)
26 |
27 | l <- lapply(seq_along_rows(y), function(r) {
28 | list(x = x[r], y = y[r,], z = z[r,,])
29 | })
30 |
31 | ls <- lapply(seq_along_rows(y), function(r) {
32 | list(x = xs[r], y = ys[r,], z = zs[r,,])
33 | })
34 |
35 | stopifnot(
36 | length(unique(c(l, ls))) == length(l))
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/man/split-array.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/split.R
3 | \name{split_on_dim}
4 | \alias{split_on_dim}
5 | \alias{split_on_rows}
6 | \alias{split_on_cols}
7 | \alias{split_along_dim}
8 | \alias{split_along_rows}
9 | \alias{split_along_cols}
10 | \title{Split an array along a dimension}
11 | \usage{
12 | split_on_dim(
13 | X,
14 | which_dim,
15 | f = dimnames(X)[[which_dim]],
16 | drop = FALSE,
17 | depth = Inf
18 | )
19 |
20 | split_on_rows(X, f = rownames(X), drop = FALSE, depth = Inf)
21 |
22 | split_on_cols(X, f = rownames(X), drop = FALSE, depth = Inf)
23 |
24 | split_along_dim(X, which_dim, depth = Inf)
25 |
26 | split_along_rows(X, depth = Inf)
27 |
28 | split_along_cols(X, depth = Inf)
29 | }
30 | \arguments{
31 | \item{X}{an array, or list of arrays. An atomic vector without a dimension
32 | attribute is treated as a 1 dimensional array (Meaning, atomic vectors
33 | without a dim attribute are only accepted if \code{which_dim} is \code{1}. Names of
34 | the passed list are preserved. If a list of arrays, all the arrays must
35 | have the same length of the dimension being split.}
36 |
37 | \item{which_dim}{a scalar string or integer, specifying which dimension to
38 | split along. Negative integers count from the back. If a string, it must
39 | refer to a named dimension (e.g, one of \code{names(dimnames(X))}.}
40 |
41 | \item{f}{Specify how to split the dimension. \describe{
42 |
43 | \item{character, integer, factor}{passed on to \code{base::split()}. Must be the
44 | same length as the dimension being split.}
45 |
46 | \item{a list of vectors}{Passed on to \code{base::interaction()} then
47 | \code{base::split()}. Each vector in the list must be the same length as the
48 | dimension being split.}
49 |
50 | \item{a scalar integer}{used to split into that many groups of equal size}
51 |
52 | \item{a numeric vector where \code{all(f<0)}}{specifies the relative size
53 | proportions of the groups being split. \code{sum(f)} must be \code{1}. For
54 | example \code{c(0.2, 0.2, 0.6)} will return approximately a 20\\%-20\\%-60\\%
55 | split.} }}
56 |
57 | \item{drop}{passed on to \code{[}.}
58 |
59 | \item{depth}{Scalar number, how many levels to recurse down. Set this if you
60 | want to explicitly treat a list as a vector (that is, a one-dimensional
61 | array). (You can alternatively set dim attributes with \verb{dim<-} on the list
62 | to prevent recursion)
63 |
64 | \code{split_along_dim(X, which_dim)} is equivalent to \code{split_on_dim(X, which_dim, seq_along_dim(X, which_dim))}.}
65 | }
66 | \value{
67 | A list of arrays, or if a list of arrays was passed in, then a list
68 | of lists of arrays.
69 | }
70 | \description{
71 | Split an array along a dimension
72 | }
73 | \examples{
74 | X <- array(1:8, c(2,3,4))
75 | X
76 | split_along_dim(X, 2)
77 |
78 | # specify f as a factor, akin to base::split()
79 | split_on_dim(X, 2, c("a", "a", "b"), drop = FALSE)
80 |
81 | d <- c(10, 3, 3)
82 | X <- array(1:prod(d), d)
83 | y <- letters[1:10]
84 | Y <- onehot(y)
85 |
86 | # specify `f`` as relative partition sizes
87 | if(require(zeallot) && require(magrittr) && require(purrr)) {
88 |
89 | c(train, validate, test) \%<-\% {
90 | list(X = X, Y = Y, y = y) \%>\%
91 | shuffle_rows() \%>\%
92 | split_on_rows(c(0.6, 0.2, 0.2)) \%>\%
93 | transpose()
94 | }
95 |
96 | str(test)
97 | str(train)
98 | str(validate)
99 |
100 | }
101 |
102 |
103 | # with with array data in a data frame by splitting row-wise
104 | if(require(tibble))
105 | tibble(y, X = split_along_rows(X))
106 | }
107 |
--------------------------------------------------------------------------------
/pkgdown/extra.css:
--------------------------------------------------------------------------------
1 |
2 | .dl-horizontal dt {
3 | white-space: normal;
4 | }
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(listarrays)
3 |
4 | test_check("listarrays")
5 |
--------------------------------------------------------------------------------
/tests/testthat/test-bind.R:
--------------------------------------------------------------------------------
1 | context("test-bind.R")
2 |
3 | test_that("bind arrays works", {
4 |
5 | lx <- replicate(10, array(1:8, 2:4), FALSE)
6 |
7 | for(d in 1:3)
8 | expect_equal(dim(bind_as_dim(lx, d))[d], 10L)
9 |
10 | for(d in 1:3)
11 | expect_equal(dim(bind_on_dim(lx, d))[d], 10L*dim(lx[[1]])[d])
12 |
13 |
14 | # dnn <- dimnames(provideDimnames(lx[[1]]))
15 | # dnn <- lapply(seq_along(dnn), function(i) {
16 | # paste(i, dnn[[i]], sep = "_")
17 | # })
18 | dnn <- list(c("1_A", "1_B"),
19 | c("2_A", "2_B", "2_C"),
20 | c("3_A", "3_B", "3_C", "3_D"))
21 |
22 | lx <- lapply(lx, function(x) {
23 | dimnames(x) <- dnn
24 | x
25 | })
26 |
27 | new_dnn <- dimnames(bind_as_rows(lx))
28 | expect_identical(new_dnn, c(list(NULL), dnn))
29 |
30 | names(lx) <- paste0("newdim_", 1:10)
31 | new_dnn <- dimnames(bind_as_rows(lx))
32 | expect_identical(new_dnn, c(list(names(lx)), dnn))
33 |
34 | # trip cmpfun limit
35 | lx <- as.list(1:2000)
36 | names(lx) <- as.character(1:2000)
37 | lx <- lapply(lx, function(.) matrix(as.character(1:12), nrow = 4))
38 |
39 | x <- bind_on_rows(lx)
40 |
41 | y <- do.call(rbind, lx)
42 | rownames(y) <- rep(names(lx), each = 4)
43 |
44 | expect_identical(x, y)
45 |
46 | })
47 |
--------------------------------------------------------------------------------
/tests/testthat/test-dimnames.R:
--------------------------------------------------------------------------------
1 | context("test-dimnames.R")
2 |
3 | test_that("setting dimnames works", {
4 | # ar <- function() array(1:8, 2:4)
5 | x <- array(1:8, 2:4)
6 | xyz <- c("x", "y", "z")
7 |
8 | # bare character string sets names of dims
9 | x_named <- set_dimnames(x, xyz)
10 | expect_equal(names(dimnames(x_named)), xyz)
11 |
12 | # setting a single dim with a character string works
13 | y <- set_dimnames(x, xyz, which_dim = 2)
14 | expect_equal(dimnames(y)[[2L]], xyz)
15 |
16 | y <- set_dimnames(x_named, xyz, which_dim = 2)
17 | expect_equal(dimnames(y)[[2L]], xyz)
18 | expect_equal(names(dimnames(y)), xyz)
19 |
20 | y <- set_dimnames(x_named, xyz, which_dim = "y")
21 | expect_equal(dimnames(y)[[2L]], xyz)
22 | expect_equal(names(dimnames(y)), xyz)
23 |
24 |
25 | # setting with a list works
26 | y <- set_dimnames(x, list(xyz), which_dim = 2)
27 | expect_equal(dimnames(y)[[2L]], xyz)
28 |
29 | y <- set_dimnames(x_named, list(xyz), which_dim = 2)
30 | expect_equal(dimnames(y)[[2L]], xyz)
31 | expect_equal(names(dimnames(y)), xyz)
32 |
33 | y <- set_dimnames(x_named, list(xyz), which_dim = "y")
34 | expect_equal(dimnames(y)[[2L]], xyz)
35 | expect_equal(names(dimnames(y)), xyz)
36 |
37 | y2 <- set_dimnames(x_named, list(y = xyz))
38 | expect_identical(y, y2)
39 |
40 | y <- set_dimnames(x, list(z = xyz), which_dim = 2)
41 | expect_equal(names(dimnames(y)), c("", "z", ""))
42 | expect_equal(dimnames(y)[["z"]], xyz)
43 |
44 |
45 | # setting more than one dimensionat a time works
46 | y <- set_dimnames(x, list(a = xyz, b = letters[1:4]), which_dim = 2:3)
47 | expect_equal(names(dimnames(y)), c("", "a", "b"))
48 | expect_equal(dimnames(y)[["a"]], xyz)
49 | expect_equal(dimnames(y)[["b"]], letters[1:4])
50 |
51 |
52 | })
53 |
54 |
55 |
56 | test_that("specifying `which_dim` by name works", {
57 |
58 | x <- provideDimnames(array(1:8, 2:4))
59 | x <- set_dimnames(x, paste0("axis", 1:3))
60 |
61 | expect_identical(extract_dim(x, "axis2", 1),
62 | extract_dim(x, 2L, 1))
63 |
64 | f <- c(TRUE, TRUE, FALSE)
65 | expect_identical(split_on_dim(x, "axis2", f),
66 | split_on_dim(x, 2L, f))
67 |
68 | expect_identical(split_along_dim(x, "axis2"),
69 | split_along_dim(x, 2L))
70 |
71 | expect_identical(modify_along_dim(x, "axis2", function(x) x + 100),
72 | modify_along_dim(x, 2L, function(x) x + 100))
73 |
74 | xx <- rep_len(list(x), 5)
75 | expect_identical(bind_on_dim(xx, "axis2"),
76 | bind_on_dim(xx, 2L))
77 |
78 |
79 | })
80 |
--------------------------------------------------------------------------------
/tests/testthat/test-map.R:
--------------------------------------------------------------------------------
1 | context("test-map.R")
2 |
3 |
4 | test_that("map_along_dim", {
5 | A <- matrix2(letters[1:15], ncol = 3)
6 |
7 | for (d in seq_along(dim(A)))
8 | expect_identical(
9 | as.list(apply(A, 1, function(x) paste(x, collapse = ""))),
10 | map_along_rows(A, ~ paste(.x, collapse = "")))
11 | })
12 |
--------------------------------------------------------------------------------
/tests/testthat/test-modify.R:
--------------------------------------------------------------------------------
1 | context("test-modify.R")
2 |
3 | test_that("modify_along_dim works", {
4 | x <- array(1:840, 4:7)
5 |
6 | for (d in seq_along(4:7)) {
7 | expect_identical(x, modify_along_dim(x, d, identity))
8 | }
9 |
10 | # accepts returned without dim
11 |
12 | for (d in seq_along(4:7))
13 | expect_identical(x, modify_along_dim(x, d, as.vector))
14 |
15 | cx <- array(as.character(x), dim = 4:7)
16 |
17 | for (d in seq_along(4:7))
18 | expect_identical(cx, modify_along_dim(x, d, paste))
19 |
20 |
21 | # works with more than one dimension
22 | for (d in combn(1:length(dim(x)), 2, simplify = FALSE)) {
23 | expect_identical(x, modify_along_dim(x, d, identity))
24 | }
25 |
26 | for (d in combn(1:length(dim(x)), 3, simplify = FALSE)) {
27 | expect_identical(x, modify_along_dim(x, d, identity))
28 | }
29 |
30 | # go big enough to trigger calling cmpfun()
31 | arr <- function(...) array(seq_len(prod(c(...))), c(...))
32 | x <- arr(5:9)
33 | expect_identical(x, modify_along_dim(x, 3:5, identity))
34 |
35 | })
36 |
--------------------------------------------------------------------------------
/tests/testthat/test-onehot.R:
--------------------------------------------------------------------------------
1 | context("test-onehot.R")
2 |
3 | test_that("onehot encoding and decoding", {
4 |
5 | y <- letters[1:4]
6 | Y <- matrix(c(1, 0, 0, 0,
7 | 0, 1, 0, 0,
8 | 0, 0, 1, 0,
9 | 0, 0, 0, 1),
10 | byrow = TRUE, ncol = 4)
11 | colnames(Y) <- y
12 |
13 |
14 |
15 | expect_identical(Y, onehot(y))
16 | expect_identical(y, decode_onehot(Y))
17 |
18 | decode <- onehot_with_decoder(y)[[2]]
19 | expect_identical(y, decode(Y))
20 |
21 |
22 | })
23 |
--------------------------------------------------------------------------------
/tests/testthat/test-shuffle.R:
--------------------------------------------------------------------------------
1 | context("test-shuffle.R")
2 |
3 | test_that("shuffle_rows", {
4 | x <- 1:3
5 | y <- matrix(1:9, ncol = 3)
6 | z <- array(1:27, c(3,3,3))
7 |
8 | suppressWarnings(RNGversion("3.5.0"))
9 | set.seed(1)
10 | l <- shuffle_rows(x, y, z)
11 |
12 | i <- c(1L, 3L, 2L)
13 | expect_identical(x[i], l[[1]])
14 | expect_identical(y[i,], l[[2]])
15 | expect_identical(z[i,,], l[[3]])
16 |
17 | })
18 |
--------------------------------------------------------------------------------
/tests/testthat/test-split.R:
--------------------------------------------------------------------------------
1 | context("test-split.R")
2 |
3 | test_that("split_along_dim", {
4 | x <- array(1:840, 4:7)
5 |
6 | for (d in seq_along(dim(x)))
7 | expect_length(split_along_dim(x, d), dim(x)[d])
8 |
9 | })
10 |
11 |
12 | test_that("split_on_dim", {
13 | x <- array(1:840, 4:7)
14 |
15 | for (d in seq_along(dim(x))) {
16 | f <- rep_len(1:2, dim(x)[d])
17 | expect_length(split_on_dim(x, d, f), 2L)
18 | }
19 |
20 | })
21 |
22 |
23 | test_that("split* works recursively", {
24 | x1 <- 1:4
25 | x2 <- matrix(1:20, nrow = 4, ncol = 5)
26 | x3 <- array(1:840, 4:7)
27 |
28 | l <- split_along_rows(list(x1, x2, x3))
29 |
30 | for (i in seq_along(l)) {
31 | expect_length(l[[i]], 4)
32 | }
33 |
34 | })
35 |
36 | test_that("split_on f inputs", {
37 | x <- array(1:840, 4:7)
38 |
39 | # test a scalar integer
40 | l <- split_on_rows(x, 4)
41 | expect_length(l, 4L)
42 | for (i in seq_along(l))
43 | expect_equal(dim(l[[i]]), c(1, 5:7))
44 |
45 | l <- split_on_rows(x, 4, drop = TRUE)
46 | expect_length(l, 4L)
47 | for (i in seq_along(l))
48 | expect_equal(dim(l[[i]]), 5:7)
49 |
50 | # test a vector of proportions
51 | x <- bind_as_rows(rep_len(list(array(1:8, 2:4)), 10))
52 | l <- split_on_rows(x, c(0.2, 0.2, 0.6), drop = FALSE)
53 | expect_length(l, 3L)
54 | expect_equal(nrow(l[[1]]), 2L)
55 | expect_equal(nrow(l[[2]]), 2L)
56 | expect_equal(nrow(l[[3]]), 6L)
57 |
58 | })
59 |
60 |
61 |
62 | test_that("split_along_rows works with common vector types", {
63 | m <- matrix(1:20, nrow = 4, ncol = 5)
64 |
65 | set.seed(42)
66 | for (mode in c("integer", "double", "complex", "logical", "list", "character")) {
67 | storage.mode(m) <- mode
68 | if (mode == "logical")
69 | m[] <- sample(c(TRUE, FALSE), length(m), TRUE)
70 | expect_equal(split_along_rows(m),
71 | array(lapply(1:4, function(r) array(m[r, ]))))
72 | }
73 |
74 | })
75 |
--------------------------------------------------------------------------------