Title: | Wrap R Tools for Debugging and Parametric Programming |
---|---|
Description: | Tools for writing and debugging R code. Provides: '%.>%' dot-pipe (an 'S3' configurable pipe), unpack/to (R style multiple assignment/return), 'build_frame()'/'draw_frame()' ('data.frame' example tools), 'qc()' (quoting concatenate), ':=' (named map builder), 'let()' (converts non-standard evaluation interfaces to parametric standard evaluation interfaces, inspired by 'gtools::strmacro()' and 'base::bquote()'), and more. |
Authors: | John Mount [aut, cre], Nina Zumel [aut], Win-Vector LLC [cph] |
Maintainer: | John Mount <[email protected]> |
License: | GPL-2 | GPL-3 |
Version: | 2.1.0 |
Built: | 2025-02-09 02:58:44 UTC |
Source: | https://github.com/winvector/wrapr |
wrapr
: Wrap R Functions for Debugging and Parametric Programming
Provides DebugFnW()
to capture function context on error for
debugging, and let()
which converts non-standard evaluation interfaces to
parametric standard evaluation interfaces.
DebugFnW()
captures the calling function and arguments prior to the
call causing the exception, while
the classic options(error=dump.frames)
form captures at the
moment of the exception
itself (thus function arguments may not be at their starting values).
let()
rebinds (possibly unbound) names to names.
For more information:
vignette('DebugFnW', package='wrapr')
vignette('let', package='wrapr')
vignette(package='wrapr')
Website: https://github.com/WinVector/wrapr
let
video: https://youtu.be/iKLGxzzm9Hk?list=PLAKBwakacHbQp_Z66asDnjn-0qttTO-o9
Debug wrapper video: https://youtu.be/zFEC9-1XSN8?list=PLAKBwakacHbQT51nPHex1on3YNCCmggZA.
Maintainer: John Mount [email protected]
Authors:
Nina Zumel [email protected]
Other contributors:
Win-Vector LLC [copyright holder]
Useful links:
Report bugs at https://github.com/WinVector/wrapr/issues
Prepare for unpack or bind values into the calling environment. This makes pipe to behavior very close to assign to behavior for the Unpacker class.
## S3 method for class 'Unpacker' wrapr_private_self[...]
## S3 method for class 'Unpacker' wrapr_private_self[...]
wrapr_private_self |
object implementing the feature, wrapr::unpack |
... |
names of to unpack to (can be escaped with bquote |
prepared unpacking object
Unpacks or binds values into the calling environment. Uses bquote
escaping.
NULL is a special case that is unpacked to all targets. NA targets are skipped.
All non-NA target names must be unique.
## S3 replacement method for class 'Unpacker' wrapr_private_self[...] <- value
## S3 replacement method for class 'Unpacker' wrapr_private_self[...] <- value
wrapr_private_self |
object implementing the feature, wrapr::unpack |
... |
names of to unpack to (can be escaped with bquote |
value |
list to unpack into values, must have a number of entries equal to number of |
Note: when using []<-
notation, a reference to the unpacker object is written into the unpacking environment as a side-effect
of the implied array assignment. :=
assigment does not have this side-effect.
Array-assign form can not use the names: .
, wrapr_private_self
, value
, or the name of the unpacker itself.
For more details please see here https://win-vector.com/2020/01/20/unpack-your-values-in-r/.
Related work includes Python
tuple unpacking, zeallot
's arrow, and vadr::bind
.
wrapr_private_self
# named unpacking # looks like assignment: DESTINATION = NAME_VALUE_USING d <- data.frame(x = 1:2, g=c('test', 'train'), stringsAsFactors = FALSE) to[train_set = train, test_set = test] := split(d, d$g) # train_set and test_set now correctly split print(train_set) print(test_set) rm(list = c('train_set', 'test_set')) # named unpacking NEWNAME = OLDNAME implicit form # values are matched by name, not index to[train, test] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test')) # bquote example train_col_name <- 'train' test_col_name <- 'test' to[train = .(train_col_name), test = .(test_col_name)] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test'))
# named unpacking # looks like assignment: DESTINATION = NAME_VALUE_USING d <- data.frame(x = 1:2, g=c('test', 'train'), stringsAsFactors = FALSE) to[train_set = train, test_set = test] := split(d, d$g) # train_set and test_set now correctly split print(train_set) print(test_set) rm(list = c('train_set', 'test_set')) # named unpacking NEWNAME = OLDNAME implicit form # values are matched by name, not index to[train, test] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test')) # bquote example train_col_name <- 'train' test_col_name <- 'test' to[train = .(train_col_name), test = .(test_col_name)] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test'))
String interpolation using bquote
-stype .() notation. Pure R, no C/C++ code called.
str %<s% envir
str %<s% envir
str |
charater string to be substituted into |
envir |
environemnt to look for values |
See also https://CRAN.R-project.org/package=R.utils, https://CRAN.R-project.org/package=rprintf, and https://CRAN.R-project.org/package=glue.
modified strings
"x is .(x)" %<s% list(x = 7)
"x is .(x)" %<s% list(x = 7)
Inline list/array concatenate.
e1 %c% e2
e1 %c% e2
e1 |
first, or left argument. |
e2 |
second, or right argument. |
c(e1, c2)
1:2 %c% 5:6 c("a", "b") %c% "d"
1:2 %c% 5:6 c("a", "b") %c% "d"
Inline dot product.
e1 %dot% e2
e1 %dot% e2
e1 |
first, or left argument. |
e2 |
second, or right argument. |
c(e1, c2)
c(1,2) %dot% c(3, 5)
c(1,2) %dot% c(3, 5)
Inline version of let
-block.
a %in_block% b
a %in_block% b
a |
(left argument) named character vector with target names as names, and replacement names as values. |
b |
(right argument) expression or block to evaluate under let substitution rules. |
evaluated block.
d <- data.frame( Sepal_Length=c(5.8,5.7), Sepal_Width=c(4.0,4.4), Species='setosa') # let-block notation let( qc( AREA_COL = Sepal_area, LENGTH_COL = Sepal_Length, WIDTH_COL = Sepal_Width ), d %.>% transform(., AREA_COL = LENGTH_COL * WIDTH_COL) ) # %in_block% notation qc( AREA_COL = Sepal_area, LENGTH_COL = Sepal_Length, WIDTH_COL = Sepal_Width ) %in_block% { d %.>% transform(., AREA_COL = LENGTH_COL * WIDTH_COL) } # Note: in packages can make assignment such as: # AREA_COL <- LENGTH_COL <- WIDTH_COL <- NULL # prior to code so targets don't look like unbound names.
d <- data.frame( Sepal_Length=c(5.8,5.7), Sepal_Width=c(4.0,4.4), Species='setosa') # let-block notation let( qc( AREA_COL = Sepal_area, LENGTH_COL = Sepal_Length, WIDTH_COL = Sepal_Width ), d %.>% transform(., AREA_COL = LENGTH_COL * WIDTH_COL) ) # %in_block% notation qc( AREA_COL = Sepal_area, LENGTH_COL = Sepal_Length, WIDTH_COL = Sepal_Width ) %in_block% { d %.>% transform(., AREA_COL = LENGTH_COL * WIDTH_COL) } # Note: in packages can make assignment such as: # AREA_COL <- LENGTH_COL <- WIDTH_COL <- NULL # prior to code so targets don't look like unbound names.
Inline character paste0.
e1 %p% e2
e1 %p% e2
e1 |
first, or left argument. |
e2 |
second, or right argument. |
c(e1, c2)
"a" %p% "b" c("a", "b") %p% "_d"
"a" %p% "b" c("a", "b") %p% "_d"
Inline quoting list/array concatenate.
e1 %qc% e2
e1 %qc% e2
e1 |
first, or left argument. |
e2 |
second, or right argument. |
qc(e1, c2)
1:2 %qc% 5:6 c("a", "b") %qc% d a %qc% b %qc% c
1:2 %qc% 5:6 c("a", "b") %qc% d a %qc% b %qc% c
String interpolation using bquote
-stype .() notation. Pure R, no C/C++ code called.
envir %s>% str
envir %s>% str
envir |
environemnt to look for values |
str |
charater string to be substituted into |
See also https://CRAN.R-project.org/package=R.utils, https://CRAN.R-project.org/package=rprintf, and https://CRAN.R-project.org/package=glue.
modified strings
list(x = 7) %s>% "x is .(x)"
list(x = 7) %s>% "x is .(x)"
Add list name as a column to a list of data.frames.
add_name_column(dlist, destinationColumn)
add_name_column(dlist, destinationColumn)
dlist |
named list of data.frames |
destinationColumn |
character, name of new column to add |
list of data frames, each of which as the new destinationColumn.
dlist <- list(a = data.frame(x = 1), b = data.frame(x = 2)) add_name_column(dlist, 'name')
dlist <- list(a = data.frame(x = 1), b = data.frame(x = 2)) add_name_column(dlist, 'name')
For formal documentation please see https://github.com/WinVector/wrapr/blob/master/extras/wrapr_pipe.pdf.
apply_left( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
apply_left( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
pipe_left_arg |
left argument. |
pipe_right_arg |
substitute(pipe_right_arg) argument. |
pipe_environment |
environment to evaluate in. |
left_arg_name |
name, if not NULL name of left argument. |
pipe_string |
character, name of pipe operator. |
right_arg_name |
name, if not NULL name of right argument. |
result
apply_left.character <- function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { if(is.language(pipe_right_arg)) { wrapr::apply_left_default(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) } else { paste(pipe_left_arg, pipe_right_arg) } } setMethod( wrapr::apply_right_S4, signature = c(pipe_left_arg = "character", pipe_right_arg = "character"), function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { paste(pipe_left_arg, pipe_right_arg) }) "a" %.>% 5 %.>% 7 "a" %.>% toupper(.) q <- "z" "a" %.>% q
apply_left.character <- function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { if(is.language(pipe_right_arg)) { wrapr::apply_left_default(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) } else { paste(pipe_left_arg, pipe_right_arg) } } setMethod( wrapr::apply_right_S4, signature = c(pipe_left_arg = "character", pipe_right_arg = "character"), function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { paste(pipe_left_arg, pipe_right_arg) }) "a" %.>% 5 %.>% 7 "a" %.>% toupper(.) q <- "z" "a" %.>% q
Place evaluation of left argument in .
and then evaluate right argument.
apply_left_default( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
apply_left_default( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
pipe_left_arg |
left argument |
pipe_right_arg |
substitute(pipe_right_arg) argument |
pipe_environment |
environment to evaluate in |
left_arg_name |
name, if not NULL name of left argument. |
pipe_string |
character, name of pipe operator. |
right_arg_name |
name, if not NULL name of right argument. |
result
5 %.>% sin(.)
5 %.>% sin(.)
Place evaluation of left argument in .
and then evaluate right argument.
## Default S3 method: apply_left( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
## Default S3 method: apply_left( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
pipe_left_arg |
left argument |
pipe_right_arg |
substitute(pipe_right_arg) argument |
pipe_environment |
environment to evaluate in |
left_arg_name |
name, if not NULL name of left argument. |
pipe_string |
character, name of pipe operator. |
right_arg_name |
name, if not NULL name of right argument. |
result
5 %.>% sin(.)
5 %.>% sin(.)
Triggered if right hand side of pipe stage was a name that does not resolve to a function. For formal documentation please see https://github.com/WinVector/wrapr/blob/master/extras/wrapr_pipe.pdf.
apply_right( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
apply_right( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
pipe_left_arg |
left argument |
pipe_right_arg |
right argument |
pipe_environment |
environment to evaluate in |
left_arg_name |
name, if not NULL name of left argument. |
pipe_string |
character, name of pipe operator. |
right_arg_name |
name, if not NULL name of right argument. |
result
# simulate a function pointer apply_right.list <- function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { pipe_right_arg$f(pipe_left_arg) } f <- list(f=sin) 2 %.>% f f$f <- cos 2 %.>% f
# simulate a function pointer apply_right.list <- function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { pipe_right_arg$f(pipe_left_arg) } f <- list(f=sin) 2 %.>% f f$f <- cos 2 %.>% f
Intended to be generic on first two arguments.
apply_right_S4( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
apply_right_S4( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
pipe_left_arg |
left argument |
pipe_right_arg |
pipe_right_arg argument |
pipe_environment |
environment to evaluate in |
left_arg_name |
name, if not NULL name of left argument. |
pipe_string |
character, name of pipe operator. |
right_arg_name |
name, if not NULL name of right argument. |
result
a <- data.frame(x = 1) b <- data.frame(x = 2) # a %.>% b # will (intentionally) throw setMethod( "apply_right_S4", signature("data.frame", "data.frame"), function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { rbind(pipe_left_arg, pipe_right_arg) }) a %.>% b # should equal data.frame(x = c(1, 2))
a <- data.frame(x = 1) b <- data.frame(x = 2) # a %.>% b # will (intentionally) throw setMethod( "apply_right_S4", signature("data.frame", "data.frame"), function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { rbind(pipe_left_arg, pipe_right_arg) }) a %.>% b # should equal data.frame(x = c(1, 2))
Default apply_right implementation: S4 dispatch to apply_right_S4.
## Default S3 method: apply_right( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
## Default S3 method: apply_right( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name )
pipe_left_arg |
left argument |
pipe_right_arg |
pipe_right_arg argument |
pipe_environment |
environment to evaluate in |
left_arg_name |
name, if not NULL name of left argument. |
pipe_string |
character, name of pipe operator. |
right_arg_name |
name, if not NULL name of right argument. |
result
apply_left
, apply_right
, apply_right_S4
# simulate a function pointer apply_right.list <- function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { pipe_right_arg$f(pipe_left_arg) } f <- list(f=sin) 2 %.>% f f$f <- cos 2 %.>% f
# simulate a function pointer apply_right.list <- function(pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { pipe_right_arg$f(pipe_left_arg) } f <- list(f=sin) 2 %.>% f f$f <- cos 2 %.>% f
Build a named list from a sequence of named arguments of the form NAME, or NAME = VALUE.
This is intended to shorten forms such as list(a = a, b = b)
to as_named_list(a, b)
.
as_named_list(...)
as_named_list(...)
... |
argument names (must be names, not strings or values) plus possible assigned values. |
a named list mapping argument names to argument values
a <- data.frame(x = 1) b <- 2 str(as_named_list(a, b)) as_named_list(a, x = b, c = 1 + 1) # an example application for this function is managing saving and # loading values into the workspace. if(FALSE) { # remotes::install_github("WinVector/wrapr") library(wrapr) a <- 5 b <- 7 do_not_want <- 13 # save the elements of our workspace we want saveRDS(as_named_list(a, b), 'example_data.RDS') # clear values out of our workspace for the example rm(list = ls()) ls() # notice workspace environemnt now empty # read back while documenting what we expect to # read in unpack[a, b] <- readRDS('example_data.RDS') # confirm what we have, the extra unpack is a side # effect of the []<- notation. To avoid this instead # use one of: # unpack(readRDS('example_data.RDS'), a, b) # readRDS('example_data.RDS') %.>% unpack(., a, b) # readRDS('example_data.RDS') %.>% unpack[a, b] ls() # notice do_not_want is not present print(a) print(b) }
a <- data.frame(x = 1) b <- 2 str(as_named_list(a, b)) as_named_list(a, x = b, c = 1 + 1) # an example application for this function is managing saving and # loading values into the workspace. if(FALSE) { # remotes::install_github("WinVector/wrapr") library(wrapr) a <- 5 b <- 7 do_not_want <- 13 # save the elements of our workspace we want saveRDS(as_named_list(a, b), 'example_data.RDS') # clear values out of our workspace for the example rm(list = ls()) ls() # notice workspace environemnt now empty # read back while documenting what we expect to # read in unpack[a, b] <- readRDS('example_data.RDS') # confirm what we have, the extra unpack is a side # effect of the []<- notation. To avoid this instead # use one of: # unpack(readRDS('example_data.RDS'), a, b) # readRDS('example_data.RDS') %.>% unpack(., a, b) # readRDS('example_data.RDS') %.>% unpack[a, b] ls() # notice do_not_want is not present print(a) print(b) }
Separates string data on whitespace and separating symbols into an array.
bc(s, ..., sep_symbols = ",|", strict = TRUE, convert = TRUE)
bc(s, ..., sep_symbols = ",|", strict = TRUE, convert = TRUE)
s |
string to parse |
... |
force later arguments to be set by name |
sep_symbols |
characters to consider separators |
strict |
logical, if TRUE throw exception on confusing input |
convert |
logical, if TRUE try to convert from string type to other types |
Can throw exception on lack of explicit value separators, example: bc('"a""b"')
and non-matching portions.
Whitespace is normalized to spaces. Attempts to split on obvious number format boundaries.
Suggested by Emil Erik Pula Bellamy Begtrup-Bright https://github.com/WinVector/wrapr/issues/12.
vector of values
bc('1 2 "c", d') # returns c("1", "2", "c", "d") bc('1 2 3') # returns c(1, 2, 3) bc('1 2 "3"') # returns c("1", "2", "3") bc('1,2|3.4') # returns c(1, 2, 3.4) bc('01 02', convert=FALSE) # returns c("01", "02")
bc('1 2 "c", d') # returns c("1", "2", "c", "d") bc('1 2 3') # returns c(1, 2, 3) bc('1 2 "3"') # returns c("1", "2", "3") bc('1,2|3.4') # returns c(1, 2, 3.4) bc('01 02', convert=FALSE) # returns c("01", "02")
bquote_call_args is a helper to allow the user to write functions with bquote-enabled argument substitution.
Uses convetion that := is considered a alias for =.
Re-writes call args to evaluate expr
with bquote
.()
substitution.
Including .(-x)
promoting x
's value from character to a name,
which is called "quote negation" (hence the minus-sign).
bquote_call_args(call, env = parent.frame())
bquote_call_args(call, env = parent.frame())
call |
result of match.call() |
env |
environment to perform lookups in. |
name list of values
f <- function(q, ...) { env = parent.frame() # match.call() best called in function context. captured_call <- match.call() captured_args <- bquote_call_args(captured_call, env) captured_args } z <- "x" y <- 5 qv <- 3 # equivalent to f(3, x = 5) f(.(qv), .(z) := .(y)) # equivalent to f(q = 7) qname <- 'q' f(.(qname) := 7)
f <- function(q, ...) { env = parent.frame() # match.call() best called in function context. captured_call <- match.call() captured_args <- bquote_call_args(captured_call, env) captured_args } z <- "x" y <- 5 qv <- 3 # equivalent to f(3, x = 5) f(.(qv), .(z) := .(y)) # equivalent to f(q = 7) qname <- 'q' f(.(qname) := 7)
bquote_function is for adapting a function defined elsewhere for bquote-enabled argument substitution.
Re-write call to evaluate expr
with bquote
.()
substitution.
Uses convetion that := is considered a alias for =.
Including .(-x)
promoting x
's value from character to a name,
which is called "quote negation" (hence the minus-sign).
bquote_function(fn)
bquote_function(fn)
fn |
function to adapt, must have non-empty formals(). |
new function.
if(requireNamespace('graphics', quietly = TRUE)) { angle = 1:10 variable <- as.name("angle") plotb <- bquote_function(graphics::plot) plotb(x = .(variable), y = sin(.(variable))) } f1 <- function(x) { substitute(x) } f2 <- bquote_function(f1) arg <- "USER_ARG" f2(arg) # returns arg f2(.(arg)) # returns "USER_ARG" (character) f2(.(-arg)) # returns USER_ARG (name)
if(requireNamespace('graphics', quietly = TRUE)) { angle = 1:10 variable <- as.name("angle") plotb <- bquote_function(graphics::plot) plotb(x = .(variable), y = sin(.(variable))) } f1 <- function(x) { substitute(x) } f2 <- bquote_function(f1) arg <- "USER_ARG" f2(arg) # returns arg f2(.(arg)) # returns "USER_ARG" (character) f2(.(-arg)) # returns USER_ARG (name)
A convenient way to build a data.frame in legible transposed form. Position of first "|" (or other infix operator) determines number of columns (all other infix operators are aliases for ","). Names are de-referenced.
build_frame(..., cf_eval_environment = parent.frame())
build_frame(..., cf_eval_environment = parent.frame())
... |
cell names, first infix operator denotes end of header row of column names. |
cf_eval_environment |
environment to evaluate names in. |
character data.frame
tc_name <- "training" x <- build_frame( "measure", tc_name, "validation" | "minus binary cross entropy", 5, -7 | "accuracy", 0.8, 0.6 ) print(x) str(x) cat(draw_frame(x)) build_frame( "x" | -1 | 2 )
tc_name <- "training" x <- build_frame( "measure", tc_name, "validation" | "minus binary cross entropy", 5, -7 | "accuracy", 0.8, 0.6 ) print(x) str(x) cat(draw_frame(x)) build_frame( "x" | -1 | 2 )
Build a custom writeback function that writes state into a user named variable.
buildNameCallback(varName)
buildNameCallback(varName)
varName |
character where to write captured state |
writeback function for use with functions such as DebugFnW
# user function f <- function(i) { (1:10)[[i]] } # capture last error in variable called "lastError" writeBack <- buildNameCallback('lastError') # wrap function with writeBack df <- DebugFnW(writeBack,f) # capture error (Note: tryCatch not needed for user code!) tryCatch( df(12), error = function(e) { print(e) }) # examine error str(lastError) # redo call, perhaps debugging tryCatch( do.call(lastError$fn_name, lastError$args), error = function(e) { print(e) })
# user function f <- function(i) { (1:10)[[i]] } # capture last error in variable called "lastError" writeBack <- buildNameCallback('lastError') # wrap function with writeBack df <- DebugFnW(writeBack,f) # capture error (Note: tryCatch not needed for user code!) tryCatch( df(12), error = function(e) { print(e) }) # examine error str(lastError) # redo call, perhaps debugging tryCatch( do.call(lastError$fn_name, lastError$args), error = function(e) { print(e) })
Confirm two dataframes are equivalent after reordering columns and rows.
check_equiv_frames(d1, d2, ..., tolerance = sqrt(.Machine$double.eps))
check_equiv_frames(d1, d2, ..., tolerance = sqrt(.Machine$double.eps))
d1 |
data.frame 1 |
d2 |
data.frame 2 |
... |
force later arguments to bind by name |
tolerance |
numeric comparision tolerance |
logical TRUE if equivalent
For local data.frame only.
checkColsFormUniqueKeys(data, keyColNames)
checkColsFormUniqueKeys(data, keyColNames)
data |
data.frame to work with. |
keyColNames |
character array of column names to check. |
logical TRUE if the rows of data are unique addressable by the columns named in keyColNames.
d <- data.frame(key = c('a','a', 'b'), k2 = c(1 ,2, 2)) checkColsFormUniqueKeys(d, 'key') # should be FALSE checkColsFormUniqueKeys(d, c('key', 'k2')) # should be TRUE
d <- data.frame(key = c('a','a', 'b'), k2 = c(1 ,2, 2)) checkColsFormUniqueKeys(d, 'key') # should be FALSE checkColsFormUniqueKeys(d, c('key', 'k2')) # should be TRUE
Please see https://win-vector.com/2014/05/30/trimming-the-fat-from-glm-models-in-r/ for discussion.
clean_fit_glm( outcome, variables, data, ..., family, intercept = TRUE, outcome_target = NULL, outcome_comparator = "==", weights = NULL, env = baseenv() )
clean_fit_glm( outcome, variables, data, ..., family, intercept = TRUE, outcome_target = NULL, outcome_comparator = "==", weights = NULL, env = baseenv() )
outcome |
character, name of outcome column. |
variables |
character, names of varaible columns. |
data |
data.frame, training data. |
... |
not used, force later arguments to be used by name |
family |
passed to stats::glm() |
intercept |
logical, if TRUE allow an intercept term. |
outcome_target |
scalar, if not NULL write outcome==outcome_target in formula. |
outcome_comparator |
one of "==", "!=", ">=", "<=", ">", "<", only use of outcome_target is not NULL. |
weights |
passed to stats::glm() |
env |
environment to work in. |
list(model=model, summary=summary)
mk_data_example <- function(k) { data.frame( x1 = rep(c("a", "a", "b", "b"), k), x2 = rep(c(0, 0, 0, 1), k), y = rep(1:4, k), yC = rep(c(FALSE, TRUE, TRUE, TRUE), k), stringsAsFactors = FALSE) } res_glm <- clean_fit_glm("yC", c("x1", "x2"), mk_data_example(1), family = binomial) length(serialize(res_glm$model, NULL)) res_glm <- clean_fit_glm("yC", c("x1", "x2"), mk_data_example(10000), family = binomial) length(serialize(res_glm$model, NULL)) predict(res_glm$model, newdata = mk_data_example(1), type = "response")
mk_data_example <- function(k) { data.frame( x1 = rep(c("a", "a", "b", "b"), k), x2 = rep(c(0, 0, 0, 1), k), y = rep(1:4, k), yC = rep(c(FALSE, TRUE, TRUE, TRUE), k), stringsAsFactors = FALSE) } res_glm <- clean_fit_glm("yC", c("x1", "x2"), mk_data_example(1), family = binomial) length(serialize(res_glm$model, NULL)) res_glm <- clean_fit_glm("yC", c("x1", "x2"), mk_data_example(10000), family = binomial) length(serialize(res_glm$model, NULL)) predict(res_glm$model, newdata = mk_data_example(1), type = "response")
Please see https://win-vector.com/2014/05/30/trimming-the-fat-from-glm-models-in-r/ for discussion.
clean_fit_lm( outcome, variables, data, ..., intercept = TRUE, weights = NULL, env = baseenv() )
clean_fit_lm( outcome, variables, data, ..., intercept = TRUE, weights = NULL, env = baseenv() )
outcome |
character, name of outcome column. |
variables |
character, names of varaible columns. |
data |
data.frame, training data. |
... |
not used, force later arguments to be used by name |
intercept |
logical, if TRUE allow an intercept term. |
weights |
passed to stats::glm() |
env |
environment to work in. |
list(model=model, summary=summary)
mk_data_example <- function(k) { data.frame( x1 = rep(c("a", "a", "b", "b"), k), x2 = rep(c(0, 0, 0, 1), k), y = rep(1:4, k), yC = rep(c(FALSE, TRUE, TRUE, TRUE), k), stringsAsFactors = FALSE) } res_lm <- clean_fit_lm("y", c("x1", "x2"), mk_data_example(1)) length(serialize(res_lm$model, NULL)) res_lm <- clean_fit_lm("y", c("x1", "x2"), mk_data_example(10000)) length(serialize(res_lm$model, NULL)) predict(res_lm$model, newdata = mk_data_example(1))
mk_data_example <- function(k) { data.frame( x1 = rep(c("a", "a", "b", "b"), k), x2 = rep(c(0, 0, 0, 1), k), y = rep(1:4, k), yC = rep(c(FALSE, TRUE, TRUE, TRUE), k), stringsAsFactors = FALSE) } res_lm <- clean_fit_lm("y", c("x1", "x2"), mk_data_example(1)) length(serialize(res_lm$model, NULL)) res_lm <- clean_fit_lm("y", c("x1", "x2"), mk_data_example(10000)) length(serialize(res_lm$model, NULL)) predict(res_lm$model, newdata = mk_data_example(1))
This is a simple "try to take values on the left, but fall back
to the right if they are not available" operator. It is inspired
by SQL coalesce and the notation is designed to
evoke the idea of testing and the C#
??
null coalescing operator.
NA
and NULL
are treated roughly equally: both are
replaced regardless of available replacement value (with some exceptions).
The exceptions are: if the left hand side is a non-zero length vector
we preserve the vector type of the left-hand side and do not assign
any values that vectors can not hold (NULLs and complex structures) and do not
replace with a right argument list.
coalesce(coalesce_left_arg, coalesce_right_arg) coalesce_left_arg %?% coalesce_right_arg
coalesce(coalesce_left_arg, coalesce_right_arg) coalesce_left_arg %?% coalesce_right_arg
coalesce_left_arg |
vector or list. |
coalesce_right_arg |
vector or list. |
This operator represents a compromise between the desire to replace
length zero structures and NULL/NA values and the desire to preserve
the first argument's structure (vector versus list). The order of
operations has been chosen to be safe, convenient, and useful. Length zero
lists are not treated as NULL (which is consistent with R in general).
Note for non-vector operations on conditions we recommend looking into
isTRUE
, which solves some problems even faster
than coalesce style operators.
When length(coalesce_left_arg)<=0 then return coalesce_right_arg if length(coalesce_right_arg)>0, otherwise return coalesce_left_arg. When length(coalesce_left_arg)>0: assume coalesce_left_arg is a list or vector and coalesce_right_arg is a list or vector that is either the same length as coalesce_left_arg or length 1. In this case replace NA/NULL elements of coalesce_left_arg with corresponding elements of coalesce_right_arg (re-cycling coalesce_right_arg when it is length 1).
coalesce_left_arg with NA elements replaced.
coalesce_left_arg %?% coalesce_right_arg
: coalesce operator
c(NA, NA, NA) %?% 5 # returns c(5, 5, 5) c(1, NA, NA) %?% list(5) # returns c(1, 5, 5) c(1, NA, NA) %?% list(list(5)) # returns c(1, NA, NA) c(1, NA, NA) %?% c(NA, 20, NA) # returns c(1, 20, NA) NULL %?% list() # returns NULL NULL %?% c(1, NA) # returns c(1, NA) list(1, NULL, NULL) %?% c(3, 4, NA) # returns list(1, 4, NA_real_) list(1, NULL, NULL, NA, NA) %?% list(2, NULL, NA, NULL, NA) # returns list(1, NULL, NA, NULL, NA) c(1, NA, NA) %?% list(1, 2, list(3)) # returns c(1, 2, NA) c(1, NA) %?% list(1, NULL) # returns c(1, NA) c() %?% list(1, NA, NULL) # returns list(1, NA, NULL) c() %?% c(1, NA, 2) # returns c(1, NA, 2)
c(NA, NA, NA) %?% 5 # returns c(5, 5, 5) c(1, NA, NA) %?% list(5) # returns c(1, 5, 5) c(1, NA, NA) %?% list(list(5)) # returns c(1, NA, NA) c(1, NA, NA) %?% c(NA, 20, NA) # returns c(1, 20, NA) NULL %?% list() # returns NULL NULL %?% c(1, NA) # returns c(1, NA) list(1, NULL, NULL) %?% c(3, 4, NA) # returns list(1, 4, NA_real_) list(1, NULL, NULL, NA, NA) %?% list(2, NULL, NA, NULL, NA) # returns list(1, NULL, NA, NULL, NA) c(1, NA, NA) %?% list(1, 2, list(3)) # returns c(1, 2, NA) c(1, NA) %?% list(1, NULL) # returns c(1, NA) c() %?% list(1, NA, NULL) # returns list(1, NA, NULL) c() %?% c(1, NA, 2) # returns c(1, NA, 2)
Run fn, save arguments on failure.
Please see: vignette("DebugFnW", package="wrapr")
.
DebugFn(saveDest, fn, ...)
DebugFn(saveDest, fn, ...)
saveDest |
where to write captured state (determined by type): NULL random temp file, character temp file, name globalenv() variable, and function triggers callback. |
fn |
function to call |
... |
arguments for fn |
fn(...) normally, but if fn(...) throws an exception save to saveDest RDS of list r such that do.call(r$fn,r$args) repeats the call to fn with args.
dump.frames
, DebugFn
, DebugFnW
, DebugFnWE
, DebugPrintFn
, DebugFnE
, DebugPrintFnE
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } # correct run DebugFn(saveDest, f, 5) # now re-run # capture error on incorrect run tryCatch( DebugFn(saveDest, f, 12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn_name,situation$args) # clean up file.remove(saveDest)
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } # correct run DebugFn(saveDest, f, 5) # now re-run # capture error on incorrect run tryCatch( DebugFn(saveDest, f, 12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn_name,situation$args) # clean up file.remove(saveDest)
Run fn, save arguments, and environment on failure.
Please see: vignette("DebugFnW", package="wrapr")
.
DebugFnE(saveDest, fn, ...)
DebugFnE(saveDest, fn, ...)
saveDest |
where to write captured state (determined by type): NULL random temp file, character temp file, name globalenv() variable, and function triggers callback. |
fn |
function to call |
... |
arguments for fn |
fn(...) normally, but if fn(...) throws an exception save to saveDest RDS of list r such that do.call(r$fn,r$args) repeats the call to fn with args.
dump.frames
, DebugFn
, DebugFnW
, DebugFnWE
, DebugPrintFn
, DebugFnE
, DebugPrintFnE
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } # correct run DebugFnE(saveDest, f, 5) # now re-run # capture error on incorrect run tryCatch( DebugFnE(saveDest, f, 12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn, situation$args, envir=situation$env) # clean up file.remove(saveDest)
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } # correct run DebugFnE(saveDest, f, 5) # now re-run # capture error on incorrect run tryCatch( DebugFnE(saveDest, f, 12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn, situation$args, envir=situation$env) # clean up file.remove(saveDest)
Wrap fn, so it will save arguments on failure.
DebugFnW(saveDest, fn)
DebugFnW(saveDest, fn)
saveDest |
where to write captured state (determined by type): NULL random temp file, character temp file, name globalenv() variable, and function triggers callback. |
fn |
function to call |
wrapped function that saves state on error.
dump.frames
, DebugFn
, DebugFnW
, DebugFnWE
, DebugPrintFn
, DebugFnE
, DebugPrintFnE
Operator idea from: https://gist.github.com/nassimhaddad/c9c327d10a91dcf9a3370d30dff8ac3d .
Please see: vignette("DebugFnW", package="wrapr")
.
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } df <- DebugFnW(saveDest,f) # correct run df(5) # now re-run # capture error on incorrect run tryCatch( df(12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn,situation$args) # clean up file.remove(saveDest) f <- function(i) { (1:10)[[i]] } curEnv <- environment() writeBack <- function(sit) { assign('lastError', sit, envir=curEnv) } attr(writeBack,'name') <- 'writeBack' df <- DebugFnW(writeBack,f) tryCatch( df(12), error = function(e) { print(e) }) str(lastError)
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } df <- DebugFnW(saveDest,f) # correct run df(5) # now re-run # capture error on incorrect run tryCatch( df(12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn,situation$args) # clean up file.remove(saveDest) f <- function(i) { (1:10)[[i]] } curEnv <- environment() writeBack <- function(sit) { assign('lastError', sit, envir=curEnv) } attr(writeBack,'name') <- 'writeBack' df <- DebugFnW(writeBack,f) tryCatch( df(12), error = function(e) { print(e) }) str(lastError)
Wrap fn, so it will save arguments and environment on failure.
Please see: vignette("DebugFnW", package="wrapr")
.
DebugFnWE(saveDest, fn, ...)
DebugFnWE(saveDest, fn, ...)
saveDest |
where to write captured state (determined by type): NULL random temp file, character temp file, name globalenv() variable, and function triggers callback. |
fn |
function to call |
... |
arguments for fn |
wrapped function that captures state on error.
dump.frames
, DebugFn
, DebugFnW
, DebugFnWE
, DebugPrintFn
, DebugFnE
, DebugPrintFnE
Idea from: https://gist.github.com/nassimhaddad/c9c327d10a91dcf9a3370d30dff8ac3d
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } df <- DebugFnWE(saveDest, f) # correct run df(5) # now re-run # capture error on incorrect run tryCatch( df(12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn, situation$args, envir=situation$env) # clean up file.remove(saveDest)
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } df <- DebugFnWE(saveDest, f) # correct run df(5) # now re-run # capture error on incorrect run tryCatch( df(12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn, situation$args, envir=situation$env) # clean up file.remove(saveDest)
Run fn and print result, save arguments on failure. Use on systems like ggplot()
where some calculation is delayed until print()
.
Please see: vignette("DebugFnW", package="wrapr")
.
DebugPrintFn(saveDest, fn, ...)
DebugPrintFn(saveDest, fn, ...)
saveDest |
where to write captured state (determined by type): NULL random temp file, character temp file, name globalenv() variable, and function triggers callback. |
fn |
function to call |
... |
arguments for fn |
fn(...) normally, but if fn(...) throws an exception save to saveDest RDS of list r such that do.call(r$fn,r$args) repeats the call to fn with args.
dump.frames
, DebugFn
, DebugFnW
, DebugFnWE
, DebugPrintFn
, DebugFnE
, DebugPrintFnE
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } # correct run DebugPrintFn(saveDest, f, 5) # now re-run # capture error on incorrect run tryCatch( DebugPrintFn(saveDest, f, 12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn,situation$args) # clean up file.remove(saveDest)
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } # correct run DebugPrintFn(saveDest, f, 5) # now re-run # capture error on incorrect run tryCatch( DebugPrintFn(saveDest, f, 12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn,situation$args) # clean up file.remove(saveDest)
Run fn and print result, save arguments and environment on failure. Use on systems like ggplot()
where some calculation is delayed until print().
Please see: vignette("DebugFnW", package="wrapr")
.
DebugPrintFnE(saveDest, fn, ...)
DebugPrintFnE(saveDest, fn, ...)
saveDest |
where to write captured state (determined by type): NULL random temp file, character temp file, name globalenv() variable, and function triggers callback. |
fn |
function to call |
... |
arguments for fn |
fn(...) normally, but if fn(...) throws an exception save to saveDest RDS of list r such that do.call(r$fn,r$args) repeats the call to fn with args.
dump.frames
, DebugFn
, DebugFnW
, DebugFnWE
, DebugPrintFn
, DebugFnE
, DebugPrintFnE
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } # correct run DebugPrintFnE(saveDest, f, 5) # now re-run # capture error on incorrect run tryCatch( DebugPrintFnE(saveDest, f, 12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn, situation$args, envir=situation$env) # clean up file.remove(saveDest)
saveDest <- paste0(tempfile('debug'),'.RDS') f <- function(i) { (1:10)[[i]] } # correct run DebugPrintFnE(saveDest, f, 5) # now re-run # capture error on incorrect run tryCatch( DebugPrintFnE(saveDest, f, 12), error = function(e) { print(e) }) # examine details situation <- readRDS(saveDest) str(situation) # fix and re-run situation$args[[1]] <- 6 do.call(situation$fn, situation$args, envir=situation$env) # clean up file.remove(saveDest)
Use this to place a copy of the lambda-symbol function builder in your workspace.
defineLambda(envir = parent.frame(), name = NULL)
defineLambda(envir = parent.frame(), name = NULL)
envir |
environment to work in. |
name |
character, name to assign to (defaults to Greek lambda). |
lambda
, makeFunction_se
, named_map_builder
defineLambda() # ls()
defineLambda() # ls()
Defined as roughly : a %>.% b
~ { . <- a; b };
(with visible .-side effects).
pipe_left_arg %.>% pipe_right_arg pipe_left_arg %>.% pipe_right_arg pipe_left_arg %.% pipe_right_arg
pipe_left_arg %.>% pipe_right_arg pipe_left_arg %>.% pipe_right_arg pipe_left_arg %.% pipe_right_arg
pipe_left_arg |
left argument expression (substituted into .) |
pipe_right_arg |
right argument expression (presumably including .) |
The pipe operator has a couple of special cases. First: if the right hand side is a name, then we try to de-reference it and apply it as a function or surrogate function.
The pipe operator checks for and throws an exception for a number of "piped into
nothing cases" such as 5 %.>% sin()
, many of these checks can be turned
off by adding braces.
For some discussion, please see https://win-vector.com/2017/07/07/in-praise-of-syntactic-sugar/.
For some more examples, please see the package README https://github.com/WinVector/wrapr.
For formal documentation please see https://github.com/WinVector/wrapr/blob/master/extras/wrapr_pipe.pdf.
For a base-R step-debuggable pipe please try the Bizarro Pipe https://win-vector.com/2017/01/29/using-the-bizarro-pipe-to-debug-magrittr-pipelines-in-r/.
%>.%
and %.>%
are synonyms.
The dot arrow pipe has S3/S4 dispatch (please see https://journal.r-project.org/archive/2018/RJ-2018-042/index.html). However as the right-hand side of the pipe is normally held unevaluated, we don't know the type except in special cases (such as the rigth-hand side being referred to by a name or variable). To force the evaluation of a pipe term, simply wrap it in .().
eval({ . <- pipe_left_arg; pipe_right_arg };)
pipe_left_arg %.>% pipe_right_arg
: dot arrow
pipe_left_arg %>.% pipe_right_arg
: alias for dot arrow
pipe_left_arg %.% pipe_right_arg
: alias for dot arrow
# both should be equal: cos(exp(sin(4))) 4 %.>% sin(.) %.>% exp(.) %.>% cos(.) f <- function() { sin } # returns f() ignoring dot, not what we want 5 %.>% f() # evaluates f() early then evaluates result with .-substitution rules 5 %.>% .(f())
# both should be equal: cos(exp(sin(4))) 4 %.>% sin(.) %.>% exp(.) %.>% cos(.) f <- function() { sin } # returns f() ignoring dot, not what we want 5 %.>% f() # evaluates f() early then evaluates result with .-substitution rules 5 %.>% .(f())
Render a simple data.frame in build_frame format.
draw_frame( x, ..., time_format = "%Y-%m-%d %H:%M:%S", formatC_options = list(), adjust_for_auto_indent = 2 )
draw_frame( x, ..., time_format = "%Y-%m-%d %H:%M:%S", formatC_options = list(), adjust_for_auto_indent = 2 )
x |
data.frame (with atomic types). |
... |
not used for values, forces later arguments to bind by name. |
time_format |
character, format for "POSIXt" classes. |
formatC_options |
named list, options for formatC()- used on numerics. |
adjust_for_auto_indent |
integer additional after first row padding |
character
tc_name <- "training" x <- build_frame( "measure" , tc_name, "validation", "idx" | "minus binary cross entropy", 5 , 7 , 1L | "accuracy" , 0.8 , 0.6 , 2L ) print(x) cat(draw_frame(x))
tc_name <- "training" x <- build_frame( "measure" , tc_name, "validation", "idx" | "minus binary cross entropy", 5 , 7 , 1L | "accuracy" , 0.8 , 0.6 , 2L ) print(x) cat(draw_frame(x))
Render a simple data.frame in qchar_frame format.
draw_framec(x, ..., unquote_cols = character(0), adjust_for_auto_indent = 2)
draw_framec(x, ..., unquote_cols = character(0), adjust_for_auto_indent = 2)
x |
data.frame (with character types). |
... |
not used for values, forces later arguments to bind by name. |
unquote_cols |
character, columns to elide quotes from. |
adjust_for_auto_indent |
integer additional after first row padding. |
character
controlTable <- wrapr::qchar_frame( "flower_part", "Length" , "Width" | "Petal" , Petal.Length , Petal.Width | "Sepal" , Sepal.Length , Sepal.Width ) cat(draw_framec(controlTable, unquote_cols = qc(Length, Width)))
controlTable <- wrapr::qchar_frame( "flower_part", "Length" , "Width" | "Petal" , Petal.Length , Petal.Width | "Sepal" , Sepal.Length , Sepal.Width ) cat(draw_framec(controlTable, unquote_cols = qc(Length, Width)))
eval(bquote(expr))
shortcut.Evaluate expr
with bquote
.()
substitution.
Including .(-x)
promoting x
's value from character to a name,
which is called "quote negation" (hence the minus-sign).
evalb(expr, where = parent.frame())
evalb(expr, where = parent.frame())
expr |
expression to evaluate. |
where |
environment to work in. |
evaluated substituted expression.
if(requireNamespace('graphics', quietly = TRUE)) { angle = 1:10 variable <- as.name("angle") fn_name <- 'sin' evalb( plot(x = .(variable), y = .(-fn_name)(.(variable))) ) }
if(requireNamespace('graphics', quietly = TRUE)) { angle = 1:10 variable <- as.name("angle") fn_name <- 'sin' evalb( plot(x = .(variable), y = .(-fn_name)(.(variable))) ) }
Execute f in parallel partitioned by partition_column
, see
partition_tables
for details.
execute_parallel( tables, f, partition_column, ..., cl = NULL, debug = FALSE, env = parent.frame() )
execute_parallel( tables, f, partition_column, ..., cl = NULL, debug = FALSE, env = parent.frame() )
tables |
named map of tables to use. |
f |
function to apply to each tableset signature is function takes a single argument that is a named list of data.frames. |
partition_column |
character name of column to partition on |
... |
force later arguments to bind by name. |
cl |
parallel cluster. |
debug |
logical if TRUE use lapply instead of parallel::clusterApplyLB. |
env |
environment to look for values in. |
list of f evaluations.
if(requireNamespace("parallel", quietly = TRUE)) { cl <- parallel::makeCluster(2) d <- data.frame(x = 1:5, g = c(1, 1, 2, 2 ,2)) f <- function(dl) { d <- dl$d d$s <- sqrt(d$x) d } r <- execute_parallel(list(d = d), f, partition_column = "g", cl = cl) %.>% do.call(rbind, .) %.>% print(.) parallel::stopCluster(cl) }
if(requireNamespace("parallel", quietly = TRUE)) { cl <- parallel::makeCluster(2) d <- data.frame(x = 1:5, g = c(1, 1, 2, 2 ,2)) f <- function(dl) { d <- dl$d d$s <- sqrt(d$x) d } r <- execute_parallel(list(d = d), f, partition_column = "g", cl = cl) %.>% do.call(rbind, .) %.>% print(.) parallel::stopCluster(cl) }
Build an anonymous function of dot.
f.(body, env = parent.frame())
f.(body, env = parent.frame())
body |
function body |
env |
environment to work in. |
user defined function.
lambda
, defineLambda
, named_map_builder
, makeFunction_se
f <- f.(sin(.) %.>% cos(.)) 7 %.>% f
f <- f.(sin(.) %.>% cos(.)) 7 %.>% f
data.frame
Grep for column names from a data.frame
grepdf( pattern, x, ..., ignore.case = FALSE, perl = FALSE, value = FALSE, fixed = FALSE, useBytes = FALSE, invert = FALSE )
grepdf( pattern, x, ..., ignore.case = FALSE, perl = FALSE, value = FALSE, fixed = FALSE, useBytes = FALSE, invert = FALSE )
pattern |
passed to |
x |
data.frame to work with |
... |
force later arguments to be passed by name |
ignore.case |
passed to |
perl |
passed to |
value |
passed to |
fixed |
passed to |
useBytes |
passed to |
invert |
passed to |
column names of x matching grep condition.
d <- data.frame(xa=1, yb=2) # starts with grepdf('^x', d) # ends with grepdf('b$', d)
d <- data.frame(xa=1, yb=2) # starts with grepdf('^x', d) # ends with grepdf('b$', d)
Return a vector of matches.
grepv( pattern, x, ..., ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE, invert = FALSE )
grepv( pattern, x, ..., ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE, invert = FALSE )
pattern |
character scalar, pattern to match, passed to |
x |
character vector to match to, passed to |
... |
not used, forced later arguments to bind by name. |
ignore.case |
logical, passed to |
perl |
logical, passed to |
fixed |
logical, passed to |
useBytes |
logical, passed |
invert |
passed to |
vector of matching values.
grepv("x$", c("sox", "xor"))
grepv("x$", c("sox", "xor"))
Check a simple data.frame (no list or exotic rows) for duplicate rows.
has_no_dup_rows(data)
has_no_dup_rows(data)
data |
data.frame |
TRUE if there are no duplicate rows, else FALSE.
For a permutation p build q such that p[q] == q[p] == seq_len(length(p)). Please see https://win-vector.com/2017/05/18/on-indexing-operators-and-composition/ and https://win-vector.com/2017/09/02/permutation-theory-in-action/.
invert_perm(p)
invert_perm(p)
p |
vector of length n containing each of seq_len(n) exactly once. |
vector q such that p[q] == q[p] == seq_len(length(p))
p <- c(4, 5, 7, 8, 9, 6, 1, 3, 2, 10) q <- invert_perm(p) p[q] all.equal(p[q], seq_len(length(p))) q[p] all.equal(q[p], seq_len(length(p)))
p <- c(4, 5, 7, 8, 9, 6, 1, 3, 2, 10) q <- invert_perm(p) p[q] all.equal(p[q], seq_len(length(p))) q[p] all.equal(q[p], seq_len(length(p)))
Mostly just a place-holder so lambda-symbol form has somewhere safe to hang its help entry.
lambda(..., env = parent.frame())
lambda(..., env = parent.frame())
... |
formal parameters of function, unbound names, followed by function body (code/language). |
env |
environment to work in |
user defined function.
defineLambda
, makeFunction_se
, named_map_builder
#lambda-syntax: lambda(arg [, arg]*, body [, env=env]) # also works with lambda character as function name # print(intToUtf8(0x03BB)) # example: square numbers sapply(1:4, lambda(x, x^2)) # example more than one argument f <- lambda(x, y, x+y) f(2,4)
#lambda-syntax: lambda(arg [, arg]*, body [, env=env]) # also works with lambda character as function name # print(intToUtf8(0x03BB)) # example: square numbers sapply(1:4, lambda(x, x^2)) # example more than one argument f <- lambda(x, y, x+y) f(2,4)
Memoizing wrapper for lapply.
lapplym(X, FUN, ...)
lapplym(X, FUN, ...)
X |
list or vector of inputs |
FUN |
function to apply |
... |
additional arguments passed to lapply |
list of results.
VectorizeM
, vapplym
, parLapplyLBm
fs <- function(x) { x <- x[[1]]; print(paste("see", x)); sin(x) } # should only print "see" twice, not 6 times lapplym(c(0, 1, 1, 0, 0, 1), fs)
fs <- function(x) { x <- x[[1]]; print(paste("see", x)); sin(x) } # should only print "see" twice, not 6 times lapplym(c(0, 1, 1, 0, 0, 1), fs)
let
implements a mapping from desired names (names used directly in the expr code) to names used in the data.
Mnemonic: "expr code symbols are on the left, external data and function argument names are on the right."
let( alias, expr, ..., envir = parent.frame(), subsMethod = "langsubs", strict = TRUE, eval = TRUE, debugPrint = FALSE )
let( alias, expr, ..., envir = parent.frame(), subsMethod = "langsubs", strict = TRUE, eval = TRUE, debugPrint = FALSE )
alias |
mapping from free names in expr to target names to use (mapping have both unique names and unique values). |
expr |
block to prepare for execution. |
... |
force later arguments to be bound by name. |
envir |
environment to work in. |
subsMethod |
character substitution method, one of 'langsubs' (preferred), 'subsubs', or 'stringsubs'. |
strict |
logical if TRUE names and values must be valid un-quoted names, and not dot. |
eval |
logical if TRUE execute the re-mapped expression (else return it). |
debugPrint |
logical if TRUE print debugging information when in stringsubs mode. |
Please see the wrapr
vignette
for some discussion of let and crossing function call boundaries: vignette('wrapr','wrapr')
.
For formal documentation please see https://github.com/WinVector/wrapr/blob/master/extras/wrapr_let.pdf.
Transformation is performed by substitution, so please be wary of unintended name collisions or aliasing.
Something like let
is only useful to get control of a function that is parameterized
(in the sense it take column names) but non-standard (in that it takes column names from
non-standard evaluation argument name capture, and not as simple variables or parameters). So wrapr:let
is not
useful for non-parameterized functions (functions that work only over values such as base::sum
),
and not useful for functions take parameters in straightforward way (such as base::merge
's "by
" argument).
dplyr::mutate
is an example where
we can use a let
helper. dplyr::mutate
is
parameterized (in the sense it can work over user supplied columns and expressions), but column names are captured through non-standard evaluation
(and it rapidly becomes unwieldy to use complex formulas with the standard evaluation equivalent dplyr::mutate_
).
alias
can not include the symbol ".
".
The intent from is from the user perspective to have (if
a <- 1; b <- 2
):
let(c(z = 'a'), z+b)
to behave a lot like
eval(substitute(z+b, c(z=quote(a))))
.
let
deliberately checks that it is mapping only to legal R
names;
this is to discourage the use of let
to make names to arbitrary values, as
that is the more properly left to R
's environment systems.
let
is intended to transform
"tame" variable and column names to "tame" variable and column names. Substitution
outcomes that are not valid simple R
variable names (produced with out use of
back-ticks) are forbidden. It is suggested that substitution targets be written
ALL_CAPS
style to make them stand out.
let
was inspired by gtools:strmacro()
.
Please see https://github.com/WinVector/wrapr/blob/master/extras/MacrosInR.md for a discussion of macro tools in R
.
result of expr executed in calling environment (or expression if eval==FALSE).
d <- data.frame( Sepal_Length=c(5.8,5.7), Sepal_Width=c(4.0,4.4), Species='setosa') mapping <- qc( AREA_COL = Sepal_area, LENGTH_COL = Sepal_Length, WIDTH_COL = Sepal_Width ) # let-block notation let( mapping, d %.>% transform(., AREA_COL = LENGTH_COL * WIDTH_COL) ) # Note: in packages can make assignment such as: # AREA_COL <- LENGTH_COL <- WIDTH_COL <- NULL # prior to code so targets don't look like unbound names.
d <- data.frame( Sepal_Length=c(5.8,5.7), Sepal_Width=c(4.0,4.4), Species='setosa') mapping <- qc( AREA_COL = Sepal_area, LENGTH_COL = Sepal_Length, WIDTH_COL = Sepal_Width ) # let-block notation let( mapping, d %.>% transform(., AREA_COL = LENGTH_COL * WIDTH_COL) ) # Note: in packages can make assignment such as: # AREA_COL <- LENGTH_COL <- WIDTH_COL <- NULL # prior to code so targets don't look like unbound names.
Build an anonymous function.
makeFunction_se(params, body, env = parent.frame())
makeFunction_se(params, body, env = parent.frame())
params |
formal parameters of function, unbound names. |
body |
substituted body of function to map arguments into. |
env |
environment to work in. |
user defined function.
lambda
, defineLambda
, named_map_builder
f <- makeFunction_se(as.name('x'), substitute({x*x})) f(7) g <- makeFunction_se(c(as.name('x'), as.name('y')), substitute({ x + 3*y })) g(1,100)
f <- makeFunction_se(as.name('x'), substitute({x*x})) f(7) g <- makeFunction_se(c(as.name('x'), as.name('y')), substitute({ x + 3*y })) g(1,100)
format a map.
map_to_char(mp, ..., sep = " ", assignment = "=", quote_fn = base::shQuote)
map_to_char(mp, ..., sep = " ", assignment = "=", quote_fn = base::shQuote)
mp |
named vector or list |
... |
not used, foce later arguments to bind by name. |
sep |
separator suffix, what to put after commas |
assignment |
assignment string |
quote_fn |
string quoting function |
character formatted representation
cat(map_to_char(c('a' = 'b', 'c' = 'd'))) cat(map_to_char(c('a' = 'b', 'd', 'e' = 'f'))) cat(map_to_char(c('a' = 'b', 'd' = NA, 'e' = 'f'))) cat(map_to_char(c(1, NA, 2)))
cat(map_to_char(c('a' = 'b', 'c' = 'd'))) cat(map_to_char(c('a' = 'b', 'd', 'e' = 'f'))) cat(map_to_char(c('a' = 'b', 'd' = NA, 'e' = 'f'))) cat(map_to_char(c(1, NA, 2)))
Map up-cased symbol names to referenced values if those values are string scalars (else throw).
map_upper(...)
map_upper(...)
... |
symbol names mapping to string scalars |
map from original symbol names to new names (names found in the current environment)
x <- 'a' print(map_upper(x)) d <- data.frame(a = "a_val") let(map_upper(x), paste(d$X, x))
x <- 'a' print(map_upper(x)) d <- data.frame(a = "a_val") let(map_upper(x), paste(d$X, x))
Map symbol names to referenced values if those values are string scalars (else throw).
mapsyms(...)
mapsyms(...)
... |
symbol names mapping to string scalars |
map from original symbol names to new names (names found in the current environment)
x <- 'a' y <- 'b' print(mapsyms(x, y)) d <- data.frame(a = 1, b = 2) let(mapsyms(x, y), d$x + d$y)
x <- 'a' y <- 'b' print(mapsyms(x, y)) d <- data.frame(a = 1, b = 2) let(mapsyms(x, y), d$x + d$y)
Build a permutation p such that ids1[p] == ids2. See https://win-vector.com/2017/09/02/permutation-theory-in-action/.
match_order(ids1, ids2)
match_order(ids1, ids2)
ids1 |
unique vector of ids. |
ids2 |
unique vector of ids with sort(ids1)==sort(ids2). |
p integers such that ids1[p] == ids2
ids1 <- c(4, 5, 7, 8, 9, 6, 1, 3, 2, 10) ids2 <- c(3, 6, 4, 8, 5, 7, 1, 9,10, 2) p <- match_order(ids1, ids2) ids1[p] all.equal(ids1[p], ids2) # note base::match(ids2, ids1) also solves this problem
ids1 <- c(4, 5, 7, 8, 9, 6, 1, 3, 2, 10) ids2 <- c(3, 6, 4, 8, 5, 7, 1, 9,10, 2) p <- match_order(ids1, ids2) ids1[p] all.equal(ids1[p], ids2) # note base::match(ids2, ids1) also solves this problem
Safely construct a simple Wilkinson notation formula from the outcome (dependent variable) name and vector of input (independent variable) names.
mk_formula( outcome, variables, ..., intercept = TRUE, outcome_target = NULL, outcome_comparator = "==", env = baseenv(), extra_values = NULL, as_character = FALSE )
mk_formula( outcome, variables, ..., intercept = TRUE, outcome_target = NULL, outcome_comparator = "==", env = baseenv(), extra_values = NULL, as_character = FALSE )
outcome |
character scalar, name of outcome or dependent variable. |
variables |
character vector, names of input or independent variables. |
... |
not used, force later arguments to bind by name. |
intercept |
logical, if TRUE allow an intercept term. |
outcome_target |
scalar, if not NULL write outcome==outcome_target in formula. |
outcome_comparator |
one of "==", "!=", ">=", "<=", ">", "<", only use of outcome_target is not NULL. |
env |
environment to use in formula (unless extra_values is non empty, then this is a parent environemnt). |
extra_values |
if not empty extra values to be added to a new formula environment containing env. |
as_character |
if TRUE return formula as a character string. |
Note: outcome and variables
are each intended to be simple variable names or column names (or .). They are not
intended to specify
interactions, I()-terms, transforms, general experessions or other complex formula terms.
Essentially the same effect as reformulate
, but trying to avoid the
paste
currently in reformulate
by calling update.formula
(which appears to work over terms).
Another reasonable way to do this is just paste(outcome, paste(variables, collapse = " + "), sep = " ~ ")
.
Care must be taken with later arguments to functions like lm()
whose help states:
"All of weights, subset and offset are evaluated in the same way as variables in formula, that is first in data and then in the environment of formula."
Also note env
defaults to baseenv()
to try and minimize refence leaks produced by the environemnt
captured by the formal ending up stored in the resulting model for lm()
and glm()
. For
behavior closer to as.formula()
please set the env
argument to parent.frame()
.
a formula object
f <- mk_formula("mpg", c("cyl", "disp")) print(f) (model <- lm(f, mtcars)) format(model$terms) f <- mk_formula("cyl", c("wt", "gear"), outcome_target = 8, outcome_comparator = ">=") print(f) (model <- glm(f, mtcars, family = binomial)) format(model$terms)
f <- mk_formula("mpg", c("cyl", "disp")) print(f) (model <- lm(f, mtcars)) format(model$terms) f <- mk_formula("cyl", c("wt", "gear"), outcome_target = 8, outcome_comparator = ">=") print(f) (model <- glm(f, mtcars, family = binomial)) format(model$terms)
Returns a function f where: f() returns a new temporary name, f(remove=vector) removes names in vector and returns what was removed, f(dumpList=TRUE) returns the list of names generated and clears the list, f(peek=TRUE) returns the list without altering anything.
mk_tmp_name_source( prefix = "tmpnam", ..., alphabet = as.character(0:9), size = 20, sep = "_" )
mk_tmp_name_source( prefix = "tmpnam", ..., alphabet = as.character(0:9), size = 20, sep = "_" )
prefix |
character, string to prefix temp names with. |
... |
force later argument to be bound by name. |
alphabet |
character, characters to choose from in building ids. |
size |
character, number of characters to build id portion of names from. |
sep |
character, separator between temp name fields. |
name generator function.
f <- mk_tmp_name_source('ex') print(f()) nm2 <- f() print(nm2) f(remove=nm2) print(f(dumpList=TRUE))
f <- mk_tmp_name_source('ex') print(f()) nm2 <- f() print(nm2) f(remove=nm2) print(f(dumpList=TRUE))
Set names of right-argument to be left-argument, and return right argument.
Called from :=
operator.
named_map_builder(targets, values) `:=`(targets, values) targets %:=% values
named_map_builder(targets, values) `:=`(targets, values) targets %:=% values
targets |
names to set. |
values |
values to assign to names (and return). |
values with names set.
lambda
, defineLambda
, makeFunction_se
c('a' := '4', 'b' := '5') # equivalent to: c(a = '4', b = '5') c('a', 'b') := c('1', '2') # equivalent to: c(a = '1', b = '2') # the important example name <- 'a' name := '5' # equivalent to: c('a' = '5')
c('a' := '4', 'b' := '5') # equivalent to: c(a = '4', b = '5') c('a', 'b') := c('1', '2') # equivalent to: c(a = '1', b = '2') # the important example name <- 'a' name := '5' # equivalent to: c('a' = '5')
Produce an ordering permutation from a list of vectors. Essentially a non-...
interface to order
.
orderv( columns, ..., na.last = TRUE, decreasing = FALSE, method = c("auto", "shell", "radix") )
orderv( columns, ..., na.last = TRUE, decreasing = FALSE, method = c("auto", "shell", "radix") )
columns |
list of atomic columns to order on, can be a |
... |
not used, force later arguments to bind by name. |
na.last |
(passed to |
decreasing |
(passed to |
method |
(passed to |
ordering permutation
d <- data.frame(x = c(2, 2, 3, 3, 1, 1), y = 6:1) d[order(d$x, d$y), , drop = FALSE] d[orderv(d), , drop = FALSE]
d <- data.frame(x = c(2, 2, 3, 3, 1, 1), y = 6:1) d[order(d$x, d$y), , drop = FALSE] d[orderv(d), , drop = FALSE]
This function packs values given by name into a named list.
pack(..., .wrapr_private_var_env = parent.frame())
pack(..., .wrapr_private_var_env = parent.frame())
... |
values to pack, these should be specified by name (not as constants). |
.wrapr_private_var_env |
environment to evaluate in |
named list of values
x <- 1 y <- 2 pack(x, y) # list(x = 1, y = 2) pack(a = x, y) # list(a = 1, y = 2) pack(a = 5, y) # list(a = 5, y = 2) pack(1, 2) # list('1' = 1, '2' = 2) v <- pack(x = 8, y = 9) # list(x = 8, y = 9) v -> unpack[x, y] print(x) # 8 print(y) # 9
x <- 1 y <- 2 pack(x, y) # list(x = 1, y = 2) pack(a = x, y) # list(a = 1, y = 2) pack(a = 5, y) # list(a = 5, y = 2) pack(1, 2) # list('1' = 1, '2' = 2) v <- pack(x = 8, y = 9) # list(x = 8, y = 9) v -> unpack[x, y] print(x) # 8 print(y) # 9
Memoizing wrapper for parLapplyLB
parLapplyLBm(cl = NULL, X, fun, ..., chunk.size = NULL)
parLapplyLBm(cl = NULL, X, fun, ..., chunk.size = NULL)
cl |
cluster object |
X |
list or vector of inputs |
fun |
function to apply |
... |
additional arguments passed to lapply |
chunk.size |
passed to |
list of results.
parLapplyLB
, lapplym
, VectorizeM
, vapplym
if(requireNamespace("parallel", quietly = TRUE)) { cl <- parallel::makeCluster(2) fs <- function(x) { x <- x[[1]]; Sys.sleep(1); sin(x) } # without memoization should take 1000 seconds lst <- parLapplyLBm(cl, c(rep(0, 1000), rep(1, 1000)), fs) parallel::stopCluster(cl) }
if(requireNamespace("parallel", quietly = TRUE)) { cl <- parallel::makeCluster(2) fs <- function(x) { x <- x[[1]]; Sys.sleep(1); sin(x) } # without memoization should take 1000 seconds lst <- parLapplyLBm(cl, c(rep(0, 1000), rep(1, 1000)), fs) parallel::stopCluster(cl) }
Partition a set of tables into a list of sets of tables. Note: removes rownames.
partition_tables( tables_used, partition_column, ..., source_usage = NULL, source_limit = NULL, tables = NULL, env = NULL )
partition_tables( tables_used, partition_column, ..., source_usage = NULL, source_limit = NULL, tables = NULL, env = NULL )
tables_used |
character, names of tables to look for. |
partition_column |
character, name of column to partition by (tables should not have NAs in this column). |
... |
force later arguments to bind by name. |
source_usage |
optional named map from tables_used names to sets of columns used. |
source_limit |
optional numeric scalar limit on rows wanted every source. |
tables |
named map from tables_used names to data.frames. |
env |
environment to also look for tables named by tables_used |
list of names maps of data.frames partitioned by partition_column.
d1 <- data.frame(a = 1:5, g = c(1, 1, 2, 2, 2)) d2 <- data.frame(x = 1:3, g = 1:3) d3 <- data.frame(y = 1) partition_tables(c("d1", "d2", "d3"), "g", tables = list(d1 = d1, d2 = d2, d3 = d3))
d1 <- data.frame(a = 1:5, g = c(1, 1, 2, 2, 2)) d2 <- data.frame(x = 1:3, g = 1:3) d3 <- data.frame(y = 1) partition_tables(c("d1", "d2", "d3"), "g", tables = list(d1 = d1, d2 = d2, d3 = d3))
This is a helper for implementing additional pipes.
pipe_impl(pipe_left_arg, pipe_right_arg, pipe_environment, pipe_string = NULL)
pipe_impl(pipe_left_arg, pipe_right_arg, pipe_environment, pipe_string = NULL)
pipe_left_arg |
possibily unevaluated left argument. |
pipe_right_arg |
possibly unevaluated right argument. |
pipe_environment |
environment to evaluate in. |
pipe_string |
character, name of pipe operator. |
result
# Example: how wrapr pipe is implemented print(`%.>%`) # Example: create a value that causes pipelines to record steps. # inject raw values into wrapped/annotated world unit_recording <- function(x, recording = paste(as.expression(substitute(x)), collapse = '\n')) { res <- list(value = x, recording = recording) class(res) <- "recording_value" res } # similar to bind or >>= # (takes U, f:U -> V to M(f(U)), instead of # U, f:U -> M(V) to M(f(U))) # so similar to a functor taking # f:U -> V to f':M(U) -> M(V) # followed by application. apply_left.recording_value <- function( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { force(pipe_environment) tmp <- wrapr::pipe_impl( pipe_left_arg = pipe_left_arg$value, pipe_right_arg = pipe_right_arg, pipe_environment = pipe_environment, pipe_string = pipe_string) unit_recording( tmp, paste0(pipe_left_arg$recording, ' %.>% ', paste(as.expression(pipe_right_arg), collapse = '\n'))) } # make available on standard S3 search path assign('apply_left.recording_value', apply_left.recording_value, envir = .GlobalEnv) unpack[value, recording] := 3 %.>% unit_recording(.) %.>% sin(.) %.>% cos(.) print(value) print(recording) # clean up rm(envir = .GlobalEnv, list = 'apply_left.recording_value')
# Example: how wrapr pipe is implemented print(`%.>%`) # Example: create a value that causes pipelines to record steps. # inject raw values into wrapped/annotated world unit_recording <- function(x, recording = paste(as.expression(substitute(x)), collapse = '\n')) { res <- list(value = x, recording = recording) class(res) <- "recording_value" res } # similar to bind or >>= # (takes U, f:U -> V to M(f(U)), instead of # U, f:U -> M(V) to M(f(U))) # so similar to a functor taking # f:U -> V to f':M(U) -> M(V) # followed by application. apply_left.recording_value <- function( pipe_left_arg, pipe_right_arg, pipe_environment, left_arg_name, pipe_string, right_arg_name) { force(pipe_environment) tmp <- wrapr::pipe_impl( pipe_left_arg = pipe_left_arg$value, pipe_right_arg = pipe_right_arg, pipe_environment = pipe_environment, pipe_string = pipe_string) unit_recording( tmp, paste0(pipe_left_arg$recording, ' %.>% ', paste(as.expression(pipe_right_arg), collapse = '\n'))) } # make available on standard S3 search path assign('apply_left.recording_value', apply_left.recording_value, envir = .GlobalEnv) unpack[value, recording] := 3 %.>% unit_recording(.) %.>% sin(.) %.>% cos(.) print(value) print(recording) # clean up rm(envir = .GlobalEnv, list = 'apply_left.recording_value')
Take a vector or list and return the first element (pseudo-aggregation or projection). If the argument length is zero or there are different items throw in an error.
psagg(x, ..., strict = TRUE)
psagg(x, ..., strict = TRUE)
x |
should be a vector or list of items. |
... |
force later arguments to be passed by name |
strict |
logical, should we check value uniqueness. |
This function is useful in some split by column situations as a safe and legible way to convert vectors to scalars.
x[[1]] (or throw if not all items are equal or this is an empty vector).
d <- data.frame( group = c("a", "a", "b"), stringsAsFactors = FALSE) dl <- lapply( split(d, d$group), function(di) { data.frame( # note: di$group is a possibly length>1 vector! # pseudo aggregate it to the value that is # constant for each group, confirming it is constant. group_label = psagg(di$group), group_count = nrow(di), stringsAsFactors = FALSE ) }) do.call(rbind, dl)
d <- data.frame( group = c("a", "a", "b"), stringsAsFactors = FALSE) dl <- lapply( split(d, d$group), function(di) { data.frame( # note: di$group is a possibly length>1 vector! # pseudo aggregate it to the value that is # constant for each group, confirming it is constant. group_label = psagg(di$group), group_count = nrow(di), stringsAsFactors = FALSE ) }) do.call(rbind, dl)
Accepts arbitrary un-parsed expressions as assignments to allow forms such as "Sepal_Long := Sepal.Length >= 2 * Sepal.Width". (without the quotes). Terms are expressions of the form "lhs := rhs", "lhs = rhs", "lhs %:=% rhs".
qae(...)
qae(...)
... |
assignment expressions. |
qae()
uses
bquote()
.()
quasiquotation escaping notation,
and .(-)
"string quotes, string to name" notation.
array of quoted assignment expressions.
ratio <- 2 exprs <- qae(Sepal_Long := Sepal.Length >= ratio * Sepal.Width, Petal_Short = Petal.Length <= 3.5) print(exprs) exprs <- qae(Sepal_Long := Sepal.Length >= .(ratio) * Sepal.Width, Petal_Short = Petal.Length <= 3.5) print(exprs) # library("rqdatatable") # datasets::iris %.>% # extend_se(., exprs) %.>% # summary(.)
ratio <- 2 exprs <- qae(Sepal_Long := Sepal.Length >= ratio * Sepal.Width, Petal_Short = Petal.Length <= 3.5) print(exprs) exprs <- qae(Sepal_Long := Sepal.Length >= .(ratio) * Sepal.Width, Petal_Short = Petal.Length <= 3.5) print(exprs) # library("rqdatatable") # datasets::iris %.>% # extend_se(., exprs) %.>% # summary(.)
The qc() function is intended to help quote user inputs.
qc(..., .wrapr_private_var_env = parent.frame())
qc(..., .wrapr_private_var_env = parent.frame())
... |
items to place into an array |
.wrapr_private_var_env |
environment to evaluate in |
qc() a convenience function allowing the user to elide excess quotation marks. It quotes its arguments instead of evaluating them, except in the case of a nested call to qc() or c(). Please see the examples for typical uses both for named and un-named character vectors.
qc() uses bquote() .() quasiquotation escaping notation. Also take care: argumetns are parsed by R before being passed to qc(). This means 01 is interpreted as 1 and a string such as 0z1 is a syntax error. Some notes on this can be found here: https://github.com/WinVector/wrapr/issues/15#issuecomment-962092462
quoted array of character items
a <- "x" qc(a) # returns the string "a" (not "x") qc(.(a)) # returns the string "x" (not "a") qc(.(a) := a) # returns c("x" = "a") qc("a") # return the string "a" (not "\"a\"") qc(sin(x)) # returns the string "sin(x)" qc(a, qc(b, c)) # returns c("a", "b", "c") qc(a, c("b", "c")) # returns c("a", "b", "c") qc(x=a, qc(y=b, z=c)) # returns c(x="a", y="b", z="c") qc('x'='a', wrapr::qc('y'='b', 'z'='c')) # returns c(x="a", y="b", z="c") c(a = c(a="1", b="2")) # returns c(a.a = "1", a.b = "2") qc(a = c(a=1, b=2)) # returns c(a.a = "1", a.b = "2") qc(a := c(a=1, b=2)) # returns c(a.a = "1", a.b = "2")
a <- "x" qc(a) # returns the string "a" (not "x") qc(.(a)) # returns the string "x" (not "a") qc(.(a) := a) # returns c("x" = "a") qc("a") # return the string "a" (not "\"a\"") qc(sin(x)) # returns the string "sin(x)" qc(a, qc(b, c)) # returns c("a", "b", "c") qc(a, c("b", "c")) # returns c("a", "b", "c") qc(x=a, qc(y=b, z=c)) # returns c(x="a", y="b", z="c") qc('x'='a', wrapr::qc('y'='b', 'z'='c')) # returns c(x="a", y="b", z="c") c(a = c(a="1", b="2")) # returns c(a.a = "1", a.b = "2") qc(a = c(a=1, b=2)) # returns c(a.a = "1", a.b = "2") qc(a := c(a=1, b=2)) # returns c(a.a = "1", a.b = "2")
A convenient way to build a character data.frame in legible transposed form. Position of first "|" (or other infix operator) determines number of columns (all other infix operators are aliases for ","). Names are treated as character types.
qchar_frame(...)
qchar_frame(...)
... |
cell names, first infix operator denotes end of header row of column names. |
qchar_frame() uses bquote() .() quasiquotation escaping notation. Because of this using dot as a name in some places may fail if the dot looks like a function call.
character data.frame
loss_name <- "loss" x <- qchar_frame( measure, training, validation | "minus binary cross entropy", .(loss_name), val_loss | accuracy, acc, val_acc ) print(x) str(x) cat(draw_frame(x)) qchar_frame( x | 1 | 2 ) %.>% str(.)
loss_name <- "loss" x <- qchar_frame( measure, training, validation | "minus binary cross entropy", .(loss_name), val_loss | accuracy, acc, val_acc ) print(x) str(x) cat(draw_frame(x)) qchar_frame( x | 1 | 2 ) %.>% str(.)
Accepts arbitrary un-parsed expressions as to allow forms such as "Sepal.Length >= 2 * Sepal.Width". (without the quotes).
qe(...)
qe(...)
... |
assignment expressions. |
qe()
uses
bquote()
.()
quasiquotation escaping notation,
and .(-)
"string quotes, string to name" notation.
array of quoted assignment expressions.
ratio <- 2 exprs <- qe(Sepal.Length >= ratio * Sepal.Width, Petal.Length <= 3.5) print(exprs) exprs <- qe(Sepal.Length >= .(ratio) * Sepal.Width, Petal.Length <= 3.5) print(exprs)
ratio <- 2 exprs <- qe(Sepal.Length >= ratio * Sepal.Width, Petal.Length <= 3.5) print(exprs) exprs <- qe(Sepal.Length >= .(ratio) * Sepal.Width, Petal.Length <= 3.5) print(exprs)
qs() uses bquote() .() quasiquotation escaping notation.
qs(s)
qs(s)
s |
expression to be quoted as a string. |
character
x <- 7 qs(a == x) qs(a == .(x))
x <- 7 qs(a == x) qs(a == .(x))
x %.|% f
stands for f(x[[1]], x[[2]], ..., x[[length(x)]])
.
v %|.% x
also stands for f(x[[1]], x[[2]], ..., x[[length(x)]])
.
The two operators are the same, the variation just allowing the user to choose the order they write things.
The mnemonic is: "data goes on the dot-side of the operator."
f %|.% args args %.|% f
f %|.% args args %.|% f
f |
function. |
args |
argument list or vector, entries expanded as function arguments. |
Note: the reduce operation is implemented by do.call()
, so has
standard R named argument semantics.
f(args) where args elements become individual arguments of f.
f %|.% args
: f reduce args
args %.|% f
: args expand f
args <- list('prefix_', c(1:3), '_suffix') args %.|% paste0 # prefix_1_suffix" "prefix_2_suffix" "prefix_3_suffix" paste0 %|.% args # prefix_1_suffix" "prefix_2_suffix" "prefix_3_suffix"
args <- list('prefix_', c(1:3), '_suffix') args %.|% paste0 # prefix_1_suffix" "prefix_2_suffix" "prefix_3_suffix" paste0 %|.% args # prefix_1_suffix" "prefix_2_suffix" "prefix_3_suffix"
Restrict an alias mapping list to things that look like name assignments
restrictToNameAssignments(alias, restrictToAllCaps = FALSE)
restrictToNameAssignments(alias, restrictToAllCaps = FALSE)
alias |
mapping list |
restrictToAllCaps |
logical, if true only use all-capitalized keys |
string to string mapping
alias <- list(region= 'east', str= "'seven'") aliasR <- restrictToNameAssignments(alias) print(aliasR)
alias <- list(region= 'east', str= "'seven'") aliasR <- restrictToNameAssignments(alias) print(aliasR)
Return an in increaing whole-number sequence from a to b inclusive (return integer(0) if none such). Allows for safe iteraton.
seqi(a, b)
seqi(a, b)
a |
scalar lower bound |
b |
scalar upper bound |
whole number sequence
# print 3, 4, and then 5 for(i in seqi(3, 5)) { print(i) } # empty for(i in seqi(5, 2)) { print(i) }
# print 3, 4, and then 5 for(i in seqi(3, 5)) { print(i) } # empty for(i in seqi(5, 2)) { print(i) }
String interpolation using bquote
-stype .() notation. Pure R, no C/C++ code called.
sinterp
and si
are synonyms.
si( str, ..., envir = parent.frame(), enclos = parent.frame(), match_pattern = "\\.\\((([^()]+)|(\\([^()]*\\)))+\\)", removal_patterns = c("^\\.\\(", "\\)$") )
si( str, ..., envir = parent.frame(), enclos = parent.frame(), match_pattern = "\\.\\((([^()]+)|(\\([^()]*\\)))+\\)", removal_patterns = c("^\\.\\(", "\\)$") )
str |
charater string to be substituted into |
... |
force later arguments to bind by name |
envir |
environemnt to look for values |
enclos |
enclosing evaluation environment |
match_pattern |
regexp to find substitution targets. |
removal_patterns |
regexps to remove markers from substitution targets. |
See also https://CRAN.R-project.org/package=R.utils, https://CRAN.R-project.org/package=rprintf, and https://CRAN.R-project.org/package=glue.
modified strings
x <- 7 si("x is .(x), x+1 is .(x+1)\n.(x) is odd is .(x%%2 == 1)") # Because matching is done by a regular expression we # can not use arbitrary depths of nested parenthesis inside # the interpolation region. The default regexp allows # one level of nesting (and one can use {} in place # of parens in many places). si("sin(x*(x+1)) is .(sin(x*{x+1}))") # We can also change the delimiters, # in this case to !! through the first whitespace. si(c("x is !!x , x+1 is !!x+1 \n!!x is odd is !!x%%2==1"), match_pattern = '!![^[:space:]]+[[:space:]]?', removal_patterns = c("^!!", "[[:space:]]?$"))
x <- 7 si("x is .(x), x+1 is .(x+1)\n.(x) is odd is .(x%%2 == 1)") # Because matching is done by a regular expression we # can not use arbitrary depths of nested parenthesis inside # the interpolation region. The default regexp allows # one level of nesting (and one can use {} in place # of parens in many places). si("sin(x*(x+1)) is .(sin(x*{x+1}))") # We can also change the delimiters, # in this case to !! through the first whitespace. si(c("x is !!x , x+1 is !!x+1 \n!!x is odd is !!x%%2==1"), match_pattern = '!![^[:space:]]+[[:space:]]?', removal_patterns = c("^!!", "[[:space:]]?$"))
String interpolation using bquote
-stype .() notation. Pure R, no C/C++ code called.
sinterp( str, ..., envir = parent.frame(), enclos = parent.frame(), match_pattern = "\\.\\((([^()]+)|(\\([^()]*\\)))+\\)", removal_patterns = c("^\\.\\(", "\\)$") )
sinterp( str, ..., envir = parent.frame(), enclos = parent.frame(), match_pattern = "\\.\\((([^()]+)|(\\([^()]*\\)))+\\)", removal_patterns = c("^\\.\\(", "\\)$") )
str |
charater string(s) to be substituted into |
... |
force later arguments to bind by name |
envir |
environemnt to look for values |
enclos |
enclosing evaluation environment |
match_pattern |
regexp to find substitution targets. |
removal_patterns |
regexps to remove markers from substitution targets. |
See also https://CRAN.R-project.org/package=R.utils, https://CRAN.R-project.org/package=rprintf, and https://CRAN.R-project.org/package=glue.
modified strings
x <- 7 sinterp("x is .(x), x+1 is .(x+1)\n.(x) is odd is .(x%%2 == 1)") # Because matching is done by a regular expression we # can not use arbitrary depths of nested parenthesis inside # the interpolation region. The default regexp allows # one level of nesting (and one can use {} in place # of parens in many places). sinterp("sin(x*(x+1)) is .(sin(x*{x+1}))") # We can also change the delimiters, # in this case to !! through the first whitespace. sinterp(c("x is !!x , x+1 is !!x+1 \n!!x is odd is !!x%%2==1"), match_pattern = '!![^[:space:]]+[[:space:]]?', removal_patterns = c("^!!", "[[:space:]]?$"))
x <- 7 sinterp("x is .(x), x+1 is .(x+1)\n.(x) is odd is .(x%%2 == 1)") # Because matching is done by a regular expression we # can not use arbitrary depths of nested parenthesis inside # the interpolation region. The default regexp allows # one level of nesting (and one can use {} in place # of parens in many places). sinterp("sin(x*(x+1)) is .(sin(x*{x+1}))") # We can also change the delimiters, # in this case to !! through the first whitespace. sinterp(c("x is !!x , x+1 is !!x+1 \n!!x is odd is !!x%%2==1"), match_pattern = '!![^[:space:]]+[[:space:]]?', removal_patterns = c("^!!", "[[:space:]]?$"))
Sort a data.frame by a set of columns.
sortv( data, colnames, ..., na.last = TRUE, decreasing = FALSE, method = c("auto", "shell", "radix") )
sortv( data, colnames, ..., na.last = TRUE, decreasing = FALSE, method = c("auto", "shell", "radix") )
data |
data.frame to sort. |
colnames |
column names to sort on. |
... |
not used, force later arguments to bind by name. |
na.last |
(passed to |
decreasing |
(passed to |
method |
(passed to |
ordering permutation
d <- data.frame(x = c(2, 2, 3, 3, 1, 1), y = 6:1) sortv(d, c("x", "y"))
d <- data.frame(x = c(2, 2, 3, 3, 1, 1), y = 6:1) sortv(d, c("x", "y"))
Split strings at -pairs.
split_at_brace_pairs(s, open_symbol = "{", close_symbol = "}")
split_at_brace_pairs(s, open_symbol = "{", close_symbol = "}")
s |
string or list of strings to split. |
open_symbol |
symbol to start marking. |
close_symbol |
symbol to end marking. |
array or list of split strings.
split_at_brace_pairs("{x} + y + {z}")
split_at_brace_pairs("{x} + y + {z}")
Generate a stop with a good error message if the dots argument was a non-trivial list. Useful in writing functions that force named arguments.
stop_if_dot_args(dot_args, msg = "")
stop_if_dot_args(dot_args, msg = "")
dot_args |
substitute(list(...)) from another function. |
msg |
character, optional message to prepend. |
NULL or stop()
f <- function(x, ..., inc = 1) { stop_if_dot_args(substitute(list(...)), "f") x + inc } f(7) f(7, inc = 2) tryCatch( f(7, 2), error = function(e) { print(e) } )
f <- function(x, ..., inc = 1) { stop_if_dot_args(substitute(list(...)), "f") x + inc } f(7) f(7, inc = 2) tryCatch( f(7, 2), error = function(e) { print(e) } )
Split a string, keeping separator regions
strsplit_capture( x, split, ..., ignore.case = FALSE, fixed = FALSE, perl = FALSE, useBytes = FALSE )
strsplit_capture( x, split, ..., ignore.case = FALSE, fixed = FALSE, perl = FALSE, useBytes = FALSE )
x |
character string to split (length 1 vector) |
split |
split pattern |
... |
force later arguments to bind by name |
ignore.case |
passed to |
fixed |
passed to |
perl |
passed to |
useBytes |
passed to |
list of string segments annotated with is_sep.
strsplit_capture("x is .(x) and x+1 is .(x+1)", "\\.\\([^()]+\\)")
strsplit_capture("x is .(x) and x+1 is .(x+1)", "\\.\\([^()]+\\)")
Separates string data on whitespace and separating symbols into an array.
sx(s, ..., sep_symbols = ",|", strict = TRUE)
sx(s, ..., sep_symbols = ",|", strict = TRUE)
s |
string to parse |
... |
force later arguments to be set by name |
sep_symbols |
characters to consider separators |
strict |
logical, if TRUE throw exception on confusing input |
Can throw exception on lack of explicit value separators, example: bc('"a""b"')
and non-matching portions.
Whitespace is normalized to spaces.
Suggested by Emil Erik Pula Bellamy Begtrup-Bright https://github.com/WinVector/wrapr/issues/15.
vector of values
sx('1 2 "c", d') # returns c("1", "2", "c", "d") sx('1 2 3') # returns c("1", "2", "3") sx('1 2 "3"') # returns c("1", "2", "3") sx('1,2|3.4') # returns c("1", "2", "3.4") sx('01 02') # returns c("01", "02")
sx('1 2 "c", d') # returns c("1", "2", "c", "d") sx('1 2 3') # returns c("1", "2", "3") sx('1 2 "3"') # returns c("1", "2", "3") sx('1,2|3.4') # returns c("1", "2", "3.4") sx('01 02') # returns c("01", "02")
Unpacks or binds values into the calling environment, eager eval (no-dot) variation. Uses bquote
escaping.
NULL is a special case that is unpacked to all targets. NA targets are skipped.
All non-NA target names must be unique.
to(...)
to(...)
... |
argument names to write to |
Note: when using []<-
notation, a reference to the unpacker object is written into the unpacking environment as a side-effect
of the implied array assignment. :=
assigment does not have this side-effect.
Array-assign form can not use the names: .
, wrapr_private_self
, value
, or to
.
function form can not use the names: .
or wrapr_private_value
.
For more detials please see here https://win-vector.com/2020/01/20/unpack-your-values-in-r/.
Related work includes Python
tuple unpacking, zeallot
's arrow, and vadr::bind
.
a UnpackTarget
# named unpacking # looks like assignment: DESTINATION = NAME_VALUE_USING d <- data.frame(x = 1:2, g=c('test', 'train'), stringsAsFactors = FALSE) to[train_set = train, test_set = test] := split(d, d$g) # train_set and test_set now correctly split print(train_set) print(test_set) rm(list = c('train_set', 'test_set')) # named unpacking NEWNAME = OLDNAME implicit form # values are matched by name, not index to[train, test] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test')) # pipe version (notice no dot) split(d, d$g) %.>% to(train, test) print(train) print(test) rm(list = c('train', 'test')) # Note: above is wrapr dot-pipe, piping does not currently work with # magrittr pipe due to magrittr's introduction of temporary # intermediate environments during evaluation. # bquote example train_col_name <- 'train' test_col_name <- 'test' to[train = .(train_col_name), test = .(test_col_name)] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test'))
# named unpacking # looks like assignment: DESTINATION = NAME_VALUE_USING d <- data.frame(x = 1:2, g=c('test', 'train'), stringsAsFactors = FALSE) to[train_set = train, test_set = test] := split(d, d$g) # train_set and test_set now correctly split print(train_set) print(test_set) rm(list = c('train_set', 'test_set')) # named unpacking NEWNAME = OLDNAME implicit form # values are matched by name, not index to[train, test] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test')) # pipe version (notice no dot) split(d, d$g) %.>% to(train, test) print(train) print(test) rm(list = c('train', 'test')) # Note: above is wrapr dot-pipe, piping does not currently work with # magrittr pipe due to magrittr's introduction of temporary # intermediate environments during evaluation. # bquote example train_col_name <- 'train' test_col_name <- 'test' to[train = .(train_col_name), test = .(test_col_name)] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test'))
Check that ...
is empty and if so call
base::unique(x, incomparables = incomparables, MARGIN = MARGIN, fromLast = fromLast)
(else throw an error)
uniques(x, ..., incomparables = FALSE, MARGIN = 1, fromLast = FALSE)
uniques(x, ..., incomparables = FALSE, MARGIN = 1, fromLast = FALSE)
x |
items to be compared. |
... |
not used, checked to be empty to prevent errors. |
incomparables |
passed to base::unique. |
MARGIN |
passed to base::unique. |
fromLast |
passed to base::unique. |
base::unique(x, incomparables = incomparables, MARGIN = MARGIN, fromLast = fromLast)
x = c("a", "b") y = c("b", "c") # task: get unique items in x plus y unique(c(x, y)) # correct answer unique(x, y) # oops forgot to wrap arguments, quietly get wrong answer tryCatch( uniques(x, y), # uniques catches the error error = function(e) { e }) uniques(c(x, y)) # uniques works like base::unique in most case
x = c("a", "b") y = c("b", "c") # task: get unique items in x plus y unique(c(x, y)) # correct answer unique(x, y) # oops forgot to wrap arguments, quietly get wrong answer tryCatch( uniques(x, y), # uniques catches the error error = function(e) { e }) uniques(c(x, y)) # uniques works like base::unique in most case
Unpacks or binds values into the calling environment. Uses bquote
escaping.
NULL is a special case that is unpacked to all targets. NA targets are skipped.
All non-NA target names must be unique.
unpack(wrapr_private_value, ...)
unpack(wrapr_private_value, ...)
wrapr_private_value |
list of values to copy |
... |
argument names to write to |
Note: when using []<-
notation, a reference to the unpacker object is written into the unpacking environment as a side-effect
of the implied array assignment. :=
assigment does not have this side-effect.
Array-assign form can not use the names: .
, wrapr_private_self
, value
, or unpack
.
Function form can not use the names: .
or wrapr_private_value
.
For more details please see here https://win-vector.com/2020/01/20/unpack-your-values-in-r/.
Related work includes Python
tuple unpacking, zeallot
's arrow, and vadr::bind
.
value passed in (invisible)
# named unpacking # looks like assignment: DESTINATION = NAME_VALUE_USING d <- data.frame(x = 1:2, g=c('test', 'train'), stringsAsFactors = FALSE) unpack[train_set = train, test_set = test] := split(d, d$g) # train_set and test_set now correctly split print(train_set) print(test_set) rm(list = c('train_set', 'test_set')) # named unpacking NEWNAME = OLDNAME implicit form # values are matched by name, not index unpack[train, test] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test')) # function version unpack(split(d, d$g), train, test) print(train) print(test) rm(list = c('train', 'test')) # pipe version split(d, d$g) %.>% unpack(., train, test) print(train) print(test) rm(list = c('train', 'test')) # Note: above is wrapr dot-pipe, piping does not currently work with # magrittr pipe due to magrittr's introduction of temporary # intermediate environments during evaluation. # bquote example train_col_name <- 'train' test_col_name <- 'test' unpack(split(d, d$g), train = .(train_col_name), test = .(test_col_name)) print(train) print(test) rm(list = c('train', 'test'))
# named unpacking # looks like assignment: DESTINATION = NAME_VALUE_USING d <- data.frame(x = 1:2, g=c('test', 'train'), stringsAsFactors = FALSE) unpack[train_set = train, test_set = test] := split(d, d$g) # train_set and test_set now correctly split print(train_set) print(test_set) rm(list = c('train_set', 'test_set')) # named unpacking NEWNAME = OLDNAME implicit form # values are matched by name, not index unpack[train, test] := split(d, d$g) print(train) print(test) rm(list = c('train', 'test')) # function version unpack(split(d, d$g), train, test) print(train) print(test) rm(list = c('train', 'test')) # pipe version split(d, d$g) %.>% unpack(., train, test) print(train) print(test) rm(list = c('train', 'test')) # Note: above is wrapr dot-pipe, piping does not currently work with # magrittr pipe due to magrittr's introduction of temporary # intermediate environments during evaluation. # bquote example train_col_name <- 'train' test_col_name <- 'test' unpack(split(d, d$g), train = .(train_col_name), test = .(test_col_name)) print(train) print(test) rm(list = c('train', 'test'))
Memoizing wrapper for vapply.
vapplym(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)
vapplym(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)
X |
list or vector of inputs |
FUN |
function to apply |
FUN.VALUE |
type of vector to return |
... |
additional arguments passed to lapply |
USE.NAMES |
passed to vapply |
vector of results.
fs <- function(x) { x <- x[[1]]; print(paste("see", x)); sin(x) } # should only print "see" twice, not 6 times vapplym(c(0, 1, 1, 0, 0, 1), fs, numeric(1))
fs <- function(x) { x <- x[[1]]; print(paste("see", x)); sin(x) } # should only print "see" twice, not 6 times vapplym(c(0, 1, 1, 0, 0, 1), fs, numeric(1))
Build a wrapped function that applies to each unique argument in a vector of arguments once.
VectorizeM( FUN, vectorize.args = arg.names, SIMPLIFY = TRUE, USE.NAMES = TRUE, UNLIST = FALSE )
VectorizeM( FUN, vectorize.args = arg.names, SIMPLIFY = TRUE, USE.NAMES = TRUE, UNLIST = FALSE )
FUN |
function to apply |
vectorize.args |
a character vector of arguments which should be vectorized. Defaults to first argument of FUN. If set must be length 1. |
SIMPLIFY |
logical or character string; attempt to reduce the result to a vector, matrix or higher dimensional array; see the simplify argument of sapply. |
USE.NAMES |
logical; use names if the first ... argument has names, or if it is a character vector, use that character vector as the names. |
UNLIST |
logical; if TRUE try to unlist the result. |
Only sensible for pure side-effect free deterministic functions.
adapted function (vectorized with one call per different value).
fs <- function(x) { x <- x[[1]]; print(paste("see", x)); sin(x) } fv <- VectorizeM(fs) # should only print "see" twice, not 6 times fv(c(0, 1, 1, 0, 0, 1))
fs <- function(x) { x <- x[[1]]; print(paste("see", x)); sin(x) } fv <- VectorizeM(fs) # should only print "see" twice, not 6 times fv(c(0, 1, 1, 0, 0, 1))
Invoke a spreadsheet like viewer when appropriate.
view(x, ..., title = wrapr_deparse(substitute(x)), n = 200)
view(x, ..., title = wrapr_deparse(substitute(x)), n = 200)
x |
R object to view |
... |
force later arguments to bind by name. |
title |
title for viewer |
n |
number of rows to show |
invoke view or format object
view(mtcars)
view(mtcars)