1 |
# MATHEMATICS |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
#' @export |
|
6 |
#' @rdname math_gcd |
|
7 |
#' @aliases math_gcd,numeric,numeric-method |
|
8 |
setMethod( |
|
9 |
f = "math_gcd", |
|
10 |
signature = c(x = "numeric", y = "numeric"), |
|
11 |
definition = function(x, y) { |
|
12 | 12x |
mapply( |
13 | 12x |
FUN = function(a, b) { |
14 | 4x |
if (isTRUE(all.equal(b, 0))) return(a) |
15 | 10x |
math_gcd(b, a %% b) |
16 |
}, |
|
17 | 12x |
a = x, |
18 | 12x |
b = y |
19 |
) |
|
20 |
} |
|
21 |
) |
|
22 | ||
23 |
#' @export |
|
24 |
#' @rdname math_lcm |
|
25 |
#' @aliases math_lcm,numeric,numeric-method |
|
26 |
setMethod( |
|
27 |
f = "math_lcm", |
|
28 |
signature = c(x = "numeric", y = "numeric"), |
|
29 |
definition = function(x, y) { |
|
30 | 1x |
(x * y) / math_gcd(x, y) |
31 |
} |
|
32 |
) |
1 |
# CHECK DATA INPUT |
|
2 |
#' @include predicates.R |
|
3 |
NULL |
|
4 | ||
5 |
#' Validate a Condition |
|
6 |
#' |
|
7 |
#' @param expr An object to be evaluated. |
|
8 |
#' @return |
|
9 |
#' Returns `NULL` on success, otherwise returns the error as a string. |
|
10 |
#' @author N. Frerebeau |
|
11 |
#' @family validation methods |
|
12 |
#' @name validate |
|
13 |
#' @rdname validate |
|
14 |
#' @export |
|
15 |
validate <- function(expr) { |
|
16 | 3x |
cnd <- catch_message(eval(expr)) |
17 | 2x |
if (has_length(cnd)) return(cnd) |
18 | 1x |
NULL |
19 |
} |
|
20 | ||
21 |
# Packages ===================================================================== |
|
22 |
#' Check the Availability of a Package |
|
23 |
#' |
|
24 |
#' @param x A [`character`] vector naming the packages to check. |
|
25 |
#' @param ask A [`logical`] scalar: should the user be asked to select packages |
|
26 |
#' before they are downloaded and installed? |
|
27 |
#' @details |
|
28 |
#' `assert_package()` is designed for use inside other functions in your own |
|
29 |
#' package to check for the availability of a suggested package. |
|
30 |
#' |
|
31 |
#' If the required packages are not available and \R is running interactively, |
|
32 |
#' the user will be asked to install the packages. |
|
33 |
#' @return Invisibly returns `NULL`. |
|
34 |
#' @family checking methods |
|
35 |
#' @author N. Frerebeau |
|
36 |
#' @export |
|
37 |
assert_package <- function(x, ask = interactive()) { |
|
38 | 1x |
ok <- vapply(X = x, FUN = requireNamespace, FUN.VALUE = logical(1), |
39 | 1x |
quietly = TRUE) |
40 | ||
41 | 1x |
miss <- x[!ok] |
42 | 1x |
n <- length(miss) |
43 | ||
44 | 1x |
if (n > 0) { |
45 | 1x |
err <- sprintf( |
46 | 1x |
ngettext(n, "Package %s is required.", "Packages %s are required."), |
47 | 1x |
paste0(sQuote(miss), collapse = ", ") |
48 |
) |
|
49 | 1x |
install <- FALSE |
50 | 1x |
if (isTRUE(ask)) { |
51 | ! |
msg <- ngettext(n, "Do you want to install it?", "Do you want to install them?") |
52 | ! |
install <- utils::askYesNo( |
53 | ! |
msg = paste0(c(err, msg), collapse = "\n"), |
54 | ! |
default = FALSE, |
55 | ! |
prompts = gettext(c("Yes", "No", "Cancel")) |
56 |
) |
|
57 |
} |
|
58 | 1x |
if (isTRUE(install)) { |
59 | ! |
utils::install.packages(miss) |
60 |
} else { |
|
61 | 1x |
throw_error("error_missing_package", err) |
62 |
} |
|
63 |
} |
|
64 | ! |
invisible(NULL) |
65 |
} |
|
66 | ||
67 |
# Attributes =================================================================== |
|
68 |
#' Check Object Length(s) |
|
69 |
#' |
|
70 |
#' @param x An object to be checked. |
|
71 |
#' @param expected An appropriate expected value. |
|
72 |
#' @param allow_empty A [`logical`] scalar: should [empty][is_empty()] object be |
|
73 |
#' ignored? |
|
74 |
#' @param allow_null A [`logical`] scalar: should `NULL` object be ignored? |
|
75 |
#' @param empty Deprecated. |
|
76 |
#' @return |
|
77 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
78 |
#' @author N. Frerebeau |
|
79 |
#' @family checking methods |
|
80 |
#' @export |
|
81 |
assert_length <- function(x, expected, allow_empty = empty, allow_null = FALSE, empty = FALSE) { |
|
82 | 1x |
if (is.null(x) && isTRUE(allow_null)) return(invisible(NULL)) |
83 | ||
84 | 26x |
arg <- deparse(substitute(x)) |
85 | 26x |
if (!(allow_empty && is_empty(x)) && !has_length(x, n = expected)) { |
86 | 4x |
txt <- tr_("%s must be of length %d; not %d.") |
87 | 4x |
msg <- sprintf(txt, sQuote(arg), expected, length(x)) |
88 | 4x |
throw_error("error_bad_length", msg) |
89 |
} |
|
90 | 22x |
invisible(x) |
91 |
} |
|
92 | ||
93 |
#' @export |
|
94 |
#' @rdname assert_length |
|
95 |
assert_lengths <- function(x, expected) { |
|
96 | 2x |
arg <- deparse(substitute(x)) |
97 | 2x |
n <- lengths(x) |
98 | 2x |
if (!all(n == expected)) { |
99 | 1x |
txt <- tr_("Elements of %s must be of lengths %s; not %s.") |
100 | 1x |
msg <- sprintf(txt, sQuote(arg), paste0(expected, collapse = ", "), |
101 | 1x |
paste0(n, collapse = ", ")) |
102 | 1x |
throw_error("error_bad_length", msg) |
103 |
} |
|
104 | 1x |
invisible(x) |
105 |
} |
|
106 | ||
107 |
#' Check Object Dimensions |
|
108 |
#' |
|
109 |
#' @param x An object to be checked. |
|
110 |
#' @param expected An appropriate expected value. |
|
111 |
#' @return |
|
112 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
113 |
#' @author N. Frerebeau |
|
114 |
#' @family checking methods |
|
115 |
#' @export |
|
116 |
assert_dim <- function(x, expected) { |
|
117 | 2x |
arg <- deparse(substitute(x)) |
118 | 2x |
n <- dim(x) |
119 | 2x |
if (!all(n == expected)) { |
120 | 1x |
txt <- tr_("%s must be of dimension %s; not %s.") |
121 | 1x |
msg <- sprintf(txt, sQuote(arg), paste0(expected, collapse = " x "), |
122 | 1x |
paste0(n, collapse = " x ")) |
123 | 1x |
throw_error("error_bad_dimensions", msg) |
124 |
} |
|
125 | 1x |
invisible(x) |
126 |
} |
|
127 | ||
128 |
#' @export |
|
129 |
#' @rdname assert_dim |
|
130 |
assert_nrow <- function(x, expected) { |
|
131 | 1x |
arg <- deparse(substitute(x)) |
132 | 1x |
n <- nrow(x) |
133 | 1x |
if (n != expected) { |
134 | 1x |
txt <- ngettext(expected, "%s must have %s row; not %s.", |
135 | 1x |
"%s must have %s rows; not %s.") |
136 | 1x |
msg <- sprintf(txt, sQuote(arg), expected, n) |
137 | 1x |
throw_error("error_bad_dimensions", msg) |
138 |
} |
|
139 | ! |
invisible(x) |
140 |
} |
|
141 | ||
142 |
#' @export |
|
143 |
#' @rdname assert_dim |
|
144 |
assert_ncol <- function(x, expected) { |
|
145 | 1x |
arg <- deparse(substitute(x)) |
146 | 1x |
n <- ncol(x) |
147 | 1x |
if (n != expected) { |
148 | 1x |
txt <- ngettext(expected, "%s must have %s column; not %s.", |
149 | 1x |
"%s must have %s columns; not %s.") |
150 | 1x |
msg <- sprintf(txt, sQuote(arg), expected, n) |
151 | 1x |
throw_error("error_bad_dimensions", msg) |
152 |
} |
|
153 | ! |
invisible(x) |
154 |
} |
|
155 | ||
156 |
#' Check Object Filling |
|
157 |
#' |
|
158 |
#' Checks if an object is (not) empty. |
|
159 |
#' @param x An object to be checked. |
|
160 |
#' @return |
|
161 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
162 |
#' @author N. Frerebeau |
|
163 |
#' @family checking methods |
|
164 |
#' @export |
|
165 |
assert_empty <- function(x) { |
|
166 | 2x |
arg <- deparse(substitute(x)) |
167 | 2x |
if (!is_empty(x)) { |
168 | 1x |
msg <- sprintf(tr_("%s must be empty."), sQuote(arg)) |
169 | 1x |
throw_error("error_bad_dimensions", msg) |
170 |
} |
|
171 | 1x |
invisible(x) |
172 |
} |
|
173 | ||
174 |
#' @export |
|
175 |
#' @rdname assert_empty |
|
176 |
assert_filled <- function(x) { |
|
177 | 18x |
arg <- deparse(substitute(x)) |
178 | 18x |
if (is_empty(x)) { |
179 | 2x |
msg <- sprintf(tr_("%s must not be empty."), sQuote(arg)) |
180 | 2x |
throw_error("error_bad_dimensions", msg) |
181 |
} |
|
182 | 16x |
invisible(x) |
183 |
} |
|
184 | ||
185 |
# Names ======================================================================== |
|
186 |
#' Check Object Names |
|
187 |
#' |
|
188 |
#' @param x An object to be checked. |
|
189 |
#' @param expected An appropriate expected value. |
|
190 |
#' @return |
|
191 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
192 |
#' @author N. Frerebeau |
|
193 |
#' @family checking methods |
|
194 |
#' @export |
|
195 |
assert_names <- function(x, expected = NULL) { |
|
196 | 4x |
arg <- deparse(substitute(x)) |
197 | 4x |
if (!has_names(x, names = expected)) { |
198 | 3x |
if (is.null(expected)) { |
199 | 1x |
msg <- sprintf(tr_("%s must have names."), sQuote(arg)) |
200 |
} else { |
|
201 | 2x |
msg <- sprintf(tr_("%s must have the following names: %s."), |
202 | 2x |
sQuote(arg), paste0(expected, collapse = ", ")) |
203 |
} |
|
204 | 3x |
throw_error("error_bad_names", msg) |
205 |
} |
|
206 | 1x |
invisible(x) |
207 |
} |
|
208 | ||
209 |
#' @export |
|
210 |
#' @rdname assert_names |
|
211 |
assert_rownames <- function(x, expected = NULL) { |
|
212 | 3x |
arg <- deparse(substitute(x)) |
213 | 3x |
if (!has_rownames(x, names = expected)) { |
214 | 2x |
if (is.null(expected)) { |
215 | 1x |
msg <- sprintf(tr_("%s must have row names."), sQuote(arg)) |
216 |
} else { |
|
217 | 1x |
msg <- sprintf(tr_("%s must have the following row names: %s."), |
218 | 1x |
sQuote(arg), paste0(expected, collapse = ", ")) |
219 |
} |
|
220 | 2x |
throw_error("error_bad_names", msg) |
221 |
} |
|
222 | 1x |
invisible(x) |
223 |
} |
|
224 | ||
225 |
#' @export |
|
226 |
#' @rdname assert_names |
|
227 |
assert_colnames <- function(x, expected = NULL) { |
|
228 | 3x |
arg <- deparse(substitute(x)) |
229 | 3x |
if (!has_colnames(x, names = expected)) { |
230 | 2x |
if (is.null(expected)) { |
231 | 1x |
msg <- sprintf(tr_("%s must have column names."), sQuote(arg)) |
232 |
} else { |
|
233 | 1x |
msg <- sprintf(tr_("%s must have the following column names: %s."), |
234 | 1x |
sQuote(arg), paste0(expected, collapse = ", ")) |
235 |
} |
|
236 | 2x |
throw_error("error_bad_names", msg) |
237 |
} |
|
238 | 1x |
invisible(x) |
239 |
} |
|
240 | ||
241 |
# NA/NaN/Inf/duplicates ======================================================== |
|
242 |
#' Check Missing Values |
|
243 |
#' |
|
244 |
#' Checks if an object contains any missing (`NA`, `NaN`) values. |
|
245 |
#' @param x An object to be checked. |
|
246 |
#' @return |
|
247 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
248 |
#' @author N. Frerebeau |
|
249 |
#' @family checking methods |
|
250 |
#' @export |
|
251 |
assert_missing <- function(x) { |
|
252 | 3x |
arg <- deparse(substitute(x)) |
253 | 3x |
n <- sum(is.na(x)) |
254 | 3x |
if (n > 0) { |
255 | 2x |
txt <- ngettext(n, "%s must not contain missing values (%d detected).", |
256 | 2x |
"%s must not contain missing values (%d detected).") |
257 | 2x |
msg <- sprintf(txt, sQuote(arg), n) |
258 | 2x |
throw_error("error_data_missing", msg) |
259 |
} |
|
260 | 1x |
invisible(x) |
261 |
} |
|
262 | ||
263 |
#' Check Infinite Values |
|
264 |
#' |
|
265 |
#' Checks if an object contains any infinite (`Inf`) values. |
|
266 |
#' @param x An object to be checked. |
|
267 |
#' @return |
|
268 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
269 |
#' @author N. Frerebeau |
|
270 |
#' @family checking methods |
|
271 |
#' @export |
|
272 |
assert_infinite <- function(x) { |
|
273 | 2x |
arg <- deparse(substitute(x)) |
274 | 2x |
n <- sum(is.infinite(x)) |
275 | 2x |
if (n > 0) { |
276 | 1x |
txt <- ngettext(n, "%s must not contain infinite values (%d detected).", |
277 | 1x |
"%s must not contain infinite values (%d detected).") |
278 | 1x |
msg <- sprintf(txt, sQuote(arg), n) |
279 | 1x |
throw_error("error_data_infinite", msg) |
280 |
} |
|
281 | 1x |
invisible(x) |
282 |
} |
|
283 | ||
284 |
#' Check Duplicates |
|
285 |
#' |
|
286 |
#' Checks if an object contains duplicated elements. |
|
287 |
#' @param x An object to be checked. |
|
288 |
#' @return |
|
289 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
290 |
#' @author N. Frerebeau |
|
291 |
#' @family checking methods |
|
292 |
#' @export |
|
293 |
assert_unique <- function(x) { |
|
294 | 2x |
arg <- deparse(substitute(x)) |
295 | 2x |
if (has_duplicates(x)) { |
296 | 1x |
msg <- sprintf(tr_("Elements of %s must be unique."), sQuote(arg)) |
297 | 1x |
throw_error("error_data_duplicates", msg) |
298 |
} |
|
299 | 1x |
invisible(x) |
300 |
} |
|
301 | ||
302 |
# Types ======================================================================== |
|
303 |
#' Check Data Types |
|
304 |
#' |
|
305 |
#' @param x An object to be checked. |
|
306 |
#' @param expected A [`character`] string specifying the expected |
|
307 |
#' type. It must be one of "`list`", "`atomic`", "`vector`", "`numeric`", |
|
308 |
#' "`integer`", "`double`", "`character`" or "`logical`". |
|
309 |
#' @param allow_empty A [`logical`] scalar: should [empty][is_empty()] object be |
|
310 |
#' allowed? |
|
311 |
#' @param allow_null A [`logical`] scalar: should `NULL` object be ignored? |
|
312 |
#' @return |
|
313 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
314 |
#' @author N. Frerebeau |
|
315 |
#' @family checking methods |
|
316 |
#' @export |
|
317 |
assert_type <- function(x, expected, allow_empty = TRUE, allow_null = FALSE) { |
|
318 | 15x |
if (is.null(x) && isTRUE(allow_null)) return(invisible(NULL)) |
319 | 1x |
if (isFALSE(allow_empty)) assert_filled(x) |
320 | ||
321 | 173x |
arg <- deparse(substitute(x)) |
322 | 173x |
msg <- sprintf(tr_("Can't find a predicate for this type: %s."), expected) |
323 | 173x |
predicate <- switch( |
324 | 173x |
expected, |
325 | 173x |
list = is_list, |
326 | 173x |
atomic = is_atomic, |
327 | 173x |
vector = is_vector, |
328 | 173x |
numeric = is_numeric, |
329 | 173x |
integer = is_integer, |
330 | 173x |
double = is_double, |
331 | 173x |
character = is_character, |
332 | 173x |
logical = is_logical, |
333 | 173x |
stop(msg, call. = FALSE) |
334 |
) |
|
335 | 173x |
if (!predicate(x)) { |
336 | 12x |
msg <- sprintf(tr_("%s must be %s; not %s."), sQuote(arg), expected, typeof(x)) |
337 | 12x |
throw_error("error_bad_type", msg) |
338 |
} |
|
339 | 161x |
invisible(x) |
340 |
} |
|
341 | ||
342 |
#' @export |
|
343 |
#' @rdname assert_type |
|
344 |
assert_scalar <- function(x, expected) { |
|
345 | 12x |
arg <- deparse(substitute(x)) |
346 | 12x |
msg <- sprintf(tr_("Can't find a predicate for this scalar: %s."), expected) |
347 | 12x |
predicate <- switch( |
348 | 12x |
expected, |
349 | 12x |
list = is_scalar_list, |
350 | 12x |
atomic = is_scalar_atomic, |
351 | 12x |
vector = is_scalar_vector, |
352 | 12x |
numeric = is_scalar_numeric, |
353 | 12x |
integer = is_scalar_integer, |
354 | 12x |
double = is_scalar_double, |
355 | 12x |
character = is_scalar_character, |
356 | 12x |
logical = is_scalar_logical, |
357 | 12x |
stop(msg, call. = FALSE) |
358 |
) |
|
359 | 12x |
if (!predicate(x)) { |
360 | 2x |
msg <- sprintf(tr_("%s must be a scalar (%s)."), sQuote(arg), expected) |
361 | 2x |
throw_error("error_bad_scalar", msg) |
362 |
} |
|
363 | 10x |
invisible(x) |
364 |
} |
|
365 | ||
366 |
#' @export |
|
367 |
#' @rdname assert_type |
|
368 |
assert_function <- function(x) { |
|
369 | 92x |
arg <- deparse(substitute(x)) |
370 | 92x |
if (!is.function(x)) { |
371 | 1x |
msg <- sprintf(tr_("%s must be a function."), sQuote(arg)) |
372 | 1x |
throw_error("error_bad_type", msg) |
373 |
} |
|
374 | 91x |
invisible(x) |
375 |
} |
|
376 | ||
377 |
# Numeric ====================================================================== |
|
378 |
#' Check Numeric Values |
|
379 |
#' |
|
380 |
#' @param x A [`numeric`] object to be checked. |
|
381 |
#' @param na.rm A [`logical`] scalar: should missing values (including `NaN`) |
|
382 |
#' be omitted? |
|
383 |
#' @param ... Extra parameters to be passed to internal methods. |
|
384 |
#' @return |
|
385 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
386 |
#' @author N. Frerebeau |
|
387 |
#' @family checking methods |
|
388 |
#' @name assert_numeric |
|
389 |
#' @rdname assert_numeric |
|
390 |
NULL |
|
391 | ||
392 |
#' @export |
|
393 |
#' @rdname assert_numeric |
|
394 |
assert_count <- function(x, na.rm = FALSE, ...) { |
|
395 | 4x |
arg <- deparse(substitute(x)) |
396 | 4x |
if (!all(is_whole(x, ...), na.rm = na.rm)) { |
397 | 3x |
msg <- sprintf(tr_("%s must contain integers (counts)."), sQuote(arg)) |
398 | 3x |
throw_error("error_bad_numeric", msg) |
399 |
} |
|
400 | 1x |
invisible(x) |
401 |
} |
|
402 | ||
403 |
#' @export |
|
404 |
#' @rdname assert_numeric |
|
405 |
assert_whole <- assert_count |
|
406 | ||
407 |
#' @export |
|
408 |
#' @rdname assert_numeric |
|
409 |
assert_positive <- function(x, na.rm = FALSE, ...) { |
|
410 | 3x |
arg <- deparse(substitute(x)) |
411 | 3x |
if (!all(is_positive(x, ...), na.rm = na.rm)) { |
412 | 2x |
msg <- sprintf(tr_("%s must contain positive numbers."), sQuote(arg)) |
413 | 2x |
throw_error("error_bad_numeric", msg) |
414 |
} |
|
415 | 1x |
invisible(x) |
416 |
} |
|
417 | ||
418 |
#' @export |
|
419 |
#' @rdname assert_numeric |
|
420 |
assert_negative <- function(x, na.rm = FALSE, ...) { |
|
421 | ! |
arg <- deparse(substitute(x)) |
422 | ! |
if (!all(is_negative(x, ...), na.rm = na.rm)) { |
423 | ! |
msg <- sprintf(tr_("%s must contain negative numbers."), sQuote(arg)) |
424 | ! |
throw_error("error_bad_numeric", msg) |
425 |
} |
|
426 | ! |
invisible(x) |
427 |
} |
|
428 | ||
429 |
#' @export |
|
430 |
#' @rdname assert_numeric |
|
431 |
assert_odd <- function(x, na.rm = FALSE, ...) { |
|
432 | 1x |
arg <- deparse(substitute(x)) |
433 | 1x |
if (!all(is_odd(x, ...), na.rm = na.rm)) { |
434 | 1x |
msg <- sprintf(tr_("%s must contain odd numbers."), sQuote(arg)) |
435 | 1x |
throw_error("error_bad_numeric", msg) |
436 |
} |
|
437 | ! |
invisible(x) |
438 |
} |
|
439 | ||
440 |
#' @export |
|
441 |
#' @rdname assert_numeric |
|
442 |
assert_even <- function(x, na.rm = FALSE, ...) { |
|
443 | 1x |
arg <- deparse(substitute(x)) |
444 | 1x |
if (!all(is_even(x, ...), na.rm = na.rm)) { |
445 | 1x |
msg <- sprintf(tr_("%s must contain even numbers."), sQuote(arg)) |
446 | 1x |
throw_error("error_bad_numeric", msg) |
447 |
} |
|
448 | ! |
invisible(x) |
449 |
} |
|
450 | ||
451 |
#' Check Numeric Trend |
|
452 |
#' |
|
453 |
#' @param x A [`numeric`] object to be checked. |
|
454 |
#' @param ... Extra parameters to be passed to internal methods. |
|
455 |
#' @return |
|
456 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
457 |
#' @author N. Frerebeau |
|
458 |
#' @family checking methods |
|
459 |
#' @export |
|
460 |
assert_constant <- function(x, ...) { |
|
461 | 1x |
arg <- deparse(substitute(x)) |
462 | 1x |
if (!is_constant(x, ...)) { |
463 | 1x |
msg <- sprintf(tr_("%s must be constant."), sQuote(arg)) |
464 | 1x |
throw_error("error_bad_numeric", msg) |
465 |
} |
|
466 | ! |
invisible(x) |
467 |
} |
|
468 | ||
469 |
#' @export |
|
470 |
#' @rdname assert_constant |
|
471 |
assert_decreasing <- function(x, ...) { |
|
472 | 1x |
arg <- deparse(substitute(x)) |
473 | 1x |
if (!is_decreasing(x, ...)) { |
474 | 1x |
msg <- sprintf(tr_("%s must be decreasing."), sQuote(arg)) |
475 | 1x |
throw_error("error_bad_numeric", msg) |
476 |
} |
|
477 | ! |
invisible(x) |
478 |
} |
|
479 | ||
480 |
#' @export |
|
481 |
#' @rdname assert_constant |
|
482 |
assert_increasing <- function(x, ...) { |
|
483 | 2x |
arg <- deparse(substitute(x)) |
484 | 2x |
if (!is_increasing(x, ...)) { |
485 | 1x |
msg <- sprintf(tr_("%s must be increasing."), sQuote(arg)) |
486 | 1x |
throw_error("error_bad_numeric", msg) |
487 |
} |
|
488 | 1x |
invisible(x) |
489 |
} |
|
490 | ||
491 |
#' Check Numeric Relations |
|
492 |
#' |
|
493 |
#' @param x,y A [`numeric`] object to be checked. |
|
494 |
#' @param ... Extra parameters to be passed to internal methods. |
|
495 |
#' @return |
|
496 |
#' Throws an error, if any, and returns `x` invisibly otherwise. |
|
497 |
#' @author N. Frerebeau |
|
498 |
#' @family checking methods |
|
499 |
#' @export |
|
500 |
assert_lower <- function(x, y, ...) { |
|
501 | 2x |
arg_x <- deparse(substitute(x)) |
502 | 2x |
arg_y <- deparse(substitute(y)) |
503 | 2x |
if (!is_lower(x, y, ...)) { |
504 | 1x |
txt <- tr_("%s must be lower than %s.") |
505 | 1x |
msg <- sprintf(txt, sQuote(arg_x), sQuote(arg_y)) |
506 | 1x |
throw_error("error_bad_numeric", msg) |
507 |
} |
|
508 | 1x |
invisible(x) |
509 |
} |
|
510 | ||
511 |
#' @export |
|
512 |
#' @rdname assert_lower |
|
513 |
assert_greater <- function(x, y, ...) { |
|
514 | 1x |
arg_x <- deparse(substitute(x)) |
515 | 1x |
arg_y <- deparse(substitute(y)) |
516 | 1x |
if (!is_greater(x, y, ...)) { |
517 | 1x |
txt <- tr_("%s must be greater than %s.") |
518 | 1x |
msg <- sprintf(txt, sQuote(arg_x), sQuote(arg_y)) |
519 | 1x |
throw_error("error_bad_numeric", msg) |
520 |
} |
|
521 | ! |
invisible(x) |
522 |
} |
|
523 | ||
524 |
# Matrix ======================================================================= |
|
525 |
#' Check Matrix |
|
526 |
#' |
|
527 |
#' @param x A [`matrix`] to be checked. |
|
528 |
#' @return Throw an error, if any, and returns `x` invisibly otherwise. |
|
529 |
#' @author N. Frerebeau |
|
530 |
#' @family checking methods |
|
531 |
#' @export |
|
532 |
assert_square <- function(x) { |
|
533 | 2x |
arg <- deparse(substitute(x)) |
534 | 2x |
if (!is_square(x)) { |
535 | 1x |
k <- paste0(dim(x), collapse = " x ") |
536 | 1x |
msg <- sprintf(tr_("%s must be a square matrix, not %s."), sQuote(arg), k) |
537 | 1x |
throw_error("error_bad_matrix", msg) |
538 |
} |
|
539 | 1x |
invisible(x) |
540 |
} |
|
541 | ||
542 |
#' @export |
|
543 |
#' @rdname assert_square |
|
544 |
assert_symmetric <- function(x) { |
|
545 | 1x |
arg <- deparse(substitute(x)) |
546 | 1x |
if (!is_symmetric(x)) { |
547 | 1x |
msg <- sprintf(tr_("%s must be a symmetric matrix."), sQuote(arg)) |
548 | 1x |
throw_error("error_bad_matrix", msg) |
549 |
} |
|
550 | ! |
invisible(x) |
551 |
} |
|
552 | ||
553 |
# Check Graph |
|
554 |
# |
|
555 |
# @param x A [`matrix`] to be checked. |
|
556 |
# @param expected An appropriate expected value. |
|
557 |
# @return Throw an error, if any. |
|
558 |
# @author N. Frerebeau |
|
559 |
# @family checking methods |
|
560 |
# @keywords internal |
|
561 |
# @export |
|
562 |
# assert_dag <- function(x) { |
|
563 |
# arg <- deparse(substitute(x)) |
|
564 |
# if (!is_dag(x)) { |
|
565 |
# msg <- sprintf(tr_("%s must not contain cycles."), sQuote(arg)) |
|
566 |
# throw_error("error_bad_graph", msg) |
|
567 |
# } |
|
568 |
# invisible(x) |
|
569 |
# } |
1 |
# STATISTICS |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
# HPDI ========================================================================= |
|
6 |
#' @export |
|
7 |
#' @rdname interval_hdr |
|
8 |
#' @aliases interval_hdr,numeric,numeric-method |
|
9 |
setMethod( |
|
10 |
f = "interval_hdr", |
|
11 |
signature = c(x = "numeric", y = "numeric"), |
|
12 |
definition = function(x, y, level = 0.954) { |
|
13 |
## Compute density |
|
14 | 1x |
y <- y / sum(y) |
15 | ||
16 |
## Order the sample (faster sorting with radix method) |
|
17 | 1x |
sorted <- sort(y, decreasing = TRUE, method = "radix") |
18 | 1x |
i <- min(which(cumsum(sorted) >= sum(y) * level)) |
19 | 1x |
h <- sorted[[i]] |
20 | 1x |
idx <- which(y >= h) |
21 | ||
22 | 1x |
gap <- which(diff(idx) > 1) |
23 | 1x |
inf <- idx[c(1, gap + 1)] |
24 | 1x |
sup <- idx[c(gap, length(idx))] |
25 | ||
26 | 1x |
int <- mapply(FUN = seq, from = inf, to = sup, |
27 | 1x |
SIMPLIFY = FALSE, USE.NAMES = FALSE) |
28 | 2x |
p <- vapply(X = int, FUN = function(i, y) { sum(y[i]) }, |
29 | 1x |
FUN.VALUE = numeric(1), y = y) |
30 | ||
31 | 1x |
cbind(start = x[inf], end = x[sup], p = round(p, digits = 2)) |
32 |
} |
|
33 |
) |
|
34 | ||
35 |
#' @export |
|
36 |
#' @rdname interval_hdr |
|
37 |
#' @aliases interval_hdr,numeric,missing-method |
|
38 |
setMethod( |
|
39 |
f = "interval_hdr", |
|
40 |
signature = c(x = "numeric", y = "missing"), |
|
41 |
definition = function(x, level = 0.954, ...) { |
|
42 |
## Compute density |
|
43 | 1x |
d <- stats::density(x, ...) |
44 | 1x |
methods::callGeneric(x = d$x, y = d$y, level = level) |
45 |
} |
|
46 |
) |
|
47 | ||
48 |
# Credible interval ============================================================ |
|
49 |
#' @export |
|
50 |
#' @rdname interval_credible |
|
51 |
#' @aliases interval_credible,numeric-method |
|
52 |
setMethod( |
|
53 |
f = "interval_credible", |
|
54 |
signature = "numeric", |
|
55 |
definition = function(x, level = 0.95) { |
|
56 |
## Order the sample |
|
57 | 1x |
sorted <- sort(x, method = "radix") # Faster sorting with radix method |
58 | ||
59 |
## Sample size |
|
60 | 1x |
N <- length(x) |
61 | ||
62 |
## Number of data to be outside of the interval |
|
63 | 1x |
outside <- as.integer(N * (1 - level)) |
64 | 1x |
inf <- seq(from = 1L, to = outside + 1L, by = 1L) |
65 | 1x |
sup <- seq(from = N - outside, to = N, by = 1L) |
66 | ||
67 |
## Look for the shortest interval |
|
68 | 1x |
a <- sorted[sup] |
69 | 1x |
b <- sorted[inf] |
70 | 1x |
ind <- which.min(a - b) |
71 | ||
72 | 1x |
cbind(start = b[[ind]], end = a[[ind]], p = level) |
73 |
} |
|
74 |
) |
|
75 | ||
76 |
# Confidence interval ========================================================== |
|
77 |
#' @export |
|
78 |
#' @rdname confidence_mean |
|
79 |
#' @aliases confidence_mean,numeric-method |
|
80 |
setMethod( |
|
81 |
f = "confidence_mean", |
|
82 |
signature = c(object = "numeric"), |
|
83 |
definition = function(object, level = 0.95, type = c("student", "normal")) { |
|
84 | 2x |
z <- zscore(level = level, n = length(object), type = type) |
85 | 2x |
margin <- z * stats::sd(object) / sqrt(length(object)) |
86 | 2x |
interval <- mean(object) + margin * c(-1, 1) |
87 | 2x |
names(interval) <- c("lower", "upper") |
88 | 2x |
interval |
89 |
} |
|
90 |
) |
|
91 | ||
92 |
#' @export |
|
93 |
#' @rdname confidence_binomial |
|
94 |
#' @aliases confidence_binomial,numeric-method |
|
95 |
setMethod( |
|
96 |
f = "confidence_binomial", |
|
97 |
signature = c(object = "numeric"), |
|
98 |
definition = function(object, n, level = 0.95, method = "wald", |
|
99 |
corrected = FALSE) { |
|
100 | 9x |
method <- match.arg(method, several.ok = FALSE) |
101 | ||
102 | 9x |
p <- object / n |
103 | 9x |
q <- 1 - p |
104 | 9x |
alpha <- 1 - level |
105 | ||
106 | 9x |
z <- stats::qnorm(1 - alpha / 2) |
107 | 9x |
margin <- z * sqrt(p * q / n) |
108 | 9x |
if (corrected) { |
109 | 4x |
margin <- margin + 1 / (2 * n) # Wald with continuity correction |
110 |
} |
|
111 | ||
112 | 9x |
interval <- c(lower = pmax(0, p - margin), upper = pmin(1, p + margin)) |
113 | 9x |
interval |
114 |
} |
|
115 |
) |
|
116 | ||
117 |
#' @export |
|
118 |
#' @rdname confidence_multinomial |
|
119 |
#' @aliases confidence_multinomial,numeric-method |
|
120 |
setMethod( |
|
121 |
f = "confidence_multinomial", |
|
122 |
signature = c(object = "numeric"), |
|
123 |
definition = function(object, level = 0.95, method = "wald", |
|
124 |
corrected = FALSE) { |
|
125 | 2x |
method <- match.arg(method, several.ok = FALSE) |
126 | ||
127 | 2x |
n <- sum(object) |
128 | 2x |
f <- switch ( |
129 | 2x |
method, |
130 | 2x |
wald = function(x) confidence_binomial(x, n = n, level = level, |
131 | 2x |
method = "wald", |
132 | 2x |
corrected = corrected) |
133 |
) |
|
134 | ||
135 | 2x |
interval <- vapply(X = object, FUN = f, FUN.VALUE = numeric(2)) |
136 | 2x |
interval <- t(interval) |
137 | 2x |
rownames(interval) <- names(object) |
138 | 2x |
interval |
139 |
} |
|
140 |
) |
|
141 | ||
142 |
zscore <- function(level, n, type = c("student", "normal")) { |
|
143 |
## Validation |
|
144 | 2x |
type <- match.arg(type, several.ok = FALSE) |
145 | ||
146 | 2x |
alpha <- 1 - level |
147 |
switch( |
|
148 | 2x |
type, |
149 | 1x |
normal = stats::qnorm(1 - alpha / 2), # Large sample size |
150 | 1x |
student = stats::qt(1 - alpha / 2, df = n - 1), # Small sample size |
151 |
) |
|
152 |
} |
|
153 | ||
154 |
# Bootstrap ==================================================================== |
|
155 |
#' @export |
|
156 |
#' @rdname bootstrap |
|
157 |
#' @aliases bootstrap,numeric-method |
|
158 |
setMethod( |
|
159 |
f = "bootstrap", |
|
160 |
signature = c(object = "numeric"), |
|
161 |
definition = function(object, do, n, ..., f = NULL) { |
|
162 | 2x |
hat <- do(object, ...) |
163 | ||
164 | 2x |
spl <- sample(object, size = length(object) * n, replace = TRUE) |
165 | 2x |
replicates <- t(matrix(spl, nrow = n)) |
166 | 2x |
values <- apply(X = replicates, MARGIN = 2, FUN = do, ...) |
167 | ||
168 | 1x |
if (is.function(f)) return(f(values)) |
169 | 1x |
summary_bootstrap(values, hat) |
170 |
} |
|
171 |
) |
|
172 | ||
173 |
summary_bootstrap <- function(x, hat) { |
|
174 | 1x |
n <- length(x) |
175 | 1x |
boot_mean <- mean(x) |
176 | 1x |
boot_bias <- boot_mean - hat |
177 | 1x |
boot_error <- stats::sd(x) |
178 | ||
179 | 1x |
results <- c(hat, boot_mean, boot_bias, boot_error) |
180 | 1x |
names(results) <- c("original", "mean", "bias", "error") |
181 | 1x |
results |
182 |
} |
|
183 | ||
184 |
# Jaccknife ==================================================================== |
|
185 |
#' @export |
|
186 |
#' @rdname jackknife |
|
187 |
#' @aliases jackknife,numeric-method |
|
188 |
setMethod( |
|
189 |
f = "jackknife", |
|
190 |
signature = c(object = "numeric"), |
|
191 |
definition = function(object, do, ..., f = NULL) { |
|
192 | 2x |
n <- length(object) |
193 | 2x |
hat <- do(object, ...) |
194 | ||
195 | 2x |
values <- vapply( |
196 | 2x |
X = seq_len(n), |
197 | 2x |
FUN = function(i, x, do, ...) { |
198 | 40x |
do(x[-i], ...) |
199 |
}, |
|
200 | 2x |
FUN.VALUE = double(1), |
201 | 2x |
x = object, do = do, ... |
202 |
) |
|
203 | ||
204 | 1x |
if (is.function(f)) return(f(values)) |
205 | 1x |
summary_jackknife(values, hat) |
206 |
} |
|
207 |
) |
|
208 | ||
209 |
summary_jackknife <- function(x, hat) { |
|
210 | 1x |
n <- length(x) |
211 | 1x |
jack_mean <- mean(x) |
212 | 1x |
jack_bias <- (n - 1) * (jack_mean - hat) |
213 | 1x |
jack_error <- sqrt(((n - 1) / n) * sum((x - jack_mean)^2)) |
214 | ||
215 | 1x |
results <- c(hat, jack_mean, jack_bias, jack_error) |
216 | 1x |
names(results) <- c("original", "mean", "bias", "error") |
217 | 1x |
results |
218 |
} |
1 |
# DATA TRANSFORMATION |
|
2 |
NULL |
|
3 | ||
4 |
#' Rescale Continuous Vector (minimum, maximum) |
|
5 |
#' |
|
6 |
#' Rescales continuous vector to have specified minimum and maximum. |
|
7 |
#' @param x A [`numeric`] vector. |
|
8 |
#' @param to A length-two [`numeric`] vector specifying the output range. |
|
9 |
#' @param from A length-two [`numeric`] vector specifying the input range. |
|
10 |
#' @return A [`numeric`] vector. |
|
11 |
#' @note For internal use only. |
|
12 |
#' @family scales |
|
13 |
#' @export |
|
14 |
scale_range <- function(x, to = c(0, 1), from = range(x, finite = TRUE)) { |
|
15 | ! |
if (.is_zero(to) || .is_zero(from)) return(ifelse(is.na(x), NA, mean(to))) |
16 | 1x |
(x - from[1L]) / diff(from) * diff(to) + to[1L] |
17 |
} |
|
18 | ||
19 |
#' Rescale Continuous Vector (minimum, midpoint, maximum) |
|
20 |
#' |
|
21 |
#' Rescales continuous vector to have specified minimum, midpoint and maximum. |
|
22 |
#' @param x A [`numeric`] vector. |
|
23 |
#' @param to A length-two [`numeric`] vector specifying the output range. |
|
24 |
#' @param from A length-two [`numeric`] vector specifying the input range. |
|
25 |
#' @param midpoint A length-one [`numeric`] vector specifying the mid-point of |
|
26 |
#' input range. |
|
27 |
#' @return A [`numeric`] vector. |
|
28 |
#' @note For internal use only. |
|
29 |
#' @family scales |
|
30 |
#' @export |
|
31 |
scale_midpoint <- function(x, to = c(0, 1), from = range(x, finite = TRUE), midpoint = 0) { |
|
32 | ! |
if (.is_zero(to) || .is_zero(from)) return(ifelse(is.na(x), NA, mean(to))) |
33 | 1x |
extent <- 2 * max(abs(from - midpoint)) |
34 | 1x |
(x - midpoint) / extent * diff(to) + mean(to) |
35 |
} |
|
36 | ||
37 |
.is_zero <- function(x, tolerance = sqrt(.Machine$double.eps)) { |
|
38 | 4x |
diff(range(x)) <= tolerance |
39 |
} |
1 |
# GENERIC METHODS |
|
2 | ||
3 |
# Data preparation ============================================================= |
|
4 |
## Count ----------------------------------------------------------------------- |
|
5 |
#' Count Values Using a Predicate |
|
6 |
#' |
|
7 |
#' Counts values by rows/columns using a predicate function. |
|
8 |
#' @param x An \R object (should be a [`matrix`] or a [`data.frame`]). |
|
9 |
#' @param f A predicate [`function`]. |
|
10 |
#' @param margin A length-one [`numeric`] vector giving the subscripts which the |
|
11 |
#' function will be applied over (`1` indicates rows, `2` indicates columns). |
|
12 |
#' @param negate A [`logical`] scalar: should the negation of `f` be used |
|
13 |
#' instead of `f`? |
|
14 |
#' @param na.rm A [`logical`] scalar: should `NA` values be stripped before the |
|
15 |
#' computation proceeds? |
|
16 |
#' @param ... Further arguments to be passed to `f`. |
|
17 |
#' @return A [`numeric`] vector. |
|
18 |
#' @example inst/examples/ex-count.R |
|
19 |
#' @author N. Frerebeau |
|
20 |
#' @docType methods |
|
21 |
#' @family data preparation tools |
|
22 |
#' @aliases count-method |
|
23 |
setGeneric( |
|
24 |
name = "count", |
|
25 | 78x |
def = function(x, ...) standardGeneric("count") |
26 |
) |
|
27 | ||
28 |
## Detect ---------------------------------------------------------------------- |
|
29 |
#' Find Rows/Columns Using a Predicate |
|
30 |
#' |
|
31 |
#' Finds rows/columns in an array-like object using a predicate function. |
|
32 |
#' @inheritParams count |
|
33 |
#' @param all A [`logical`] scalar. If `TRUE`, only the rows/columns whose |
|
34 |
#' values all meet the condition defined by `f` are considered. If `FALSE` |
|
35 |
#' (the default), only rows/columns where at least one value validates the |
|
36 |
#' condition defined by `f` are considered. |
|
37 |
#' @param ... Further arguments to be passed to `f`. |
|
38 |
#' @return A [`logical`] vector. |
|
39 |
#' @example inst/examples/ex-detect.R |
|
40 |
#' @author N. Frerebeau |
|
41 |
#' @docType methods |
|
42 |
#' @family data preparation tools |
|
43 |
#' @aliases detect-method |
|
44 |
setGeneric( |
|
45 |
name = "detect", |
|
46 | 59x |
def = function(x, ...) standardGeneric("detect") |
47 |
) |
|
48 | ||
49 |
## Keep ------------------------------------------------------------------------ |
|
50 |
#' Keep Rows/Columns Using a Predicate |
|
51 |
#' |
|
52 |
#' Keeps rows/columns in an array-like object using a predicate function. |
|
53 |
#' @inheritParams detect |
|
54 |
#' @param verbose A [`logical`] scalar: should \R report extra information |
|
55 |
#' on progress? |
|
56 |
#' @example inst/examples/ex-keep.R |
|
57 |
#' @author N. Frerebeau |
|
58 |
#' @docType methods |
|
59 |
#' @family data preparation tools |
|
60 |
#' @aliases keep-method |
|
61 |
setGeneric( |
|
62 |
name = "keep", |
|
63 | 10x |
def = function(x, ...) standardGeneric("keep") |
64 |
) |
|
65 | ||
66 |
#' @rdname keep |
|
67 |
#' @aliases keep_columns-method |
|
68 |
setGeneric( |
|
69 |
name = "keep_columns", |
|
70 | 5x |
def = function(x, ...) standardGeneric("keep_columns") |
71 |
) |
|
72 | ||
73 |
#' @rdname keep |
|
74 |
#' @aliases keep_rows-method |
|
75 |
setGeneric( |
|
76 |
name = "keep_rows", |
|
77 | 5x |
def = function(x, ...) standardGeneric("keep_rows") |
78 |
) |
|
79 | ||
80 |
## Discard --------------------------------------------------------------------- |
|
81 |
#' Remove Rows/Columns Using a Predicate |
|
82 |
#' |
|
83 |
#' Removes rows/columns in an array-like object using a predicate function. |
|
84 |
#' @inheritParams detect |
|
85 |
#' @param verbose A [`logical`] scalar: should \R report extra information |
|
86 |
#' on progress? |
|
87 |
#' @example inst/examples/ex-discard.R |
|
88 |
#' @author N. Frerebeau |
|
89 |
#' @docType methods |
|
90 |
#' @family data preparation tools |
|
91 |
#' @aliases discard-method |
|
92 |
setGeneric( |
|
93 |
name = "discard", |
|
94 | 39x |
def = function(x, ...) standardGeneric("discard") |
95 |
) |
|
96 | ||
97 |
#' @rdname discard |
|
98 |
#' @aliases discard_columns-method |
|
99 |
setGeneric( |
|
100 |
name = "discard_columns", |
|
101 | 4x |
def = function(x, ...) standardGeneric("discard_columns") |
102 |
) |
|
103 | ||
104 |
#' @rdname discard |
|
105 |
#' @aliases discard_rows-method |
|
106 |
setGeneric( |
|
107 |
name = "discard_rows", |
|
108 | 4x |
def = function(x, ...) standardGeneric("discard_rows") |
109 |
) |
|
110 | ||
111 |
## Compact --------------------------------------------------------------------- |
|
112 |
#' Remove Empty Rows/Columns |
|
113 |
#' |
|
114 |
#' Removes empty rows/columns in an array-like object. |
|
115 |
#' @inheritParams detect |
|
116 |
#' @param verbose A [`logical`] scalar: should \R report extra information |
|
117 |
#' on progress? |
|
118 |
#' @param ... Currently not used. |
|
119 |
#' @details |
|
120 |
#' A row/column is empty if it contains only zeros (if of type `numeric`) |
|
121 |
#' or zero length character strings (if of type `character`). |
|
122 |
#' @example inst/examples/ex-compact.R |
|
123 |
#' @author N. Frerebeau |
|
124 |
#' @docType methods |
|
125 |
#' @family data preparation tools |
|
126 |
#' @aliases compact-method |
|
127 |
setGeneric( |
|
128 |
name = "compact", |
|
129 | 12x |
def = function(x, ...) standardGeneric("compact") |
130 |
) |
|
131 | ||
132 |
#' @rdname compact |
|
133 |
#' @aliases compact_columns-method |
|
134 |
setGeneric( |
|
135 |
name = "compact_columns", |
|
136 | 5x |
def = function(x, ...) standardGeneric("compact_columns") |
137 |
) |
|
138 | ||
139 |
#' @rdname compact |
|
140 |
#' @aliases compact_rows-method |
|
141 |
setGeneric( |
|
142 |
name = "compact_rows", |
|
143 | 7x |
def = function(x, ...) standardGeneric("compact_rows") |
144 |
) |
|
145 | ||
146 |
## Seek ------------------------------------------------------------------------ |
|
147 |
#' Search Rows/Columns by Name |
|
148 |
#' |
|
149 |
#' Searches rows/columns by name in an array-like object. |
|
150 |
#' @param x An \R object (should be a [`matrix`] or a [`data.frame`]). |
|
151 |
#' @param select A [`function`] to be applied to the row/column names |
|
152 |
#' (e.g. [startsWith()]) that returns an `integer` or `logical` vector. |
|
153 |
#' @param names A [`character`] vector of row/column names to look for. |
|
154 |
#' Only used if `select` is `NULL`. |
|
155 |
#' @param ... Further arguments to be passed to `select`. |
|
156 |
#' @return |
|
157 |
#' An [`integer`] vector or `NULL`. |
|
158 |
#' @example inst/examples/ex-seek.R |
|
159 |
#' @author N. Frerebeau |
|
160 |
#' @docType methods |
|
161 |
#' @family data preparation tools |
|
162 |
#' @name seek |
|
163 |
#' @rdname seek |
|
164 |
NULL |
|
165 | ||
166 |
#' @rdname seek |
|
167 |
#' @aliases seek_columns-method |
|
168 |
setGeneric( |
|
169 |
name = "seek_columns", |
|
170 | 8x |
def = function(x, ...) standardGeneric("seek_columns") |
171 |
) |
|
172 | ||
173 |
#' @rdname seek |
|
174 |
#' @aliases seek_rows-method |
|
175 |
setGeneric( |
|
176 |
name = "seek_rows", |
|
177 | 8x |
def = function(x, ...) standardGeneric("seek_rows") |
178 |
) |
|
179 | ||
180 |
## Get ------------------------------------------------------------------------- |
|
181 |
#' Get Rows/Columns by Name |
|
182 |
#' |
|
183 |
#' Returns rows/columns selected by name in an array-like object. |
|
184 |
#' @inheritParams seek |
|
185 |
#' @return An object of the same sort as `x`. |
|
186 |
#' @example inst/examples/ex-seek.R |
|
187 |
#' @author N. Frerebeau |
|
188 |
#' @docType methods |
|
189 |
#' @family data preparation tools |
|
190 |
#' @name get |
|
191 |
#' @rdname get |
|
192 |
NULL |
|
193 | ||
194 |
#' @rdname get |
|
195 |
#' @aliases get_columns-method |
|
196 |
setGeneric( |
|
197 |
name = "get_columns", |
|
198 | 1x |
def = function(x, ...) standardGeneric("get_columns") |
199 |
) |
|
200 | ||
201 |
#' @rdname get |
|
202 |
#' @aliases get_rows-method |
|
203 |
setGeneric( |
|
204 |
name = "get_rows", |
|
205 | 1x |
def = function(x, ...) standardGeneric("get_rows") |
206 |
) |
|
207 | ||
208 |
## Assign ---------------------------------------------------------------------- |
|
209 |
#' Assign a Specific Row/Column to the Column/Row Names |
|
210 |
#' |
|
211 |
#' @param x A [`data.frame`]. |
|
212 |
#' @param row A length-one [`numeric`] vector specifying the row number that is |
|
213 |
#' to become the column names. |
|
214 |
#' @param column A length-one [`numeric`] vector specifying the column number |
|
215 |
#' that is to become the row names. |
|
216 |
#' @param remove A [`logical`] scalar: should the specified row/column be removed |
|
217 |
#' after making it the column/row names? |
|
218 |
#' @param ... Currently not used. |
|
219 |
#' @example inst/examples/ex-assign.R |
|
220 |
#' @return A [`data.frame`]. |
|
221 |
#' @author N. Frerebeau |
|
222 |
#' @docType methods |
|
223 |
#' @family data preparation tools |
|
224 |
#' @name assign |
|
225 |
#' @rdname assign |
|
226 |
NULL |
|
227 | ||
228 |
#' @rdname assign |
|
229 |
#' @aliases assign_colnames-method |
|
230 |
setGeneric( |
|
231 |
name = "assign_colnames", |
|
232 | 1x |
def = function(x, ...) standardGeneric("assign_colnames") |
233 |
) |
|
234 | ||
235 |
#' @rdname assign |
|
236 |
#' @aliases assign_rownames-method |
|
237 |
setGeneric( |
|
238 |
name = "assign_rownames", |
|
239 | 1x |
def = function(x, ...) standardGeneric("assign_rownames") |
240 |
) |
|
241 | ||
242 |
## Append ---------------------------------------------------------------------- |
|
243 |
#' Convert Row Names to an Explicit Column |
|
244 |
#' |
|
245 |
#' @param x A [`data.frame`]. |
|
246 |
#' @param after A length-one [`numeric`] vector specifying a subscript, |
|
247 |
#' after which the row names are to be appended. |
|
248 |
#' @param var A [`character`] string giving the name of name of the new column. |
|
249 |
#' @param remove A [`logical`] scalar: should the row names be removed? |
|
250 |
#' @param ... Currently not used. |
|
251 |
#' @example inst/examples/ex-assign.R |
|
252 |
#' @return A [`data.frame`]. |
|
253 |
#' @author N. Frerebeau |
|
254 |
#' @docType methods |
|
255 |
#' @family data preparation tools |
|
256 |
#' @aliases append_rownames-method |
|
257 |
setGeneric( |
|
258 |
name = "append_rownames", |
|
259 | 1x |
def = function(x, ...) standardGeneric("append_rownames") |
260 |
) |
|
261 | ||
262 |
#' Add a (Named) Vector as a Column |
|
263 |
#' |
|
264 |
#' @param x A [`data.frame`]. |
|
265 |
#' @param column A (named) `vector`. |
|
266 |
#' @param after A length-one [`numeric`] vector specifying a subscript, |
|
267 |
#' after which the new column is to be appended. |
|
268 |
#' @param var A [`character`] string giving the name of the new column. |
|
269 |
#' @param ... Currently not used. |
|
270 |
#' @details |
|
271 |
#' If `column` is named, names will be matched to the row names of `x`. Only |
|
272 |
#' the first match is retained, and elements of `column` without a match are |
|
273 |
#' removed. This allows to add as a column a vector whose length is less than |
|
274 |
#' the number of rows in `x` (`NA`s will be inserted). |
|
275 |
#' @example inst/examples/ex-append.R |
|
276 |
#' @return A [`data.frame`]. |
|
277 |
#' @author N. Frerebeau |
|
278 |
#' @docType methods |
|
279 |
#' @family data preparation tools |
|
280 |
#' @aliases append_column-method |
|
281 |
setGeneric( |
|
282 |
name = "append_column", |
|
283 | 3x |
def = function(x, ...) standardGeneric("append_column") |
284 |
) |
|
285 | ||
286 |
# Data cleaning ================================================================ |
|
287 |
## NA -------------------------------------------------------------------------- |
|
288 |
#' Remove Rows/Columns with Missing Values |
|
289 |
#' |
|
290 |
#' Removes rows/columns that contain [missing values][NA]. |
|
291 |
#' @inheritParams detect |
|
292 |
#' @param verbose A [`logical`] scalar: should \R report extra information |
|
293 |
#' on progress? |
|
294 |
#' @param ... Currently not used. |
|
295 |
#' @example inst/examples/ex-missing.R |
|
296 |
#' @author N. Frerebeau |
|
297 |
#' @docType methods |
|
298 |
#' @family data cleaning tools |
|
299 |
#' @aliases remove_NA-method |
|
300 |
#' @aliases missing |
|
301 |
setGeneric( |
|
302 |
name = "remove_NA", |
|
303 | 4x |
def = function(x, ...) standardGeneric("remove_NA") |
304 |
) |
|
305 | ||
306 |
#' Replace Missing Values |
|
307 |
#' |
|
308 |
#' Replaces [missing values][NA] values. |
|
309 |
#' @inheritParams detect |
|
310 |
#' @param value A possible replacement value. |
|
311 |
#' @param ... Currently not used. |
|
312 |
#' @example inst/examples/ex-missing.R |
|
313 |
#' @author N. Frerebeau |
|
314 |
#' @docType methods |
|
315 |
#' @family data cleaning tools |
|
316 |
#' @aliases replace_NA-method |
|
317 |
setGeneric( |
|
318 |
name = "replace_NA", |
|
319 | 2x |
def = function(x, ...) standardGeneric("replace_NA") |
320 |
) |
|
321 | ||
322 |
## Inf ------------------------------------------------------------------------- |
|
323 |
#' Remove Rows/Columns with Infinite Values |
|
324 |
#' |
|
325 |
#' Removes rows/columns that contain [infinite values][is.finite]. |
|
326 |
#' @inheritParams detect |
|
327 |
#' @param verbose A [`logical`] scalar: should \R report extra information |
|
328 |
#' on progress? |
|
329 |
#' @param ... Currently not used. |
|
330 |
#' @example inst/examples/ex-infinite.R |
|
331 |
#' @author N. Frerebeau |
|
332 |
#' @docType methods |
|
333 |
#' @family data cleaning tools |
|
334 |
#' @aliases remove_Inf-method |
|
335 |
setGeneric( |
|
336 |
name = "remove_Inf", |
|
337 | 4x |
def = function(x, ...) standardGeneric("remove_Inf") |
338 |
) |
|
339 | ||
340 |
#' Replace Infinite Values |
|
341 |
#' |
|
342 |
#' Replaces [infinite values][is.finite] values. |
|
343 |
#' @inheritParams detect |
|
344 |
#' @param value A possible replacement value. |
|
345 |
#' @param ... Currently not used. |
|
346 |
#' @example inst/examples/ex-infinite.R |
|
347 |
#' @author N. Frerebeau |
|
348 |
#' @docType methods |
|
349 |
#' @family data cleaning tools |
|
350 |
#' @aliases replace_Inf-method |
|
351 |
setGeneric( |
|
352 |
name = "replace_Inf", |
|
353 | 2x |
def = function(x, ...) standardGeneric("replace_Inf") |
354 |
) |
|
355 | ||
356 |
## Zeros ----------------------------------------------------------------------- |
|
357 |
#' Remove Rows/Columns with Zeros |
|
358 |
#' |
|
359 |
#' Removes rows/columns that contain zeros. |
|
360 |
#' @inheritParams detect |
|
361 |
#' @param verbose A [`logical`] scalar: should \R report extra information |
|
362 |
#' on progress? |
|
363 |
#' @param ... Currently not used. |
|
364 |
#' @example inst/examples/ex-zero.R |
|
365 |
#' @author N. Frerebeau |
|
366 |
#' @docType methods |
|
367 |
#' @family data cleaning tools |
|
368 |
#' @aliases remove_zero-method |
|
369 |
#' @aliases zero |
|
370 |
setGeneric( |
|
371 |
name = "remove_zero", |
|
372 | 4x |
def = function(x, ...) standardGeneric("remove_zero") |
373 |
) |
|
374 | ||
375 |
#' Replace Zeros |
|
376 |
#' |
|
377 |
#' Replaces zeros. |
|
378 |
#' @inheritParams detect |
|
379 |
#' @param value A possible replacement value. |
|
380 |
#' @param ... Currently not used. |
|
381 |
#' @example inst/examples/ex-zero.R |
|
382 |
#' @author N. Frerebeau |
|
383 |
#' @docType methods |
|
384 |
#' @family data cleaning tools |
|
385 |
#' @aliases replace_zero-method |
|
386 |
setGeneric( |
|
387 |
name = "replace_zero", |
|
388 | 2x |
def = function(x, ...) standardGeneric("replace_zero") |
389 |
) |
|
390 | ||
391 |
## Empty string ---------------------------------------------------------------- |
|
392 |
#' Remove Rows/Columns with Empty String |
|
393 |
#' |
|
394 |
#' Removes rows/columns that contain empty strings. |
|
395 |
#' @inheritParams detect |
|
396 |
#' @param verbose A [`logical`] scalar: should \R report extra information |
|
397 |
#' on progress? |
|
398 |
#' @param ... Currently not used. |
|
399 |
#' @example inst/examples/ex-empty.R |
|
400 |
#' @author N. Frerebeau |
|
401 |
#' @docType methods |
|
402 |
#' @family data cleaning tools |
|
403 |
#' @aliases remove_empty-method |
|
404 |
setGeneric( |
|
405 |
name = "remove_empty", |
|
406 | 4x |
def = function(x, ...) standardGeneric("remove_empty") |
407 |
) |
|
408 | ||
409 |
#' Replace Empty String |
|
410 |
#' |
|
411 |
#' Replaces empty strings. |
|
412 |
#' @inheritParams detect |
|
413 |
#' @param value A possible replacement value. |
|
414 |
#' @param ... Currently not used. |
|
415 |
#' @example inst/examples/ex-empty.R |
|
416 |
#' @author N. Frerebeau |
|
417 |
#' @docType methods |
|
418 |
#' @family data cleaning tools |
|
419 |
#' @aliases replace_empty-method |
|
420 |
setGeneric( |
|
421 |
name = "replace_empty", |
|
422 | 2x |
def = function(x, ...) standardGeneric("replace_empty") |
423 |
) |
|
424 | ||
425 |
## Constant -------------------------------------------------------------------- |
|
426 |
#' Remove Constant Columns |
|
427 |
#' |
|
428 |
#' @param x An \R object (should be a [`matrix`] or a [`data.frame`]). |
|
429 |
#' @param na.rm A [`logical`] scalar: should `NA` values be stripped before the |
|
430 |
#' computation proceeds? |
|
431 |
#' @param verbose A [`logical`] scalar: should \R report extra information |
|
432 |
#' on progress? |
|
433 |
#' @param ... Currently not used. |
|
434 |
#' @example inst/examples/ex-constant.R |
|
435 |
#' @author N. Frerebeau |
|
436 |
#' @docType methods |
|
437 |
#' @family data cleaning tools |
|
438 |
#' @aliases remove_constant-method |
|
439 |
setGeneric( |
|
440 |
name = "remove_constant", |
|
441 | 3x |
def = function(x, ...) standardGeneric("remove_constant") |
442 |
) |
|
443 | ||
444 |
## Whitespace ------------------------------------------------------------------ |
|
445 |
#' Remove Leading/Trailing Whitespace |
|
446 |
#' |
|
447 |
#' @param x An \R object (should be a [`matrix`] or a [`data.frame`]). |
|
448 |
#' @param which A [`character`] string specifying whether to remove `both` |
|
449 |
#' leading and trailing whitespace (default), or only leading ("`left`") or |
|
450 |
#' trailing ("`right`"). |
|
451 |
#' @param squish A [`logical`] scalar: should all internal whitespace be |
|
452 |
#' replaced with a single space? |
|
453 |
#' @param ... Currently not used. |
|
454 |
#' @example inst/examples/ex-whitespace.R |
|
455 |
#' @seealso [trimws()] |
|
456 |
#' @author N. Frerebeau |
|
457 |
#' @docType methods |
|
458 |
#' @family data cleaning tools |
|
459 |
#' @aliases clean_whitespace-method |
|
460 |
setGeneric( |
|
461 |
name = "clean_whitespace", |
|
462 | 5x |
def = function(x, ...) standardGeneric("clean_whitespace") |
463 |
) |
|
464 | ||
465 |
# Data summary ================================================================= |
|
466 |
#' Data Description |
|
467 |
#' |
|
468 |
#' Describes an object. |
|
469 |
#' @param x An \R object (should be a [`matrix`] or a [`data.frame`]). |
|
470 |
#' @param ... Currently not used. |
|
471 |
#' @return |
|
472 |
#' `describe()` is called for its side-effects. Invisibly returns `x`. |
|
473 |
#' @example inst/examples/ex-describe.R |
|
474 |
#' @author N. Frerebeau |
|
475 |
#' @docType methods |
|
476 |
#' @family data summaries |
|
477 |
#' @aliases describe-method |
|
478 |
setGeneric( |
|
479 |
name = "describe", |
|
480 | 1x |
def = function(x, ...) standardGeneric("describe") |
481 |
) |
|
482 | ||
483 |
#' Sparsity |
|
484 |
#' |
|
485 |
#' Computes data sparsity (proportion of zeros). |
|
486 |
#' @param x An \R object (should be a [`matrix`] or a [`data.frame`]). |
|
487 |
#' @param count A [`logical`] scalar: should a count be returned instead of a |
|
488 |
#' proportion? |
|
489 |
#' @param ... Currently not used. |
|
490 |
#' @details |
|
491 |
#' If `x` is a `data.frame`, sparsity is computed on `numeric` variables only. |
|
492 |
#' @return |
|
493 |
#' A length-one [`numeric`] vector. |
|
494 |
#' @example inst/examples/ex-describe.R |
|
495 |
#' @author N. Frerebeau |
|
496 |
#' @docType methods |
|
497 |
#' @family data summaries |
|
498 |
#' @aliases sparsity-method |
|
499 |
setGeneric( |
|
500 |
name = "sparsity", |
|
501 | 3x |
def = function(x, ...) standardGeneric("sparsity") |
502 |
) |
|
503 | ||
504 |
# Mathematics ================================================================== |
|
505 |
#' Least Common Multiple |
|
506 |
#' |
|
507 |
#' Computes the lowest common multiple of the denominators of a set of |
|
508 |
#' fractions. |
|
509 |
#' @param x,y A [`numeric`] vector. |
|
510 |
#' @return A [`numeric`] vector. |
|
511 |
#' @author N. Frerebeau |
|
512 |
#' @docType methods |
|
513 |
#' @family mathematic functions |
|
514 |
#' @aliases math_lcm-method |
|
515 |
setGeneric( |
|
516 |
name = "math_lcm", |
|
517 | 1x |
def = function(x, y) standardGeneric("math_lcm") |
518 |
) |
|
519 | ||
520 |
#' Greatest Common Divisor |
|
521 |
#' |
|
522 |
#' Computes the greatest common divisor (GCD) of two integer using the Euclidean |
|
523 |
#' algorithm. |
|
524 |
#' @param x,y A [`numeric`] vector. |
|
525 |
#' @return A [`numeric`] vector. |
|
526 |
#' @author N. Frerebeau |
|
527 |
#' @docType methods |
|
528 |
#' @family mathematic functions |
|
529 |
#' @aliases math_gcd-method |
|
530 |
setGeneric( |
|
531 |
name = "math_gcd", |
|
532 | 12x |
def = function(x, y) standardGeneric("math_gcd") |
533 |
) |
|
534 | ||
535 |
# Statistics =================================================================== |
|
536 |
## Interval -------------------------------------------------------------------- |
|
537 |
#' Highest Density Regions |
|
538 |
#' |
|
539 |
#' @param x A [`numeric`] vector giving the coordinates of the points where |
|
540 |
#' the density is estimated. |
|
541 |
#' @param y A [`numeric`] vector giving the estimated density values. |
|
542 |
#' If `y` is missing and `x` is a `numeric` vector, density estimates will be |
|
543 |
#' computed from `x`. |
|
544 |
#' @param level A length-one [`numeric`] vector giving the confidence level. |
|
545 |
#' @param ... Further arguments to be passed to [stats::density()]. |
|
546 |
#' @return |
|
547 |
#' A three-columns `numeric` [`matrix`] giving the lower and upper boundaries |
|
548 |
#' of the HPD interval and associated probabilities. |
|
549 |
#' @references |
|
550 |
#' Hyndman, R. J. (1996). Computing and graphing highest density regions. |
|
551 |
#' *American Statistician*, 50: 120-126. \doi{10.2307/2684423}. |
|
552 |
#' @example inst/examples/ex-interval.R |
|
553 |
#' @author N. Frerebeau |
|
554 |
#' @family summary statistics |
|
555 |
#' @docType methods |
|
556 |
#' @aliases interval_hdr-method |
|
557 |
setGeneric( |
|
558 |
name = "interval_hdr", |
|
559 | 2x |
def = function(x, y, ...) standardGeneric("interval_hdr") |
560 |
) |
|
561 | ||
562 |
#' Bayesian Credible Interval |
|
563 |
#' |
|
564 |
#' Computes the shortest credible interval within which an unobserved parameter |
|
565 |
#' value falls with a particular probability. |
|
566 |
#' @param x A [`numeric`] vector. |
|
567 |
#' @param level A length-one [`numeric`] vector giving the confidence level. |
|
568 |
#' @param ... Currently not used. |
|
569 |
#' @return |
|
570 |
#' A three-columns `numeric` [`matrix`] giving the lower and upper boundaries |
|
571 |
#' of the credible interval and associated probability. |
|
572 |
#' @example inst/examples/ex-interval.R |
|
573 |
#' @author N. Frerebeau |
|
574 |
#' @family summary statistics |
|
575 |
#' @docType methods |
|
576 |
#' @aliases interval_credible-method |
|
577 |
setGeneric( |
|
578 |
name = "interval_credible", |
|
579 | 1x |
def = function(x, ...) standardGeneric("interval_credible") |
580 |
) |
|
581 | ||
582 |
## Confidence ------------------------------------------------------------------ |
|
583 |
#' Confidence Interval for a Mean |
|
584 |
#' |
|
585 |
#' Computes a confidence interval for a mean at a desired level of significance. |
|
586 |
#' @param object A [`numeric`] vector. |
|
587 |
#' @param level A length-one [`numeric`] vector giving the confidence level. |
|
588 |
#' Must be a single number between \eqn{0} and \eqn{1}. |
|
589 |
#' @param type A [`character`] string giving the type of confidence |
|
590 |
#' interval to be returned. It must be one "`student`" (the default) or |
|
591 |
#' "`normal`". Any unambiguous substring can be given. |
|
592 |
#' @param ... Currently not used. |
|
593 |
#' @return A length-two [`numeric`] vector giving the lower and upper confidence |
|
594 |
#' limits. |
|
595 |
#' @example inst/examples/ex-statistics.R |
|
596 |
#' @author N. Frerebeau |
|
597 |
#' @docType methods |
|
598 |
#' @family summary statistics |
|
599 |
#' @aliases confidence_mean-method |
|
600 |
setGeneric( |
|
601 |
name = "confidence_mean", |
|
602 | 2x |
def = function(object, ...) standardGeneric("confidence_mean") |
603 |
) |
|
604 | ||
605 |
#' Confidence Interval for Binomial Proportions |
|
606 |
#' |
|
607 |
#' Computes a Wald interval for a proportion at a desired level of significance. |
|
608 |
#' @param object A [`numeric`] vector giving the number of success. |
|
609 |
#' @param n A length-one [`numeric`] vector giving the number of trials. |
|
610 |
#' @param level A length-one [`numeric`] vector giving the confidence level. |
|
611 |
#' Must be a single number between \eqn{0} and \eqn{1}. |
|
612 |
#' @param method A [`character`] string specifying the method to be used. |
|
613 |
#' Any unambiguous substring can be used. |
|
614 |
#' @param corrected A [`logical`] scalar: should continuity correction be used? |
|
615 |
#' Only used if `method` is "`wald`". |
|
616 |
#' @param ... Currently not used. |
|
617 |
#' @return A length-two [`numeric`] vector giving the lower and upper confidence |
|
618 |
#' limits. |
|
619 |
#' @example inst/examples/ex-statistics.R |
|
620 |
#' @author N. Frerebeau |
|
621 |
#' @docType methods |
|
622 |
#' @family summary statistics |
|
623 |
#' @aliases confidence_binomial-method |
|
624 |
setGeneric( |
|
625 |
name = "confidence_binomial", |
|
626 | 9x |
def = function(object, ...) standardGeneric("confidence_binomial") |
627 |
) |
|
628 | ||
629 |
#' Confidence Interval for Multinomial Proportions |
|
630 |
#' |
|
631 |
#' Computes a Wald interval for a proportion at a desired level of significance. |
|
632 |
#' @param object A [`numeric`] vector of positive integers giving the number of |
|
633 |
#' occurrences of each class. |
|
634 |
#' @param level A length-one [`numeric`] vector giving the confidence level. |
|
635 |
#' Must be a single number between \eqn{0} and \eqn{1}. |
|
636 |
#' @param method A [`character`] string specifying the method to be used. |
|
637 |
#' Any unambiguous substring can be used. |
|
638 |
#' @param corrected A [`logical`] scalar: should continuity correction be used? |
|
639 |
#' Only used if `method` is "`wald`". |
|
640 |
#' @param ... Currently not used. |
|
641 |
#' @return A two column [`numeric`] `matrix` giving the lower and upper |
|
642 |
#' confidence limits. |
|
643 |
#' @example inst/examples/ex-statistics.R |
|
644 |
#' @author N. Frerebeau |
|
645 |
#' @docType methods |
|
646 |
#' @family summary statistics |
|
647 |
#' @aliases confidence_multinomial-method |
|
648 |
setGeneric( |
|
649 |
name = "confidence_multinomial", |
|
650 | 2x |
def = function(object, ...) standardGeneric("confidence_multinomial") |
651 |
) |
|
652 | ||
653 |
# Resampling =================================================================== |
|
654 |
## Bootstrap ------------------------------------------------------------------- |
|
655 |
#' Bootstrap Estimation |
|
656 |
#' |
|
657 |
#' Samples randomly from the elements of `object` with replacement. |
|
658 |
#' @param object A [`numeric`] vector. |
|
659 |
#' @param do A [`function`] that takes `object` as an argument and returns a |
|
660 |
#' single numeric value. |
|
661 |
#' @param n A non-negative [`integer`] giving the number of bootstrap |
|
662 |
#' replications. |
|
663 |
#' @param f A [`function`] that takes a single numeric vector (the result of |
|
664 |
#' `do`) as argument. |
|
665 |
#' @param ... Extra arguments to be passed to `do`. |
|
666 |
#' @return |
|
667 |
#' If `f` is `NULL` (the default), `bootstrap()` returns a named `numeric` |
|
668 |
#' vector with the following elements: |
|
669 |
#' \describe{ |
|
670 |
#' \item{`original`}{The observed value of `do` applied to `object`.} |
|
671 |
#' \item{`mean`}{The bootstrap estimate of mean of `do`.} |
|
672 |
#' \item{`bias`}{The bootstrap estimate of bias of `do`.} |
|
673 |
#' \item{`error`}{he bootstrap estimate of standard error of `do`.} |
|
674 |
#' } |
|
675 |
#' |
|
676 |
#' If `f` is a `function`, `bootstrap()` returns the result of `f` applied to |
|
677 |
#' the `n` values of `do`. |
|
678 |
#' @example inst/examples/ex-resample.R |
|
679 |
#' @author N. Frerebeau |
|
680 |
#' @docType methods |
|
681 |
#' @family resampling methods |
|
682 |
#' @rdname bootstrap |
|
683 |
#' @aliases bootstrap-method |
|
684 |
setGeneric( |
|
685 |
name = "bootstrap", |
|
686 | 2x |
def = function(object, ...) standardGeneric("bootstrap") |
687 |
) |
|
688 | ||
689 |
## Jackknife ------------------------------------------------------------------- |
|
690 |
#' Jackknife Estimation |
|
691 |
#' |
|
692 |
#' @param object A [`numeric`] vector. |
|
693 |
#' @param do A [`function`] that takes `object` as an argument and returns a |
|
694 |
#' single numeric value. |
|
695 |
#' @param ... Extra arguments to be passed to `do`. |
|
696 |
#' @param f A [`function`] that takes a single numeric vector (the leave-one-out |
|
697 |
#' values of `do`) as argument. |
|
698 |
#' @return |
|
699 |
#' If `f` is `NULL` (the default), `jackknife()` returns a named `numeric` |
|
700 |
#' vector with the following elements: |
|
701 |
#' \describe{ |
|
702 |
#' \item{`original`}{The observed value of `do` applied to `object`.} |
|
703 |
#' \item{`mean`}{The jackknife estimate of mean of `do`.} |
|
704 |
#' \item{`bias`}{The jackknife estimate of bias of `do`.} |
|
705 |
#' \item{`error`}{he jackknife estimate of standard error of `do`.} |
|
706 |
#' } |
|
707 |
#' |
|
708 |
#' If `f` is a `function`, `jackknife()` returns the result of `f` applied to |
|
709 |
#' the leave-one-out values of `do`. |
|
710 |
#' @example inst/examples/ex-resample.R |
|
711 |
#' @author N. Frerebeau |
|
712 |
#' @docType methods |
|
713 |
#' @family resampling methods |
|
714 |
#' @rdname jackknife |
|
715 |
#' @aliases jackknife-method |
|
716 |
setGeneric( |
|
717 |
name = "jackknife", |
|
718 | 2x |
def = function(object, ...) standardGeneric("jackknife") |
719 |
) |
1 |
# DATA SUMMARY: SPARCITY |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
#' @export |
|
6 |
#' @rdname sparsity |
|
7 |
#' @aliases sparsity,matrix-method |
|
8 |
setMethod( |
|
9 |
f = "sparsity", |
|
10 |
signature = c(x = "matrix"), |
|
11 |
definition = function(x, count = FALSE) { |
|
12 | ! |
zeros <- sum(count(x, f = is_zero_numeric, margin = 2, na.rm = TRUE)) |
13 | ! |
if (count) return(zeros) |
14 | ||
15 |
## Proportion |
|
16 | ! |
total <- prod(dim(x)) |
17 | ! |
zeros / total |
18 |
} |
|
19 |
) |
|
20 | ||
21 |
#' @export |
|
22 |
#' @rdname sparsity |
|
23 |
#' @aliases sparsity,data.frame-method |
|
24 |
setMethod( |
|
25 |
f = "sparsity", |
|
26 |
signature = c(x = "data.frame"), |
|
27 |
definition = function(x, count = FALSE) { |
|
28 | 3x |
zeros <- sum(count(x, f = is_zero_numeric, margin = 2, na.rm = TRUE)) |
29 | 1x |
if (count) return(zeros) |
30 | ||
31 |
## Count numeric values only |
|
32 | 2x |
num <- vapply(X = x, FUN = is.numeric, FUN.VALUE = logical(1)) |
33 | 2x |
total <- nrow(x) * sum(num) |
34 | ||
35 |
## Proportion |
|
36 | 2x |
zeros / total |
37 |
} |
|
38 |
) |
1 |
# DATA SUMMARY: DESCRIBE |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
#' @export |
|
6 |
#' @rdname describe |
|
7 |
#' @aliases describe,ANY-method |
|
8 |
setMethod( |
|
9 |
f = "describe", |
|
10 |
signature = c(x = "ANY"), |
|
11 |
definition = function(x) { |
|
12 |
## Dimensions |
|
13 | 1x |
m <- nrow(x) |
14 | 1x |
p <- ncol(x) |
15 | ||
16 | 1x |
msg_rows <- sprintf(ngettext(m, "%d observation", "%d observations"), m) |
17 | 1x |
msg_cols <- sprintf(ngettext(p, "%d variable", "%d variables"), p) |
18 | 1x |
msg_tbl <- sprintf("%s, %s:", msg_rows, msg_cols) |
19 | ||
20 |
## Missing values |
|
21 | 1x |
n_NA <- sum(count(x, f = is.na)) |
22 | 1x |
m_NA <- sum(detect(x, f = is.na, margin = 1)) |
23 | 1x |
p_NA <- sum(detect(x, f = is.na, margin = 2)) |
24 | 1x |
pc <- label_percent(c(m_NA / m, p_NA / p), digits = 1, trim = TRUE) |
25 | ||
26 | 1x |
msg_NA <- sprintf(ngettext(n_NA, "\n%d missing value:", "\n%d missing values:"), n_NA) |
27 | ||
28 | 1x |
rows_NA <- ngettext(m_NA, "%d observation (%s) contains missing values.", |
29 | 1x |
"%d observations (%s) contain missing values.") |
30 | 1x |
msg_row_NA <- sprintf(rows_NA, m_NA, pc[[1]]) |
31 | ||
32 | 1x |
cols_NA <- ngettext(p_NA, "%d variable (%s) contains missing values.", |
33 | 1x |
"%d variables (%s) contain missing values.") |
34 | 1x |
msg_col_NA <- sprintf(cols_NA, p_NA, pc[[2]]) |
35 | ||
36 |
## Constant columns |
|
37 | 1x |
p_var <- sum(detect(x, f = function(x) is_unique(x), margin = 2)) |
38 | 1x |
cols_var <- ngettext(p_var, "%d variable with no variance.", |
39 | 1x |
"%d variables with no variance.") |
40 | 1x |
msg_col_var <- sprintf(cols_var, p_var) |
41 | ||
42 |
## Sparsity |
|
43 | 1x |
spa <- sparsity(x, count = FALSE) |
44 | 1x |
msg_spa <- sprintf(tr_("%s of numeric values are zero."), label_percent(spa, digits = 1)) |
45 | ||
46 |
## Variable types |
|
47 | 1x |
num <- detect(x, f = is.numeric, margin = 2) |
48 | 1x |
bin <- detect(x, f = is.logical, margin = 2) |
49 | 1x |
n_num <- sum(num) |
50 | 1x |
n_bin <- sum(bin) |
51 | 1x |
n_cha <- sum(!num & !bin) |
52 | ||
53 | 1x |
msg_num <- sprintf(ngettext(n_num, "%d numeric variable.", "%d numeric variables."), n_num) |
54 | 1x |
msg_bin <- sprintf(ngettext(n_bin, "%d binary variable.", "%d binary variables."), n_bin) |
55 | 1x |
msg_cha <- sprintf(ngettext(n_cha, "%d categorial variable.", "%d categorial variables."), n_cha) |
56 | ||
57 | 1x |
cat(msg_tbl, msg_num, msg_cha, msg_bin, sep = "\n* ") |
58 | 1x |
cat(msg_NA, msg_row_NA, msg_col_NA, sep = "\n* ") |
59 | 1x |
cat(tr_("\nData checking:"), msg_spa, msg_col_var, sep = "\n* ") |
60 | ||
61 |
# tot <- list( |
|
62 |
# m = m, p = p, |
|
63 |
# n_numeric = n_num, n_categorial = n_cha, n_binary = n_bin, |
|
64 |
# row_missing = m_NA, col_missing = p_NA, |
|
65 |
# zero_values = spa, zero_variance = p_var |
|
66 |
# ) |
|
67 | 1x |
invisible(x) |
68 |
} |
|
69 |
) |
|
70 | ||
71 |
#' Label Percentages |
|
72 |
#' |
|
73 |
#' @param x A [`numeric`] vector. |
|
74 |
#' @param digits An [`integer`] indicating the number of decimal places. |
|
75 |
#' If `NULL` (the default), breaks will have the minimum number of digits |
|
76 |
#' needed to show the difference between adjacent values. |
|
77 |
#' @param trim A [`logical`] scalar. If `FALSE` (the default), values are |
|
78 |
#' right-justified to a common width (see [base::format()]). |
|
79 |
#' @return A [`character`] vector. |
|
80 |
#' @keywords internal |
|
81 |
#' @export |
|
82 |
label_percent <- function(x, digits = NULL, trim = FALSE) { |
|
83 | 4x |
i <- !is.na(x) |
84 | 4x |
y <- x[i] |
85 | 4x |
y <- abs(y) * 100 |
86 | 4x |
y <- format(y, trim = trim, digits = digits) |
87 | 4x |
y <- paste0(y, "%") |
88 | 4x |
x[i] <- y |
89 | 4x |
x |
90 |
} |
1 |
# CONDITIONS |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
#' Conditions |
|
6 |
#' |
|
7 |
#' * `throw_error()` stops execution of the current expression and executes an |
|
8 |
#' error action. |
|
9 |
#' * `throw_warning()` generates a warning message. |
|
10 |
#' * `catch_conditions()` and `catch_message()` handles unusual conditions. |
|
11 |
#' @param expr An expression to be evaluated. |
|
12 |
#' @param .subclass A [`character`] string specifying the class of |
|
13 |
#' the message to be returned. |
|
14 |
#' @param message A [`character`] string specifying the message to be |
|
15 |
#' returned. |
|
16 |
#' @param call The call. |
|
17 |
#' @param ... Extra arguments. |
|
18 |
#' @author N. Frerebeau |
|
19 |
#' @name conditions |
|
20 |
#' @rdname conditions |
|
21 |
#' @family condition |
|
22 |
#' @keywords internal error |
|
23 |
NULL |
|
24 | ||
25 |
#' @rdname conditions |
|
26 |
throw_error <- function(.subclass, message, call = NULL, ...) { |
|
27 | 52x |
err <- structure( |
28 | 52x |
list( |
29 | 52x |
message = message, |
30 | 52x |
call = call, |
31 |
... |
|
32 |
), |
|
33 | 52x |
class = c(.subclass, "error", "condition") |
34 |
) |
|
35 | 52x |
stop(err) |
36 |
} |
|
37 | ||
38 |
#' @rdname conditions |
|
39 |
throw_warning <- function(.subclass, message, call = NULL, ...) { |
|
40 | ! |
wrn <- structure( |
41 | ! |
list( |
42 | ! |
message = message, |
43 | ! |
call = call, |
44 |
... |
|
45 |
), |
|
46 | ! |
class = c(.subclass, "warning", "condition") |
47 |
) |
|
48 | ! |
warning(wrn) |
49 |
} |
|
50 | ||
51 |
#' @rdname conditions |
|
52 |
catch_message <- function(expr) { |
|
53 | 6x |
cnd <- vector(mode = "character") |
54 | 6x |
add_msg <- function(x) { |
55 | 1x |
cnd <<- append(cnd, x$message) |
56 | 1x |
invokeRestart("muffleMessage") |
57 |
} |
|
58 | 6x |
add_wrn <- function(x) { |
59 | 3x |
cnd <<- append(cnd, x$message) |
60 | 3x |
invokeRestart("muffleWarning") |
61 |
} |
|
62 | 6x |
add_err <- function(x) { |
63 | 1x |
cnd <<- append(cnd, x$message) |
64 |
} |
|
65 | ||
66 | 6x |
tryCatch( |
67 | 6x |
error = add_err, |
68 | 6x |
withCallingHandlers( |
69 | 6x |
message = add_msg, |
70 | 6x |
warning = add_wrn, |
71 | 6x |
expr |
72 |
) |
|
73 |
) |
|
74 | 6x |
return(cnd) |
75 |
} |
|
76 | ||
77 |
#' @rdname conditions |
|
78 |
catch_conditions <- function(expr) { |
|
79 | 46x |
cnd <- vector(mode = "list") |
80 | 46x |
add_msg <- function(x) { |
81 | 2x |
cnd <<- append(cnd, list(x)) |
82 | 2x |
invokeRestart("muffleMessage") |
83 |
} |
|
84 | 46x |
add_wrn <- function(x) { |
85 | 1x |
cnd <<- append(cnd, list(x)) |
86 | 1x |
invokeRestart("muffleWarning") |
87 |
} |
|
88 | 46x |
add_err <- function(x) { |
89 | 43x |
cnd <<- append(cnd, list(x)) |
90 |
} |
|
91 | ||
92 | 46x |
tryCatch( |
93 | 46x |
error = add_err, |
94 | 46x |
withCallingHandlers( |
95 | 46x |
message = add_msg, |
96 | 46x |
warning = add_wrn, |
97 | 46x |
expr |
98 |
) |
|
99 |
) |
|
100 | 46x |
return(cnd) |
101 |
} |
|
102 | ||
103 |
# Diagnostic =================================================================== |
|
104 |
#' Class Diagnostic |
|
105 |
#' |
|
106 |
#' @param object An object to which error messages are related. |
|
107 |
#' @param conditions A [`list`] of condition messages. |
|
108 |
#' @return |
|
109 |
#' Throw an error if `conditions` is of non-zero length, invisibly returns |
|
110 |
#' `TRUE` if not. |
|
111 |
#' @author N. Frerebeau |
|
112 |
#' @keywords internal |
|
113 |
#' @export |
|
114 |
check_class <- function(object, conditions) { |
|
115 | ! |
cnd <- Filter(Negate(is_empty), conditions) |
116 | ! |
if (has_length(cnd)) { |
117 | ! |
li <- paste0("* ", cnd, collapse = "\n") |
118 | ! |
err <- sprintf(tr_("<%s> instance initialization:\n%s"), class(object), li) |
119 | ! |
throw_error("arkhe_error_class", err, call = NULL) |
120 |
} |
|
121 | ||
122 | ! |
invisible(TRUE) |
123 |
} |
1 |
# HELPERS |
|
2 | ||
3 |
## https://michaelchirico.github.io/potools/articles/developers.html |
|
4 |
tr_ <- function(...) { |
|
5 | 282x |
enc2utf8(gettext(paste0(...), domain = "R-arkhe")) |
6 |
} |
|
7 | ||
8 |
## https://stackoverflow.com/questions/56191862/where-do-i-specify-random-seed-for-tests-in-r-package |
|
9 |
#' Evaluate an Expression with a Temporarily Seed |
|
10 |
#' |
|
11 |
#' @param expr An [`expression`] to be evaluated. |
|
12 |
#' @param seed A single value to be passed to [set.seed()]. |
|
13 |
#' @param envir The [environment][environment()] in which `expr` should be |
|
14 |
#' evaluated. |
|
15 |
#' @param rounding A [`logical`] scalar: should the default discrete uniform |
|
16 |
#' generation method in \R versions prior to 3.6.0 be used? Usefull for unit |
|
17 |
#' testing. |
|
18 |
#' @param ... Further arguments to be passed to [set.seed()]. |
|
19 |
#' @return |
|
20 |
#' The results of `expr` evaluated. |
|
21 |
#' @seealso [set.seed()] |
|
22 |
#' @keywords internal |
|
23 |
with_seed <- function(expr, seed, ..., envir = parent.frame(), rounding = TRUE) { |
|
24 | 3x |
expr <- substitute(expr) |
25 |
## Save and restore the random number generator (RNG) state |
|
26 | 3x |
env <- globalenv() |
27 | 3x |
old_seed <- env$.Random.seed |
28 | 3x |
on.exit({ |
29 | 3x |
if (is.null(old_seed)) { |
30 | ! |
rm(list = ".Random.seed", envir = env, inherits = FALSE) |
31 |
} else { |
|
32 | 3x |
assign(".Random.seed", value = old_seed, envir = env, inherits = FALSE) |
33 |
} |
|
34 |
}) |
|
35 |
## Keep the results the same for R versions prior to 3.6 |
|
36 | 3x |
if (isTRUE(rounding) && getRversion() >= "3.6") { |
37 |
## Set sample.kind = "Rounding" to reproduce the old sampling |
|
38 |
## Suppress warning "non-uniform 'Rounding' sampler used" |
|
39 | 3x |
suppressWarnings(set.seed(seed, sample.kind = "Rounding")) |
40 |
} else { |
|
41 | ! |
set.seed(seed) |
42 |
} |
|
43 | 3x |
eval(expr, envir = envir) |
44 |
} |
1 |
# PREDICATES |
|
2 | ||
3 |
# Not exported ================================================================= |
|
4 |
is_zero_numeric <- function(x, tolerance = sqrt(.Machine$double.eps)) { |
|
5 | 35x |
if (is.numeric(x)) return(abs(x) <= tolerance) |
6 | 14x |
rep(FALSE, length(x)) |
7 |
} |
|
8 | ||
9 |
# Attributes =================================================================== |
|
10 |
#' Attributes Predicates |
|
11 |
#' |
|
12 |
#' * `has_length()` checks how long is an object. |
|
13 |
#' * `is_empty()` checks is an object is empty (any zero-length dimensions). |
|
14 |
#' @param x A [`vector`] to be tested. |
|
15 |
#' @param n A length-one [`numeric`] vector specifying the length to test `x` |
|
16 |
#' with. If `NULL`, returns `TRUE` if `x` has length greater than zero, and |
|
17 |
#' `FALSE` otherwise. |
|
18 |
#' @return A [`logical`] scalar. |
|
19 |
#' @family predicates |
|
20 |
#' @name predicate-attributes |
|
21 |
#' @rdname predicate-attributes |
|
22 |
NULL |
|
23 | ||
24 |
#' @export |
|
25 |
#' @rdname predicate-attributes |
|
26 |
has_length <- function(x, n = NULL) { |
|
27 | 16x |
if (is.null(n)) length(x) > 0 else length(x) == n |
28 |
} |
|
29 | ||
30 |
#' @export |
|
31 |
#' @rdname predicate-attributes |
|
32 |
is_empty <- function(x) { |
|
33 | 17x |
if (!is.null(dim(x))) nrow(x) == 0 || ncol(x) == 0 |
34 | 8x |
else length(x) == 0 |
35 |
} |
|
36 | ||
37 |
# Names ======================================================================== |
|
38 |
#' Names Predicates |
|
39 |
#' |
|
40 |
#' Checks if an object is named. |
|
41 |
#' @param x A [`vector`] to be tested. |
|
42 |
#' @param names A [`character`] vector specifying the names to test `x` |
|
43 |
#' with. If `NULL`, returns `TRUE` if `x` has names, and `FALSE` otherwise. |
|
44 |
#' @return A [`logical`] scalar. |
|
45 |
#' @family predicates |
|
46 |
#' @name predicate-names |
|
47 |
#' @rdname predicate-names |
|
48 |
NULL |
|
49 | ||
50 |
#' @export |
|
51 |
#' @rdname predicate-names |
|
52 |
has_names <- function(x, names = NULL) { |
|
53 | 9x |
if (is.null(names)) { |
54 | 6x |
has_length(names(x)) |
55 |
} else { |
|
56 | 3x |
identical(names(x), names) |
57 |
} |
|
58 |
} |
|
59 | ||
60 |
#' @export |
|
61 |
#' @rdname predicate-names |
|
62 |
has_rownames <- function(x, names = NULL) { |
|
63 | 6x |
if (is.null(names)) { |
64 | 4x |
has_length(rownames(x)) |
65 |
} else { |
|
66 | 2x |
identical(rownames(x), names) |
67 |
} |
|
68 |
} |
|
69 | ||
70 |
#' @export |
|
71 |
#' @rdname predicate-names |
|
72 |
has_colnames <- function(x, names = NULL) { |
|
73 | 3x |
if (is.null(names)) { |
74 | 1x |
has_length(colnames(x)) |
75 |
} else { |
|
76 | 2x |
identical(colnames(x), names) |
77 |
} |
|
78 |
} |
|
79 | ||
80 |
# NA/NaN/Inf/duplicates ======================================================== |
|
81 |
#' Utility Predicates |
|
82 |
#' |
|
83 |
#' * `has_missing()` and `has_infinite()` check if an object contains missing |
|
84 |
#' or infinite values. |
|
85 |
#' * `has_duplicates()` checks if an object has duplicated elements. |
|
86 |
#' @param x A [`vector`] to be tested. |
|
87 |
#' @param tolerance A [`numeric`] scalar giving the tolerance to check within |
|
88 |
#' (for `numeric` vector). |
|
89 |
#' @param na.rm A [`logical`] scalar: should missing values (including `NaN`) |
|
90 |
#' be omitted? |
|
91 |
#' @return A [`logical`] scalar. |
|
92 |
#' @family predicates |
|
93 |
#' @name predicate-data |
|
94 |
#' @rdname predicate-data |
|
95 |
NULL |
|
96 | ||
97 |
#' @export |
|
98 |
#' @rdname predicate-data |
|
99 |
has_missing <- function(x) { |
|
100 | 3x |
any(is.na(x)) |
101 |
} |
|
102 | ||
103 |
#' @export |
|
104 |
#' @rdname predicate-data |
|
105 |
has_infinite <- function(x) { |
|
106 | 3x |
any(is.infinite(x)) |
107 |
} |
|
108 | ||
109 |
#' @export |
|
110 |
#' @rdname predicate-data |
|
111 |
has_duplicates <- function(x) { |
|
112 | 4x |
any(duplicated(x)) |
113 |
} |
|
114 | ||
115 |
is_duplicated <- function(x) { |
|
116 | ! |
duplicated(x, fromLast = FALSE) | duplicated(x, fromLast = TRUE) |
117 |
} |
|
118 | ||
119 |
#' @export |
|
120 |
#' @rdname predicate-data |
|
121 |
is_unique <- function(x, tolerance = sqrt(.Machine$double.eps), na.rm = FALSE) { |
|
122 | 2x |
if (na.rm) x <- stats::na.omit(x) |
123 | 13x |
if (is.numeric(x)) { |
124 | 11x |
cte <- is_constant(x, tolerance = tolerance) |
125 | 3x |
if (is.na(cte)) cte <- FALSE |
126 |
} else { |
|
127 | 2x |
cte <- length(unique(x)) == 1 |
128 |
} |
|
129 | 13x |
cte |
130 |
} |
|
131 | ||
132 |
# Type ========================================================================= |
|
133 |
#' Type Predicates |
|
134 |
#' |
|
135 |
#' @param x An object to be tested. |
|
136 |
#' @return A [`logical`] scalar. |
|
137 |
#' @family predicates |
|
138 |
#' @name predicate-type |
|
139 |
#' @rdname predicate-type |
|
140 |
NULL |
|
141 | ||
142 |
#' @export |
|
143 |
#' @rdname predicate-type |
|
144 |
is_list <- function(x) { |
|
145 | 7x |
typeof(x) == "list" |
146 |
} |
|
147 |
#' @export |
|
148 |
#' @rdname predicate-type |
|
149 |
is_atomic <- function(x) { |
|
150 | 14x |
typeof(x) %in% c("logical", "integer", "double", |
151 | 14x |
"complex", "character", "raw") |
152 |
} |
|
153 |
#' @export |
|
154 |
#' @rdname predicate-type |
|
155 |
is_vector <- function(x) { |
|
156 | 6x |
is_atomic(x) || is_list(x) |
157 |
} |
|
158 |
#' @export |
|
159 |
#' @rdname predicate-type |
|
160 |
is_numeric <- function(x) { |
|
161 | 219x |
typeof(x) %in% c("integer", "double") |
162 |
} |
|
163 |
#' @export |
|
164 |
#' @rdname predicate-type |
|
165 |
is_integer <- function(x) { |
|
166 | 13x |
typeof(x) == "integer" |
167 |
} |
|
168 |
#' @export |
|
169 |
#' @rdname predicate-type |
|
170 |
is_double <- function(x) { |
|
171 | 5x |
typeof(x) == "double" |
172 |
} |
|
173 |
#' @export |
|
174 |
#' @rdname predicate-type |
|
175 |
is_character <- function(x) { |
|
176 | 31x |
typeof(x) == "character" |
177 |
} |
|
178 |
#' @export |
|
179 |
#' @rdname predicate-type |
|
180 |
is_logical <- function(x) { |
|
181 | 43x |
typeof(x) == "logical" |
182 |
} |
|
183 |
#' @export |
|
184 |
#' @rdname predicate-type |
|
185 |
is_error <- function(x) { |
|
186 | 2x |
inherits(x, "try-error") || inherits(x, "simpleError") || inherits(x, "error") |
187 |
} |
|
188 |
#' @export |
|
189 |
#' @rdname predicate-type |
|
190 |
is_warning <- function(x) { |
|
191 | 1x |
inherits(x, "simpleWarning") || inherits(x, "warning") |
192 |
} |
|
193 |
#' @export |
|
194 |
#' @rdname predicate-type |
|
195 |
is_message <- function(x) { |
|
196 | 1x |
inherits(x, "simpleMessage") || inherits(x, "message") |
197 |
} |
|
198 | ||
199 |
# Scalar ======================================================================= |
|
200 |
#' Scalar Type Predicates |
|
201 |
#' |
|
202 |
#' @param x An object to be tested. |
|
203 |
#' @return A [`logical`] scalar. |
|
204 |
#' @family predicates |
|
205 |
#' @name is_scalar |
|
206 |
#' @rdname is_scalar |
|
207 |
NULL |
|
208 | ||
209 |
#' @export |
|
210 |
#' @rdname is_scalar |
|
211 |
is_scalar_list <- function(x) { |
|
212 | 3x |
is_list(x) && length(x) == 1 |
213 |
} |
|
214 |
#' @export |
|
215 |
#' @rdname is_scalar |
|
216 |
is_scalar_atomic <- function(x) { |
|
217 | 3x |
is_atomic(x) && length(x) == 1 |
218 |
} |
|
219 |
#' @export |
|
220 |
#' @rdname is_scalar |
|
221 |
is_scalar_vector <- function(x) { |
|
222 | 3x |
is_vector(x) && length(x) == 1 |
223 |
} |
|
224 |
#' @export |
|
225 |
#' @rdname is_scalar |
|
226 |
is_scalar_numeric <- function(x) { |
|
227 | 8x |
is_numeric(x) && length(x) == 1 |
228 |
} |
|
229 |
#' @export |
|
230 |
#' @rdname is_scalar |
|
231 |
is_scalar_integer <- function(x) { |
|
232 | 3x |
is_integer(x) && length(x) == 1 |
233 |
} |
|
234 |
#' @export |
|
235 |
#' @rdname is_scalar |
|
236 |
is_scalar_double <- function(x) { |
|
237 | 3x |
is_double(x) && length(x) == 1 |
238 |
} |
|
239 |
#' @export |
|
240 |
#' @rdname is_scalar |
|
241 |
is_scalar_character <- function(x) { |
|
242 | 9x |
is_character(x) && length(x) == 1 |
243 |
} |
|
244 |
#' @export |
|
245 |
#' @rdname is_scalar |
|
246 |
is_scalar_logical <- function(x) { |
|
247 | 4x |
is_logical(x) && length(x) == 1 |
248 |
} |
|
249 | ||
250 |
# Numeric ====================================================================== |
|
251 |
#' Numeric Predicates |
|
252 |
#' |
|
253 |
#' Check numeric objects: |
|
254 |
#' * `is_zero()` checks if an object contains only zeros. |
|
255 |
#' * `is_odd()` and `is_even()` check if a number is odd or even, respectively. |
|
256 |
#' * `is_positive()` and `is_negative` check if an object contains only |
|
257 |
#' (strictly) positive or negative numbers. |
|
258 |
#' * `is_whole()` checks if an object only contains whole numbers. |
|
259 |
#' @param x A [`numeric`] object to be tested. |
|
260 |
#' @param tolerance A [`numeric`] scalar giving the tolerance to check within. |
|
261 |
#' @param strict A [`logical`] scalar: should strict inequality be used? |
|
262 |
#' @param ... Currently not used. |
|
263 |
#' @return A [`logical`] vector. |
|
264 |
#' @family predicates |
|
265 |
#' @name predicate-numeric |
|
266 |
#' @rdname predicate-numeric |
|
267 |
NULL |
|
268 | ||
269 |
#' @export |
|
270 |
#' @rdname predicate-numeric |
|
271 |
is_zero <- function(x, tolerance = sqrt(.Machine$double.eps), ...) { |
|
272 | 77x |
assert_type(x, "numeric") |
273 | 77x |
abs(x) <= tolerance |
274 |
} |
|
275 |
#' @export |
|
276 |
#' @rdname predicate-numeric |
|
277 |
is_odd <- function(x, ...) { # impair |
|
278 | 3x |
assert_type(x, "numeric") |
279 | 3x |
as.logical(x %% 2) |
280 |
} |
|
281 |
#' @export |
|
282 |
#' @rdname predicate-numeric |
|
283 |
is_even <- function(x, ...) { # pair |
|
284 | 2x |
assert_type(x, "numeric") |
285 | 2x |
!as.logical(x %% 2) |
286 |
} |
|
287 |
#' @export |
|
288 |
#' @rdname predicate-numeric |
|
289 |
is_positive <- function(x, strict = FALSE, ...) { |
|
290 | 7x |
assert_type(x, "numeric") |
291 | 2x |
if (strict) x > 0 else x >= 0 |
292 |
} |
|
293 |
#' @export |
|
294 |
#' @rdname predicate-numeric |
|
295 |
is_negative <- function(x, strict = FALSE, ...) { |
|
296 | 4x |
assert_type(x, "numeric") |
297 | 1x |
if (strict) x < 0 else x <= 0 |
298 |
} |
|
299 |
#' @export |
|
300 |
#' @rdname predicate-numeric |
|
301 |
is_whole <- function(x, tolerance = sqrt(.Machine$double.eps), ...) { |
|
302 | 9x |
assert_type(x, "numeric") |
303 | 8x |
abs(x - round(x, digits = 0)) <= tolerance |
304 |
} |
|
305 | ||
306 |
#' Numeric Trend Predicates |
|
307 |
#' |
|
308 |
#' Check numeric objects: |
|
309 |
#' * `is_constant()` checks for equality among all elements of a vector. |
|
310 |
#' * `is_increasing()` and `is_decreasing()` check if a sequence of numbers |
|
311 |
#' is monotonically increasing or decreasing, respectively. |
|
312 |
#' @param x,y A [`numeric`] object to be tested. |
|
313 |
#' @param tolerance A [`numeric`] scalar giving the tolerance to check within. |
|
314 |
#' @param strict A [`logical`] scalar: should strict inequality be used? |
|
315 |
#' @param na.rm A [`logical`] scalar: should missing values (including `NaN`) |
|
316 |
#' be omitted? |
|
317 |
#' @return A [`logical`] scalar. |
|
318 |
#' @family predicates |
|
319 |
#' @name predicate-trend |
|
320 |
#' @rdname predicate-trend |
|
321 |
NULL |
|
322 | ||
323 |
#' @export |
|
324 |
#' @rdname predicate-trend |
|
325 |
is_constant <- function(x, tolerance = sqrt(.Machine$double.eps), na.rm = FALSE) { |
|
326 | 18x |
assert_type(x, "numeric") |
327 | 17x |
abs(max(x, na.rm = na.rm) - min(x, na.rm = na.rm)) <= tolerance |
328 |
} |
|
329 |
#' @export |
|
330 |
#' @rdname predicate-trend |
|
331 |
is_increasing <- function(x, na.rm = FALSE) { |
|
332 | 8x |
assert_type(x, "numeric") |
333 | 1x |
if (na.rm) x <- stats::na.omit(x) |
334 | 7x |
all(x == cummax(x)) |
335 |
} |
|
336 |
#' @export |
|
337 |
#' @rdname predicate-trend |
|
338 |
is_decreasing <- function(x, na.rm = FALSE) { |
|
339 | 7x |
assert_type(x, "numeric") |
340 | 1x |
if (na.rm) x <- stats::na.omit(x) |
341 | 6x |
all(x == cummin(x)) |
342 |
} |
|
343 |
#' @export |
|
344 |
#' @rdname predicate-trend |
|
345 |
is_greater <- function(x, y, strict = FALSE, na.rm = FALSE) { |
|
346 | 4x |
assert_type(x, "numeric") |
347 | 4x |
assert_type(y, "numeric") |
348 | 4x |
z <- if (strict) x > y else x >= y |
349 | 4x |
all(z, na.rm = na.rm) |
350 |
} |
|
351 |
#' @export |
|
352 |
#' @rdname predicate-trend |
|
353 |
is_lower <- function(x, y, strict = FALSE, na.rm = FALSE) { |
|
354 | 7x |
assert_type(x, "numeric") |
355 | 6x |
assert_type(y, "numeric") |
356 | 5x |
z <- if (strict) x < y else x <= y |
357 | 5x |
all(z, na.rm = na.rm) |
358 |
} |
|
359 | ||
360 |
# Matrix ======================================================================= |
|
361 |
#' Matrix Predicates |
|
362 |
#' |
|
363 |
#' * `is_square()` checks if a matrix is square. |
|
364 |
#' * `is_symmetric()` checks if a matrix is symmetric. |
|
365 |
#' @param x A [`matrix`] to be tested. |
|
366 |
#' @return A [`logical`] scalar. |
|
367 |
#' @family predicates |
|
368 |
#' @name predicate-matrix |
|
369 |
#' @rdname predicate-matrix |
|
370 |
NULL |
|
371 | ||
372 |
#' @export |
|
373 |
#' @rdname predicate-matrix |
|
374 |
is_square <- function(x) { |
|
375 | 1x |
if (is.matrix(x)) nrow(x) == ncol(x) else FALSE |
376 |
} |
|
377 |
#' @export |
|
378 |
#' @rdname predicate-matrix |
|
379 |
is_symmetric <- function(x) { |
|
380 | 1x |
if (is.matrix(x)) identical(x, t(x)) else FALSE |
381 |
} |
|
382 | ||
383 |
# Graph ======================================================================== |
|
384 |
# Graph Predicates |
|
385 |
# |
|
386 |
# `is_dag()` checks if a graph has a topological ordering (i.e. is a directed |
|
387 |
# acyclic graph) using Kahn's algorithm. |
|
388 |
# @param x An adjacency [`matrix`] to be tested. |
|
389 |
# @return A [`logical`] scalar. |
|
390 |
# @references |
|
391 |
# Kahn, A. B. (1962). Topological sorting of large networks. *Communications |
|
392 |
# of the ACM*, 5(11), p. 558-562. \doi{10.1145/368996.369025}. |
|
393 |
# @family predicates |
|
394 |
# @keywords internal |
|
395 |
# @export |
|
396 |
# is_dag <- function(x) { |
|
397 |
# # Get edges |
|
398 |
# G <- matrix2edges(x) |
|
399 |
# # Find nodes which have no incoming edges |
|
400 |
# S <- which(colSums(x) == 0) |
|
401 |
# # List that will contain the sorted elements |
|
402 |
# L <- list() |
|
403 |
# |
|
404 |
# if (length(S) == 0) |
|
405 |
# return(FALSE) |
|
406 |
# |
|
407 |
# k <- 1L |
|
408 |
# while (k == 1 || length(S) != 0) { |
|
409 |
# # Remove a node n from S and add n to tail of L |
|
410 |
# n <- S[[1]] |
|
411 |
# S <- S[-1] |
|
412 |
# L <- append(L, n) |
|
413 |
# # For each node m with an edge e from n to m |
|
414 |
# e <- which(G[, 1] == n) |
|
415 |
# m <- G[e, 2] |
|
416 |
# # Do remove edge e from the graph |
|
417 |
# G <- G[-e, , drop = FALSE] |
|
418 |
# # If m has no other incoming edges then insert m into S |
|
419 |
# if (nrow(G) != 0) { |
|
420 |
# m <- m[!(m %in% G[, 2])] |
|
421 |
# if (length(m) != 0) |
|
422 |
# S <- append(S, m) |
|
423 |
# } |
|
424 |
# k <- k + 1 |
|
425 |
# } |
|
426 |
# return(nrow(G) == 0) |
|
427 |
# } |
|
428 | ||
429 |
# matrix2edges <- function(from) { |
|
430 |
# edges <- matrix(data = NA, nrow = 0, ncol = 2) |
|
431 |
# nodes <- seq_len(nrow(from)) |
|
432 |
# for (i in nodes) { |
|
433 |
# to <- which(from[i, ]) |
|
434 |
# if (length(to) != 0) { |
|
435 |
# e <- cbind(form = i, to = to) |
|
436 |
# edges <- rbind(edges, e) |
|
437 |
# } |
|
438 |
# } |
|
439 |
# |
|
440 |
# edges |
|
441 |
# } |
1 |
# DATA CLEANING: DISCARD |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
# discard ====================================================================== |
|
6 |
#' @export |
|
7 |
#' @rdname discard |
|
8 |
#' @aliases discard,ANY-method |
|
9 |
setMethod( |
|
10 |
f = "discard", |
|
11 |
signature = c(x = "ANY"), |
|
12 |
definition = function(x, f, margin = 1, negate = FALSE, all = FALSE, |
|
13 |
na.rm = FALSE, verbose = getOption("arkhe.verbose"), |
|
14 |
...) { |
|
15 | 39x |
i <- detect(x, f = f, margin = margin, negate = negate, all = all, |
16 | 39x |
na.rm = na.rm, ...) |
17 | 39x |
discard_message(x, keep = !i, margin = margin, verbose = verbose) |
18 | 19x |
if (any(margin == 1)) return(x[!i, , drop = FALSE]) |
19 | 20x |
if (any(margin == 2)) return(x[, !i, drop = FALSE]) |
20 | ! |
i |
21 |
} |
|
22 |
) |
|
23 | ||
24 |
#' @export |
|
25 |
#' @rdname discard |
|
26 |
#' @aliases discard_rows,ANY-method |
|
27 |
setMethod( |
|
28 |
f = "discard_rows", |
|
29 |
signature = c(x = "ANY"), |
|
30 |
definition = function(x, f, negate = FALSE, all = FALSE, na.rm = FALSE, |
|
31 |
verbose = getOption("arkhe.verbose"), ...) { |
|
32 | 4x |
discard(x, f, margin = 1, negate = negate, all = all, na.rm = na.rm, |
33 | 4x |
verbose = verbose, ...) |
34 |
} |
|
35 |
) |
|
36 | ||
37 |
#' @export |
|
38 |
#' @rdname discard |
|
39 |
#' @aliases discard_columns,ANY-method |
|
40 |
setMethod( |
|
41 |
f = "discard_columns", |
|
42 |
signature = c(x = "ANY"), |
|
43 |
definition = function(x, f, negate = FALSE, all = FALSE, na.rm = FALSE, |
|
44 |
verbose = getOption("arkhe.verbose"), ...) { |
|
45 | 4x |
discard(x, f, margin = 2, negate = negate, all = all, na.rm = na.rm, |
46 | 4x |
verbose = verbose, ...) |
47 |
} |
|
48 |
) |
|
49 | ||
50 |
#' Diagnostic Message |
|
51 |
#' |
|
52 |
#' Generates a diagnostic message describing columns or rows that are being |
|
53 |
#' removed. |
|
54 |
#' @param x A [`matrix`] or a [`data.frame`]. |
|
55 |
#' @param margin A length-one [`numeric`] vector giving the subscripts which the |
|
56 |
#' function will be applied over (`1` indicates rows, `2` indicates columns). |
|
57 |
#' @param keep A [`logical`] vector of rows or columns to keep (`TRUE`) or |
|
58 |
#' remove (`FALSE`). |
|
59 |
#' @param verbose A [`logical`] scalar: should the message be generated? |
|
60 |
#' @keywords internal |
|
61 |
#' @noRd |
|
62 |
discard_message <- function(x, keep, margin, |
|
63 |
verbose = getOption("arkhe.verbose")) { |
|
64 | 49x |
drop <- sum(!keep, na.rm = TRUE) |
65 | 49x |
what <- ngettext(drop, "element", "elements") |
66 | 24x |
if (any(margin == 1)) what <- ngettext(drop, "row", "rows") |
67 | 25x |
if (any(margin == 2)) what <- ngettext(drop, "column", "columns") |
68 | ||
69 | 49x |
if (drop == 0) { |
70 | 21x |
msg <- tr_("Nothing to remove.") |
71 |
} else { |
|
72 | 28x |
pc <- sprintf("%0.3g%%", 100 * drop / length(keep)) |
73 | 28x |
if (margin == 2 && !is.null(colnames(x))) { |
74 | 6x |
pc <- paste0(colnames(x)[!keep], collapse = ", ") |
75 |
} |
|
76 | 28x |
msg <- tr_("Removing %g %s out of %g (%s).") |
77 | 28x |
msg <- sprintf(msg, drop, what, length(keep), pc) |
78 |
} |
|
79 | ||
80 | 8x |
if (verbose) message(msg) |
81 | 49x |
invisible(msg) |
82 |
} |
1 |
# DATA CLEANING: ASSIGN |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
#' @export |
|
6 |
#' @rdname assign |
|
7 |
#' @aliases assign_rownames,data.frame-method |
|
8 |
setMethod( |
|
9 |
f = "assign_rownames", |
|
10 |
signature = c(x = "data.frame"), |
|
11 |
definition = function(x, column, remove = TRUE) { |
|
12 |
## Validation |
|
13 | 1x |
assert_length(column, 1) |
14 | ! |
if ((column > ncol(x)) | (column < 1)) return(x) |
15 | ||
16 | 1x |
y <- x |
17 | 1x |
rownames(y) <- y[, column] |
18 | 1x |
if (remove) { |
19 | 1x |
y <- y[, -column, drop = FALSE] |
20 |
} |
|
21 | 1x |
y |
22 |
} |
|
23 |
) |
|
24 | ||
25 |
#' @export |
|
26 |
#' @rdname assign |
|
27 |
#' @aliases assign_colnames,data.frame-method |
|
28 |
setMethod( |
|
29 |
f = "assign_colnames", |
|
30 |
signature = c(x = "data.frame"), |
|
31 |
definition = function(x, row, remove = TRUE) { |
|
32 |
## Validation |
|
33 | 1x |
assert_length(row, 1) |
34 | ! |
if ((row > nrow(x)) | (row < 1)) return(x) |
35 | ||
36 | 1x |
y <- x |
37 | 1x |
colnames(y) <- y[row, ] |
38 | 1x |
if (remove) { |
39 | 1x |
y <- y[-row, , drop = FALSE] |
40 |
} |
|
41 | 1x |
y |
42 |
} |
|
43 |
) |
1 |
# DATA CLEANING: REPLACE |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
# Replace ====================================================================== |
|
6 |
## Missing values -------------------------------------------------------------- |
|
7 |
#' @export |
|
8 |
#' @rdname replace_NA |
|
9 |
#' @aliases replace_NA,matrix-method |
|
10 |
setMethod( |
|
11 |
f = "replace_NA", |
|
12 |
signature = c(x = "matrix"), |
|
13 |
definition = function(x, value = 0) { |
|
14 | 1x |
x[is.na(x)] <- value |
15 | 1x |
x |
16 |
} |
|
17 |
) |
|
18 | ||
19 |
#' @export |
|
20 |
#' @rdname replace_NA |
|
21 |
#' @aliases replace_NA,data.frame-method |
|
22 |
setMethod( |
|
23 |
f = "replace_NA", |
|
24 |
signature = c(x = "data.frame"), |
|
25 |
definition = function(x, value = 0) { |
|
26 | 1x |
x[] <- lapply( |
27 | 1x |
X = x, |
28 | 1x |
FUN = function(x, value) { |
29 | 3x |
x[is.na(x)] <- value |
30 | 3x |
x |
31 |
}, |
|
32 | 1x |
value = value |
33 |
) |
|
34 | 1x |
x |
35 |
} |
|
36 |
) |
|
37 | ||
38 |
## Infinite values ------------------------------------------------------------- |
|
39 |
#' @export |
|
40 |
#' @rdname replace_Inf |
|
41 |
#' @aliases replace_Inf,matrix-method |
|
42 |
setMethod( |
|
43 |
f = "replace_Inf", |
|
44 |
signature = c(x = "matrix"), |
|
45 |
definition = function(x, value = 0) { |
|
46 | 1x |
x[is.infinite(x)] <- value |
47 | 1x |
x |
48 |
} |
|
49 |
) |
|
50 | ||
51 |
#' @export |
|
52 |
#' @rdname replace_Inf |
|
53 |
#' @aliases replace_Inf,data.frame-method |
|
54 |
setMethod( |
|
55 |
f = "replace_Inf", |
|
56 |
signature = c(x = "data.frame"), |
|
57 |
definition = function(x, value = 0) { |
|
58 | 1x |
x[] <- lapply( |
59 | 1x |
X = x, |
60 | 1x |
FUN = function(x, value) { |
61 | 3x |
x[is.infinite(x)] <- value |
62 | 3x |
x |
63 |
}, |
|
64 | 1x |
value = value |
65 |
) |
|
66 | 1x |
x |
67 |
} |
|
68 |
) |
|
69 | ||
70 |
## Zeros ----------------------------------------------------------------------- |
|
71 |
#' @export |
|
72 |
#' @rdname replace_zero |
|
73 |
#' @aliases replace_zero,matrix-method |
|
74 |
setMethod( |
|
75 |
f = "replace_zero", |
|
76 |
signature = c(x = "matrix"), |
|
77 |
definition = function(x, value) { |
|
78 | 1x |
x[is_zero(x)] <- value |
79 | 1x |
x |
80 |
} |
|
81 |
) |
|
82 | ||
83 |
#' @export |
|
84 |
#' @rdname replace_zero |
|
85 |
#' @aliases replace_zero,data.frame-method |
|
86 |
setMethod( |
|
87 |
f = "replace_zero", |
|
88 |
signature = c(x = "data.frame"), |
|
89 |
definition = function(x, value) { |
|
90 | 1x |
num <- vapply(X = x, FUN = is.numeric, FUN.VALUE = logical(1)) |
91 | 1x |
nozero <- lapply( |
92 | 1x |
X = x[, num, drop = FALSE], |
93 | 1x |
FUN = function(x, value) { |
94 | 2x |
x[is_zero(x)] <- value |
95 | 2x |
x |
96 |
}, |
|
97 | 1x |
value = value |
98 |
) |
|
99 | 1x |
x[, num] <- nozero |
100 | 1x |
x |
101 |
} |
|
102 |
) |
|
103 | ||
104 |
## Empty string ---------------------------------------------------------------- |
|
105 |
#' @export |
|
106 |
#' @rdname replace_empty |
|
107 |
#' @aliases replace_empty,matrix-method |
|
108 |
setMethod( |
|
109 |
f = "replace_empty", |
|
110 |
signature = c(x = "matrix"), |
|
111 |
definition = function(x, value) { |
|
112 | 1x |
x[!nzchar(x)] <- value |
113 | 1x |
x |
114 |
} |
|
115 |
) |
|
116 | ||
117 |
#' @export |
|
118 |
#' @rdname replace_empty |
|
119 |
#' @aliases replace_empty,data.frame-method |
|
120 |
setMethod( |
|
121 |
f = "replace_empty", |
|
122 |
signature = c(x = "data.frame"), |
|
123 |
definition = function(x, value) { |
|
124 | 1x |
char <- vapply(X = x, FUN = is.character, FUN.VALUE = logical(1)) |
125 | 1x |
noblank <- lapply( |
126 | 1x |
X = x[, char, drop = FALSE], |
127 | 1x |
FUN = function(x, value) { |
128 | 1x |
x[!nzchar(x)] <- value |
129 | 1x |
x |
130 |
}, |
|
131 | 1x |
value = value |
132 |
) |
|
133 | 1x |
x[, char] <- noblank |
134 | 1x |
x |
135 |
} |
|
136 |
) |
1 |
# DATA CLEANING: KEEP |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
# keep ========================================================================= |
|
6 |
#' @export |
|
7 |
#' @rdname keep |
|
8 |
#' @aliases keep,ANY-method |
|
9 |
setMethod( |
|
10 |
f = "keep", |
|
11 |
signature = c(x = "ANY"), |
|
12 |
definition = function(x, f, margin = 1, negate = FALSE, all = FALSE, |
|
13 |
na.rm = FALSE, verbose = getOption("arkhe.verbose"), |
|
14 |
...) { |
|
15 | 10x |
i <- detect(x, f = f, margin = margin, negate = negate, all = all, |
16 | 10x |
na.rm = na.rm, ...) |
17 | 10x |
discard_message(x, keep = i, margin = margin, verbose = verbose) |
18 | 5x |
if (any(margin == 1)) return(x[i, , drop = FALSE]) |
19 | 5x |
if (any(margin == 2)) return(x[, i, drop = FALSE]) |
20 | ! |
i |
21 |
} |
|
22 |
) |
|
23 | ||
24 |
#' @export |
|
25 |
#' @rdname keep |
|
26 |
#' @aliases keep_rows,ANY-method |
|
27 |
setMethod( |
|
28 |
f = "keep_rows", |
|
29 |
signature = c(x = "ANY"), |
|
30 |
definition = function(x, f, negate = FALSE, all = FALSE, na.rm = FALSE, |
|
31 |
verbose = getOption("arkhe.verbose"), ...) { |
|
32 | 5x |
keep(x, f, margin = 1, negate = negate, all = all, na.rm = na.rm, |
33 | 5x |
verbose = verbose, ...) |
34 |
} |
|
35 |
) |
|
36 | ||
37 |
#' @export |
|
38 |
#' @rdname keep |
|
39 |
#' @aliases keep_columns,ANY-method |
|
40 |
setMethod( |
|
41 |
f = "keep_columns", |
|
42 |
signature = c(x = "ANY"), |
|
43 |
definition = function(x, f, negate = FALSE, all = FALSE, na.rm = FALSE, |
|
44 |
verbose = getOption("arkhe.verbose"), ...) { |
|
45 | 5x |
keep(x, f, margin = 2, negate = negate, all = all, na.rm = na.rm, |
46 | 5x |
verbose = verbose, ...) |
47 |
} |
|
48 |
) |
1 |
# SEEK |
|
2 | ||
3 |
seek <- function(x, margin = 2, select = NULL, names = NULL, ...) { |
|
4 | 16x |
assert_filled(x) |
5 | 16x |
assert_length(margin, 1) |
6 | 16x |
assert_type(names, "character", allow_null = TRUE) |
7 | ||
8 | 14x |
dm <- dim(x)[[margin]] |
9 | 14x |
nm <- dimnames(x)[[margin]] |
10 | ! |
if (is.null(nm)) return(NULL) |
11 | ||
12 | 14x |
if (is.null(select)) { |
13 | 2x |
if (is.null(names)) return(NULL) |
14 | 4x |
select <- function(i) match(names, i) |
15 |
} |
|
16 | ||
17 | 12x |
assert_function(select) |
18 | 12x |
i <- select(nm, ...) |
19 | ||
20 | 8x |
if (is.logical(i)) i <- which(i) |
21 | 4x |
if (length(i) == 0 || all(is.na(i))) i <- NULL |
22 | 12x |
assert_type(i, "integer", allow_null = TRUE) |
23 | 12x |
i |
24 |
} |
|
25 | ||
26 |
#' @export |
|
27 |
#' @rdname seek |
|
28 |
#' @aliases seek_rows,data.frame-method |
|
29 |
setMethod( |
|
30 |
f = "seek_rows", |
|
31 |
signature = c(x = "data.frame"), |
|
32 |
definition = function(x, select = NULL, names = NULL, ...) { |
|
33 | 7x |
seek(x, margin = 1, select = select, names = names, ...) |
34 |
} |
|
35 |
) |
|
36 | ||
37 |
#' @export |
|
38 |
#' @rdname seek |
|
39 |
#' @aliases seek_rows,matrix-method |
|
40 |
setMethod( |
|
41 |
f = "seek_rows", |
|
42 |
signature = c(x = "matrix"), |
|
43 |
definition = function(x, select = NULL, names = NULL, ...) { |
|
44 | 1x |
seek(x, margin = 1, select = select, names = names, ...) |
45 |
} |
|
46 |
) |
|
47 | ||
48 |
#' @export |
|
49 |
#' @rdname seek |
|
50 |
#' @aliases seek_columns,data.frame-method |
|
51 |
setMethod( |
|
52 |
f = "seek_columns", |
|
53 |
signature = c(x = "data.frame"), |
|
54 |
definition = function(x, select = NULL, names = NULL, ...) { |
|
55 | 7x |
seek(x, margin = 2, select = select, names = names, ...) |
56 |
} |
|
57 |
) |
|
58 | ||
59 |
#' @export |
|
60 |
#' @rdname seek |
|
61 |
#' @aliases seek_columns,matrix-method |
|
62 |
setMethod( |
|
63 |
f = "seek_columns", |
|
64 |
signature = c(x = "matrix"), |
|
65 |
definition = function(x, select = NULL, names = NULL, ...) { |
|
66 | 1x |
seek(x, margin = 2, select = select, names = names, ...) |
67 |
} |
|
68 |
) |
1 |
# DATA CLEANING: COUNT |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
# Count ======================================================================== |
|
6 |
#' @export |
|
7 |
#' @rdname count |
|
8 |
#' @aliases count,data.frame-method |
|
9 |
setMethod( |
|
10 |
f = "count", |
|
11 |
signature = c(x = "data.frame"), |
|
12 |
definition = function(x, f, margin = 1, negate = FALSE, na.rm = FALSE, ...) { |
|
13 | 42x |
assert_function(f) |
14 | 6x |
if (negate) f <- Negate(f) |
15 | 42x |
x[] <- lapply(X = x, FUN = f, ...) |
16 | 16x |
if (any(margin == 1)) return(rowSums(x, na.rm = na.rm)) |
17 | 25x |
if (any(margin == 2)) return(colSums(x, na.rm = na.rm)) |
18 | 1x |
x |
19 |
} |
|
20 |
) |
|
21 | ||
22 |
#' @export |
|
23 |
#' @rdname count |
|
24 |
#' @aliases count,matrix-method |
|
25 |
setMethod( |
|
26 |
f = "count", |
|
27 |
signature = c(x = "matrix"), |
|
28 |
definition = function(x, f, margin = 1, negate = FALSE, na.rm = FALSE, ...) { |
|
29 | 36x |
assert_function(f) |
30 | 2x |
if (negate) f <- Negate(f) |
31 | 36x |
x <- apply(X = x, MARGIN = margin, FUN = f, ..., simplify = TRUE) |
32 |
## If simplify is TRUE: |
|
33 |
## apply() returns an array of dimension c(n, dim(X)[MARGIN]) if n > 1 |
|
34 |
## apply() returns a vector if n == 1 and MARGIN has length 1 |
|
35 | ! |
if (is.null(dim(x))) x <- matrix(x, nrow = 1) |
36 | 36x |
colSums(x, na.rm = na.rm) |
37 |
} |
|
38 |
) |
1 |
# GET |
|
2 | ||
3 |
#' @export |
|
4 |
#' @rdname get |
|
5 |
#' @aliases get_columns,ANY-method |
|
6 |
setMethod( |
|
7 |
f = "get_columns", |
|
8 |
signature = c(x = "ANY"), |
|
9 |
definition = function(x, select = NULL, names = NULL, ...) { |
|
10 | 1x |
i <- seek_columns(x, select = select, names = names, ...) |
11 | 1x |
x[, i, drop = FALSE] |
12 |
} |
|
13 |
) |
|
14 | ||
15 |
#' @export |
|
16 |
#' @rdname get |
|
17 |
#' @aliases get_rows,ANY-method |
|
18 |
setMethod( |
|
19 |
f = "get_rows", |
|
20 |
signature = c(x = "ANY"), |
|
21 |
definition = function(x, select = NULL, names = NULL, ...) { |
|
22 | 1x |
i <- seek_rows(x, select = select, names = names, ...) |
23 | 1x |
x[i, , drop = FALSE] |
24 |
} |
|
25 |
) |
1 |
# UTILITIES |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
#' Default value for NULL |
|
6 |
#' |
|
7 |
#' Replaces `NULL` with a default value. |
|
8 |
#' @param x,y An object. |
|
9 |
#' @return If `x` is `NULL`, returns `y`; otherwise returns `x`. |
|
10 |
#' @family utilities |
|
11 |
#' @keywords utilities |
|
12 |
#' @name null |
|
13 |
#' @rdname null |
|
14 |
#' @export |
|
15 |
`%||%` <- function(x, y) { |
|
16 |
if (is.null(x)) y else x |
|
17 |
} |
|
18 | ||
19 |
# Reexport from base on newer versions of R to avoid conflict messages |
|
20 |
if (exists("%||%", envir = baseenv())) { |
|
21 |
`%||%` <- get("%||%", envir = baseenv()) |
|
22 |
} |
|
23 | ||
24 |
#' Concatenate |
|
25 |
#' |
|
26 |
#' Concatenates character vectors. |
|
27 |
#' @param x,y A [`character`] vector. |
|
28 |
#' @return A [`character`] vector. |
|
29 |
#' @family utilities |
|
30 |
#' @keywords utilities |
|
31 |
#' @name concat |
|
32 |
#' @rdname concat |
|
33 |
#' @export |
|
34 |
`%+%` <- function (x, y) { |
|
35 | 4x |
stopifnot(is.character(x), is.character(y)) |
36 | 4x |
stopifnot(length(x) == length(y) || length(x) == 1 || length(y) == 1) |
37 | ||
38 | 1x |
if (length(x) == 0 && length(y) == 0) paste0(x, y) |
39 | 1x |
else if (length(x) == 0) x |
40 | 1x |
else if (length(y) == 0) y |
41 | 1x |
else paste0(x, y) |
42 |
} |
1 |
# DATA CLEANING: COMPACT |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
## compact rows/columns ======================================================== |
|
6 |
#' @export |
|
7 |
#' @rdname compact |
|
8 |
#' @aliases compact,ANY-method |
|
9 |
setMethod( |
|
10 |
f = "compact", |
|
11 |
signature = c(x = "ANY"), |
|
12 |
definition = function(x, margin = 1, na.rm = FALSE, |
|
13 |
verbose = getOption("arkhe.verbose")) { |
|
14 | 12x |
vide <- function(x) { |
15 | 13x |
if (is_numeric(x)) x == 0 |
16 | 24x |
else if (is_logical(x)) !x |
17 | 13x |
else if (is_character(x)) x == "" |
18 | ! |
else rep(FALSE, length(x)) |
19 |
} |
|
20 | 12x |
discard(x, f = vide, margin = margin, all = TRUE, |
21 | 12x |
na.rm = na.rm, verbose = verbose) |
22 |
} |
|
23 |
) |
|
24 | ||
25 |
#' @export |
|
26 |
#' @rdname compact |
|
27 |
#' @aliases compact_columns,ANY-method |
|
28 |
setMethod( |
|
29 |
f = "compact_columns", |
|
30 |
signature = c(x = "ANY"), |
|
31 |
definition = function(x, na.rm = FALSE, verbose = getOption("arkhe.verbose")) { |
|
32 | 5x |
compact(x, margin = 2, na.rm = na.rm, verbose = verbose) |
33 |
} |
|
34 |
) |
|
35 | ||
36 |
#' @export |
|
37 |
#' @rdname compact |
|
38 |
#' @aliases compact_rows,ANY-method |
|
39 |
setMethod( |
|
40 |
f = "compact_rows", |
|
41 |
signature = c(x = "ANY"), |
|
42 |
definition = function(x, na.rm = FALSE, verbose = getOption("arkhe.verbose")) { |
|
43 | 7x |
compact(x, margin = 1, na.rm = na.rm, verbose = verbose) |
44 |
} |
|
45 |
) |
1 |
# CLEAN |
|
2 | ||
3 |
# Whitespace =================================================================== |
|
4 |
#' @export |
|
5 |
#' @rdname clean_whitespace |
|
6 |
#' @aliases clean_whitespace,data.frame-method |
|
7 |
setMethod( |
|
8 |
f = "clean_whitespace", |
|
9 |
signature = c(x = "data.frame"), |
|
10 |
definition = function(x, which = c("both", "left", "right"), squish = TRUE) { |
|
11 | 4x |
x[] <- lapply( |
12 | 4x |
X = x, |
13 | 4x |
FUN = function(x, which, squish) { |
14 | 4x |
if (!is.character(x)) return(x) |
15 | 4x |
trim(x, which = which, squish = squish) |
16 |
}, |
|
17 | 4x |
which = which, |
18 | 4x |
squish = squish |
19 |
) |
|
20 | 4x |
x |
21 |
} |
|
22 |
) |
|
23 | ||
24 |
#' @export |
|
25 |
#' @rdname clean_whitespace |
|
26 |
#' @aliases clean_whitespace,matrix-method |
|
27 |
setMethod( |
|
28 |
f = "clean_whitespace", |
|
29 |
signature = c(x = "matrix"), |
|
30 |
definition = function(x, which = c("both", "left", "right"), squish = TRUE) { |
|
31 | 1x |
x[] <- trim(x, which = which, squish = squish) |
32 | 1x |
x |
33 |
} |
|
34 |
) |
|
35 | ||
36 |
trim <- function(x, which = c("both", "left", "right"), squish = TRUE) { |
|
37 |
## Squish |
|
38 | 2x |
if (squish) x <- gsub(pattern = "\\s+", replacement = " ", x = x) |
39 |
## Trim |
|
40 | 5x |
x <- trimws(x, which = which, whitespace = "[ \t\r\n]") |
41 | ||
42 | 5x |
x |
43 |
} |
1 |
# DATA CLEANING: DETECT |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
# Detect ======================================================================= |
|
6 |
#' @export |
|
7 |
#' @rdname detect |
|
8 |
#' @aliases detect,ANY-method |
|
9 |
setMethod( |
|
10 |
f = "detect", |
|
11 |
signature = c(x = "ANY"), |
|
12 |
definition = function(x, f, margin = 1, negate = FALSE, all = FALSE, |
|
13 |
na.rm = FALSE, ...) { |
|
14 | 59x |
total <- count(x, f, margin = margin, negate = negate, na.rm = na.rm, ...) |
15 | ||
16 | 59x |
miss <- rep(0, length(total)) |
17 | 10x |
if (na.rm) miss <- count(x, f = is.na, margin = margin) |
18 | ||
19 | 59x |
k <- 1 |
20 | 59x |
if (all) { |
21 | 15x |
if (any(margin == 1)) k <- ncol(x) - miss |
22 | 18x |
if (any(margin == 2)) k <- nrow(x) - miss |
23 |
} |
|
24 | 59x |
total >= k |
25 |
} |
|
26 |
) |
1 |
# DATA CLEANING: APPEND |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
#' @export |
|
6 |
#' @rdname append_rownames |
|
7 |
#' @aliases append_rownames,data.frame-method |
|
8 |
setMethod( |
|
9 |
f = "append_rownames", |
|
10 |
signature = c(x = "data.frame"), |
|
11 |
definition = function(x, after = 0, remove = TRUE, var = "rownames") { |
|
12 | 1x |
assert_scalar(after, "numeric") |
13 | 1x |
assert_scalar(remove, "logical") |
14 | 1x |
assert_scalar(var, "character") |
15 | ||
16 | 1x |
n <- ncol(x) |
17 | 1x |
if (after > n) after <- n |
18 | 1x |
i_before <- seq_len(after) |
19 | 1x |
i_after <- if (after < n) seq(from = after + 1, to = n, by = 1) else 0 |
20 | ||
21 | 1x |
z <- rownames(x) |
22 | 1x |
x <- cbind(x[, i_before, drop = FALSE], z, x[, i_after, drop = FALSE]) |
23 | ||
24 | 1x |
colnames(x)[after + 1] <- var |
25 | 1x |
rownames(x) <- if (remove) NULL else z |
26 | ||
27 | 1x |
x |
28 |
} |
|
29 |
) |
|
30 | ||
31 |
#' @export |
|
32 |
#' @rdname append_column |
|
33 |
#' @aliases append_column,data.frame-method |
|
34 |
setMethod( |
|
35 |
f = "append_column", |
|
36 |
signature = c(x = "data.frame"), |
|
37 |
definition = function(x, column, after = 0, var = ".col") { |
|
38 | 3x |
assert_scalar(after, "numeric") |
39 | 3x |
assert_scalar(var, "character") |
40 | 3x |
if (!is_atomic(column)) { |
41 | ! |
stop(sprintf("%s must be an atomic vector.", sQuote("x")), call. = FALSE) |
42 |
} |
|
43 | ||
44 | 3x |
m <- nrow(x) |
45 | 3x |
if (has_rownames(x) && has_names(column)) { |
46 | 2x |
i <- match(names(column), rownames(x)) |
47 | ||
48 | 2x |
if (anyNA(i)) { |
49 | 1x |
column <- column[!is.na(i)] |
50 | 1x |
i <- i[!is.na(i)] |
51 |
} |
|
52 | ||
53 | 2x |
old_column <- column |
54 | 2x |
column <- rep(NA, m) |
55 | 2x |
column[i] <- old_column |
56 |
} |
|
57 | ||
58 | 3x |
assert_length(column, m) |
59 | ||
60 | 2x |
p <- ncol(x) |
61 | 2x |
if (after > p) after <- p |
62 | 2x |
i_before <- seq_len(after) |
63 | 2x |
i_after <- if (after < p) seq(from = after + 1, to = p, by = 1) else 0 |
64 | ||
65 | 2x |
x <- cbind(x[, i_before, drop = FALSE], column, x[, i_after, drop = FALSE]) |
66 | ||
67 | 2x |
colnames(x)[after + 1] <- var |
68 | 2x |
x |
69 |
} |
|
70 |
) |
1 |
# DATA CLEANING: REMOVE |
|
2 |
#' @include AllGenerics.R |
|
3 |
NULL |
|
4 | ||
5 |
# Missing values =============================================================== |
|
6 |
#' @export |
|
7 |
#' @rdname remove_NA |
|
8 |
#' @aliases remove_NA,ANY-method |
|
9 |
setMethod( |
|
10 |
f = "remove_NA", |
|
11 |
signature = c(x = "ANY"), |
|
12 |
definition = function(x, margin = 1, all = FALSE, |
|
13 |
verbose = getOption("arkhe.verbose")) { |
|
14 | 4x |
discard(x, f = is.na, margin = margin, all = all, verbose = verbose) |
15 |
} |
|
16 |
) |
|
17 | ||
18 |
# Infinite values ============================================================== |
|
19 |
#' @export |
|
20 |
#' @rdname remove_Inf |
|
21 |
#' @aliases remove_Inf,ANY-method |
|
22 |
setMethod( |
|
23 |
f = "remove_Inf", |
|
24 |
signature = c(x = "ANY"), |
|
25 |
definition = function(x, margin = 1, all = FALSE, |
|
26 |
verbose = getOption("arkhe.verbose")) { |
|
27 | 4x |
discard(x, f = is.infinite, margin = margin, all = all, verbose = verbose) |
28 |
} |
|
29 |
) |
|
30 | ||
31 |
# Zeros ======================================================================== |
|
32 |
#' @export |
|
33 |
#' @rdname remove_zero |
|
34 |
#' @aliases remove_zero,ANY-method |
|
35 |
setMethod( |
|
36 |
f = "remove_zero", |
|
37 |
signature = c(x = "ANY"), |
|
38 |
definition = function(x, margin = 1, all = FALSE, |
|
39 |
verbose = getOption("arkhe.verbose")) { |
|
40 | 4x |
discard(x, f = is_zero_numeric, margin = margin, |
41 | 4x |
all = all, na.rm = TRUE, verbose = verbose) |
42 |
} |
|
43 |
) |
|
44 | ||
45 |
# Empty string ================================================================= |
|
46 |
#' @export |
|
47 |
#' @rdname remove_empty |
|
48 |
#' @aliases remove_empty,ANY-method |
|
49 |
setMethod( |
|
50 |
f = "remove_empty", |
|
51 |
signature = c(x = "ANY"), |
|
52 |
definition = function(x, margin = 1, all = FALSE, |
|
53 |
verbose = getOption("arkhe.verbose")) { |
|
54 | 4x |
discard(x, f = nzchar, margin = margin, negate = TRUE, |
55 | 4x |
all = all, na.rm = TRUE, verbose = verbose) |
56 |
} |
|
57 |
) |
|
58 | ||
59 |
# Constant ===================================================================== |
|
60 |
#' @export |
|
61 |
#' @rdname remove_constant |
|
62 |
#' @aliases remove_constant,ANY-method |
|
63 |
setMethod( |
|
64 |
f = "remove_constant", |
|
65 |
signature = c(x = "ANY"), |
|
66 |
definition = function(x, na.rm = FALSE, verbose = getOption("arkhe.verbose")) { |
|
67 | 6x |
discard(x, f = function(x) { is_unique(x, na.rm = na.rm) }, |
68 | 3x |
margin = 2, all = FALSE, verbose = verbose) |
69 |
} |
|
70 |
) |