R refClass Methods - r

I am using R refClass example below.
Person = setRefClass("Person",fields = list(name = "character", age = "numeric")
) ## Person = setRefClass("Person",
Person$methods = list(
increaseAge <- function(howMuch){
age = age + howMuch
}
)
When I store this program in a file called Person.R and source it, it does not show any errors. Now I instantiate a new object.
p = new("Person",name="sachin",age=40)
And I try to invoke the method increaseAge, using p$increaseAge(40), and it shows the following error
Error in envRefInferField(x, what, getClass(class(x)), selfEnv) :
"increaseAge" is not a valid field or method name for reference class "Person"
I cannot figure out why it says that the method increaseAge is not a valid method name when I have defined it.

To specify a method independent of class definition, invoke the methods() function on the generator. Also, use either <<- or .self$age = for the assignment.
Person$methods(increaseAge=function(howMuch) {
age <<- age + howMuch
## alterenatively, .self$age = age + howMuch or .self$age <- age + howMuch
})
Remember that R works best on vectors, so think of a Persons class (modeling columns) representing all the individuals in your study, rather than a collection of Person instances (modeling rows).

I get an error using your code. I would do something like this:
Person = setRefClass("Person",
fields = list(name = "character", age = "numeric"),
methods = list(
increaseAge = function(howMuch) age <<- age + howMuch
))
> p = new("Person",name="sachin",age=40)
> p$increaseAge(5)
> p$age
[1] 45

Related

Making a function that builds a dataframe

I'm trying to make a function that basically builds a dataframe and returns it. This new dataframe is made of columns taken from another dataframe that I have, called metadata.. in addetion to some additional data that I want to control, by passing the TRUE or FALSE values when calling the function.
Here is what I did:
make_data = function(metric, use_additions = FALSE){
data = data.frame(my_metric = metadata[['metric']], gender = metadata$Gender ,
age = as.numeric(metadata$Age) , use_additions = t(additional_data))
data = data %>% dplyr::select(my_metric, everything())
return(data)
}
data = make_data(CR, FALSE)
I want to pass different metric values each time, and all other features stay the same. So here for example I called the function with metric as CR which is the name of the column I want in the metadata. The argument I want to control is use_additions, sometines I want to add it and sometimes I don't.
metadata and additional_data have the exact same row names and the same rows number. It's just adding the data or not.
I get this error(s):
Error in data.frame(metric = metadata[["metric"]], gender = metadata$Gender, :
arguments imply differing number of rows: 0, 1523
In addition: Warning message:
In data.frame(metric = metadata[["metric"]], gender = metadata$Gender, :
Error in data.frame(my_metric = metadata[["metric"]], gender = metadata$Gender, :
arguments imply differing number of rows: 0, 1523
I've tried several ways to do this, with '' and without, using the $, but non of these worked. So for example when I type metric = metadata[[metric]] I get this:
Error in (function(x, i, exact) if (is.matrix(i)) as.matrix(x)[[i]] else .subset2(x, :
object 'CR' not found
make_data = function(colname, use_additions = FALSE){
data = data.frame(my_metric = metadata[colname], gender = metadata$Gender ,
age = as.numeric(metadata$Age))
if (use_additions) data$use_additions=additional_data
return(data)
}
data = make_data(“CR”, FALSE)

lme object within a function uses response variable from previous run

I am using a lme object within a function but it does not use the response variable that I feed it, instead it uses the response variable from the previous time I called the function.
library(nlme)
library(car)
# DATA (Example)
S1=data.frame(blok = c(rep("blokI",16),rep("blokII",16)),
treat=rep(c("plus","plus","min","min"),8),
field = c(1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16),
subfield = rep(c("a","b"),16),
var1=rnorm(32)^2,
var2=rnorm(32)^2)
S2=data.frame(blok = c(rep("blokI",16),rep("blokII",16)),
treat=rep(c("plus","plus","min","min"),8),
field = c(1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16),
subfield = rep(c("a","b"),16),
var3=rnorm(32)^2,
var4=rnorm(32)^2)
# FUNCTION
get.stats = function(S,dofor){
U = data.frame(crop = NA, C = NA, T_S=NA, T_F=NA, T_DF=NA, T_P=NA, R_S=NA, R_F=NA, R_DF=NA, R_P=NA, TR_S=NA,TR_F=NA, TR_DF=NA, TR_P=NA)
for (i in 1:length(dofor)){
f = as.formula(paste(dofor[i]," ~ treat",sep=""))
model = lme(f, data=S, random = ~1|blok/treat/field/subfield)
av = Anova(model, type = "II")
U[i,1] = NaN
U[i,2] = dofor[i]
U[i,3] = av$`Chisq`[1]
U[i,4] = NaN
U[i,5] = av$Df[1]
U[i,6] = av$`Pr(>Chisq)`[1]
U[i,7] = av$`Chisq`[2]
U[i,8] = NaN
U[i,9] = av$Df[2]
U[i,10] = av$`Pr(>Chisq)`[2]
U[i,11] = av$`Chisq`[3]
U[i,12] = NaN
U[i,13] = av$Df[3]
U[i,14] = av$`Pr(>Chisq)`[3]
}
return(U)
}
dofor=c("var1","var2")
U = get.stats(S1, dofor) # First call of function
dofor=c("var3","var4")
U = rbind(U, get.stats(S2, dofor)) # Second call of function
If I call the function the first time I get Error in eval(x$call$fixed) : object 'f' not found, which is already strange to me as f is defined within the function. I execute the command line where f is defined for i = 1 and call the function again. Now it works, but when I call the function a second time with S2 as data input I get the error:
Error in eval(predvars, data, env) : object 'var2' not found
I have to repeat this model for a many variables on yield of different crops for different years. With this function I intend to collect all the statistics for the different crop species in one matrix which I can latter edit in an Excel sheet.
Any suggestions on how to solve or by-pass my problem?

for loop in ctree [R]

I want to run a decision tree for each variable in my dataframe, so I'm using this:
results_cont = list()
for (i in 2:(ncol(DATA)-1)) {
current_var = colnames(DATA[i])
current_result = ctree(TARGET ~ current_var, DATA, control = ctrl)
results_cont[[i]] = current_result
}
Where DATA is a dataframe where the first column is the ID and the last column (TARGET) is my binary Target.
I keep getting this error:
Error in trafo(data = data, numeric_trafo = numeric_trafo, factor_trafo = factor_trafo, :
data class “character” is not supported
But I don't have any character in mi dataframe.
Is there anything wrong with my loop or something else ?
Thank you guys.
Since you do not provide data, I have not tested this, but I believe your problem is the line
current_result = ctree(TARGET ~ current_var, DATA, control = ctrl)
This is not working because current_var is just a character string. You need to build the formula as a string and then convert it to a formula - like this:
current_var = colnames(DATA[i])
FORM = as.formula(paste("TARGET ~ ", current_var))
current_result = ctree(FORM, DATA, control = ctrl)

Create a S4 super class - with code example

Okay, it took me a while to create a snippet of code that replicates my problem. Here it is. Notice that if you run the command new("FirstSet", id = "Input", multiplier = 2)
you will get the correct answer. However, if you try to create a class that contains both you will get the following: Error in .local(.Object, ...) : argument "id" is missing, with no default. This is literally the best I can do to explain/show the problem.
What in the world am I doing wrong?
setClass("Details",
representation(
ID = "character",
Anumber = "numeric"))
Input <- new("Details",
ID = "Input",
Anumber = 2)
setClass("FirstSet",
representation(
Anothernumber = "numeric"))
setGeneric(
name = "FirstSet",
def = function(object){standardGeneric("FirstSet")}
)
setMethod("initialize",
signature(.Object = "FirstSet"),
function (.Object, id, multiplier)
{ x = id#Anumber
y = x * multiplier
.Object#Anothernumber = y
return(.Object)
}
)
setClass("Super", contains = c("Details", "FirstSet"))
Corrected Code now gives a new error. I followed the instruction in the post and solved my problem. I also created a generic and a method for "Super", see code below,. Now, I get a new error. Error in .local(.Object, ...) : trying to get slot "Anumber" from an object of a basic class ("character") with no slots. Man, this is exhausting, I thought I had it.
The goal for details is, there will be many files that are serialized and methods are called depending on characteristics of the data in the file. Is this even possible in R or am I trying to do something that R cannot do?
New Code
setClass("Details",
representation(
ID = "character",
Anumber = "numeric"))
setGeneric("Details",
def = function(object){standardGeneric("Details")})
setMethod("initialize",
signature(.Object = "Details"),
function(.Object, ID = character(), Anumber = numeric()){
.Object#ID = ID
.Object#Anumber = 2
return(.Object)
})
setClass("FirstSet",
representation(
Anothernumber = "numeric"))
setGeneric(
name = "FirstSet",
def = function(object){standardGeneric("FirstSet")}
)
setMethod("initialize",
signature(.Object = "FirstSet"),
function (.Object, id = character(), multiplier = numeric())
{ x = id#Anumber
y = x * multiplier
.Object#Anothernumber = y
return(.Object)
}
)
setClass("Super", contains = c("Details", "FirstSet"))
setGeneric("Super",
def = function(object){standardGeneric("Super")})
setMethod("initialize",
signature(.Object = "Super"),
function(.Object, id = character(), Anumber = numeric()){
Details <- new("Details", ID = id, Anumber = Anumber)
FirstSet <- new("FirstSet", Anothernumber = Anothernumber)
Super <- new("Super", Details, FirstSet)
return(.Object)
})
The basic rule is that new("FirstSet") (or any non-virtual class) needs to work. Yours doesn't (because the intiailize arguments don't have default values). See this answer for some more guidelines.

Why am I getting the message "node stack overflow" when the superclass is "VIRTUAL"?

I am getting the message
Error in parent.frame() : node stack overflow
Error during wrapup: node stack overflow
when I try to construct an object using the S4 command "as", but only when a superclass is declared "VIRTUAL".
The class hierarchy is as follows:
PivotBasic contains Pivot contains Model
The setClass commands for Pivot and Pivot Basic and the constructor for PivotBasic are below. Class Pivot does not have a constructor. The Model constructor is too big to insert here.
This is really not a big deal (I think) because everything works fine if the "VIRTUAL" keyword is removed from the representation argument of setClass. But I am curious about the reason for the problem. Would anyone have insights on it?
Thanks,
Fernando Saldanha
setClass(Class = "Pivot",
representation = representation(
pivotName = "character",
pivotNames = "character",
pivotData = "data.frame",
"VIRTUAL"
),
contains = "Model"
)
setClass(Class = "PivotBasic",
representation = representation(),
contains = "Pivot"
)
pivotBasic <- function(
portfolio,
assets,
controlVariableList,
pivotData = NULL, # pivotName is ignored if pivotData is not null
pivotName = "N_WEEKDAY_3_6",
firstPredictionDate = as.Date(integer(), origin = "1970-01-01"),
name = NULL,
tags = "Event"
) {
if (missing(portfolio)) stop("[PivotBasic: pivotBasic] - Missing portfolio argument")
if (missing(assets)) stop("[PivotBasic: pivotBasic] - Missing assets argument")
if (missing(controlVariableList)) stop("[PivotBasic: pivotBasic] - Missing controlVariableList argument")
object <- model(
portfolio,
assets,
controlVariableList,
firstPredictionDate,
name,
tags)
# The error message happens when this command is executed
mdl <- as(object, "PivotBasic")
# Other code
mdl
} # end pivotBasic
Is this a minimal example that illustrates your problem
.Model <- setClass(Class = "Model",
representation=representation(x="integer")
)
setClass(Class = "Pivot",
representation = representation("VIRTUAL"),
contains = "Model"
)
.PivotBasic <- setClass(Class = "PivotBasic",
contains = "Pivot"
)
This generates an error
> as(.Model(), "PivotBasic")
Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
> R.version.string
[1] "R version 3.0.0 Patched (2013-04-15 r62590)"
but might generate an error like you see under an earlier version of R. This thread on the R-devel mailing list is relevant, where a solution is to define a setIs method such as
setIs("PivotBasic", "Model",
coerce = function(from) .PivotBasic(x = from#x),
replace = function(from, value) {
from#x = value#x
from
}
)
I think of setIs as part of the class definition. If there are many slots needing copying, then a further work-around might be, in the replace function,
nms <- intersect(slotNames(value), slotNames(from))
for (nm in nms)
slot(from, nm) <- slot(value, nm)
from
but the underlying issue is really in S4's implementation. A cost to removing the "VIRTUAL" specification is that it compromises your class design, and presumably the formalism of the S4 system is what motivated your choice in the first place; maybe that's not such a bad cost when faced with the alternatives.

Resources