[R] Why does debugging print() change output of function?
William Dunlap
wdunlap at tibco.com
Sun Sep 7 01:24:47 CEST 2014
In your first example I get an error:
> mtest.data.frame(testdata, valid2=="N", valid3 > 1)
Error in mtest.data.frame(testdata, valid2 == "N", valid3 > 1) :
object 'valid2' not found
I expect the error because list(...) ought to evaluate the ... arguments.
Use substitute() to get the unevaluated ... arguments up front and
don't use substitute() in the loop over the elements of test.
There are several ways to get the unevaluated ... arguments. E.g.,
f0 <- function(x, ..., drop=FALSE) match.call(expand.dots=FALSE)$...
f1 <- function(x, ..., drop=FALSE) substitute(...())
f2 <- function(x, ..., drop=FALSE) as.list(substitute(list(...)))[-1]
Your function could be the following, where I also fixed a problem
with parent.frame() being
called in the wrong scope and improved, IMO, the names on the output data.frame.
m2 <- function (x, ..., drop = FALSE, verbose = FALSE)
{
tests <- substitute(...())
nms <- names(tests) # fix up names, since data.frame makes ugly ones
if (is.null(nms)) {
names(tests) <- paste0("T", seq_along(tests))
}
else if (any(nms == "")) {
names(tests)[nms == ""] <- paste0("T", which(nms == ""))
}
if (verbose) {
print(tests)
}
r <- if (length(tests) == 0) {
stop("no 'tests'")
}
else {
enclos <- parent.frame() # evaluate parent.frame() outside of FUN()
data.frame(lapply(tests, FUN=function(e) {
r <- eval(e, x, enclos)
if (!is.logical(r)) {
stop("'tests' must be logical")
}
r & !is.na(r)
}))
}
r
}
used as:
> m2(testdata, group2=="UNC", Eleven.Two=valid5=="11.2")
T1 Eleven.Two
1 TRUE FALSE
2 TRUE TRUE
3 FALSE FALSE
4 FALSE FALSE
5 FALSE FALSE
6 FALSE FALSE
7 TRUE FALSE
Bill Dunlap
TIBCO Software
wdunlap tibco.com
On Sat, Sep 6, 2014 at 3:31 PM, David Winsemius <dwinsemius at comcast.net> wrote:
> The goal:
> to create a function modeled after `subset` (notorious for its non-standard evaluation) that will take a series of logical tests as unqiuoted expressions to be evaluated in the framework of a dataframe environment and return a dataframe of logicals:
>
>
> mtest.data.frame <-
> function (x, ..., drop=FALSE)
> { tests <- list(...); print(tests)
> r <- if (length(tests)==0)
> stop("no 'tests'")
> else { cbind.data.frame(
> lapply( tests, function(t){
> e <- substitute(t)
> r <- eval(e, x, parent.frame() )
> if ( !is.logical(r) ) {
> stop("'tests' must be logical") }
> r & !is.na(r) } ) )
> }
> }
> #--------------
>
> testdata <- structure(list(group1 = structure(1:7, .Label = c("Group A",
> "Group B", "Group C", "Group D", "Group E", "Group F", "Group G"
> ), class = "factor"), group2 = structure(c(3L, 3L, 2L, 1L, 1L,
> 2L, 3L), .Label = c("LS", "SS", "UNC"), class = "factor"), valid1 = structure(c(2L,
> 1L, NA, 1L, 2L, 2L, 1L), .Label = c("N", "Y"), class = "factor"),
> valid2 = structure(c(1L, 1L, 2L, 1L, 1L, 2L, 1L), .Label = c("N",
> "Y"), class = "factor"), valid3 = structure(c(4L, 3L, NA,
> 2L, 1L, NA, 5L), .Label = c("0.3", "0.7", "1.2", "1.4", "1.7"
> ), class = "factor"), valid4 = structure(c(2L, 1L, 3L, 4L,
> 1L, 1L, 5L), .Label = c("0.3", "0.4", "0.53", "0.66", "0.71"
> ), class = "factor"), valid5 = structure(c(4L, 1L, NA, NA,
> 3L, NA, 2L), .Label = c("11.2", "11.7", "8.3", "8.5"), class = "factor")), .Names = c("group1",
> "group2", "valid1", "valid2", "valid3", "valid4", "valid5"), row.names = c(NA,
> -7L), class = "data.frame")
>
> #######
>
>
>> mtest.data.frame(testdata, valid2=="N", valid3 > 1)
> [[1]]
> [1] "tests are"
>
> [[2]]
> [1] TRUE TRUE FALSE TRUE TRUE FALSE TRUE
>
> [[3]]
> [1] TRUE TRUE NA FALSE FALSE NA TRUE
>
> This actually seemed to be somewhat successful, but when ...
>
> Now if I take out the `print()` call for 'tests', I get an different answer:
>
>> mtest.data.frame <-
> + function (x, ..., drop=FALSE)
> + { tests <- list(...)
> + r <- if (length(tests)==0)
> + stop("no 'tests'")
> + else { cbind.data.frame(
> + lapply( tests, function(t){
> + e <- substitute(t)
> + r <- eval(e, x, parent.frame() )
> + if ( !is.logical(r) ) {
> + stop("'tests' must be logical") }
> + r & !is.na(r) } ) )
> + }
> + }
>> mtest.data.frame(testdata, valid2=="N", valid3 > 1)
>> # i.e. no answer
>
> --
>
> David Winsemius
> Alameda, CA, USA
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
More information about the R-help
mailing list