Reputation: 4711
Is there any way to set an attribute on an object that is removed when it is processed by another function? For example, I might write:
weightedMeanZr <- function(r,n) {
require(psych)
Zr <- fisherz(r)
ZrBar <- sum(Zr*(n-3))/(sum(n-3))
attr(ZrBar,"names") <- "ZrBar"
return(ZrBar)
}
To calculated the weighted fisher transformed Z average for a set of correlations. However, if I convert it back into an r, e.g.
require(psych)
bdata <- structure(list(Sample = 1:6, n = c(4L, 13L, 9L, 5L, 11L, 14L),
r = c(0.93, 0.57, 0.46, -0.09, 0.12, 0.32)), .Names = c("Sample",
"n", "r"), class = "data.frame", row.names = c(NA, -6L))
fisherz2r(with(bdata,weightedMeanZr(r,n)))
The output value from fisherz2r
has retained the names attribute from the results of weightedMeanZr. Is there any way to make that attribute fragile such that being processed by functions like fisherz2r
removes the names attribute?
Edit Something like what this accomplishes:
weightedMeanZr <- function(r,n) {
require(psych)
Zr <- fisherz(r)
ZrBar <- sum(Zr*(n-3))/(sum(n-3))
class(ZrBar) <- "ZrBar"
return(ZrBar)
}
"+.ZrBar" <- function(e1,e2) {
return(unclass(e1)+unclass(e2))
}
"-.ZrBar" <- function(e1,e2) {
return(unclass(e1)-unclass(e2))
}
"*.ZrBar" <- function(e1,e2) {
return(unclass(e1)*unclass(e2))
}
"/.ZrBar" <- function(e1,e2) {
return(unclass(e1)/unclass(e2))
}
weightedMeanZr(bdata$r,bdata$n)
weightedMeanZr(bdata$r,bdata$n)+1
weightedMeanZr(bdata$r,bdata$n)-1
weightedMeanZr(bdata$r,bdata$n)*2
weightedMeanZr(bdata$r,bdata$n)/2
fisherz2r(weightedMeanZr(bdata$r,bdata$n))
... but this only works because fisherz2r calls those particular methods... is there a more general approach?
Upvotes: 3
Views: 106
Reputation: 4711
No, there isn't a way to automatically do what I am trying to do (at least as of R 2.15.2 as far as I can tell). There is a callback system in R (thanks go to @JoshuaUlrich for bringing that keyword to mind), but trying to implement the desired behavior may be computationally expensive.
However, here is a (working) example:
require(psych)
bdata <- structure(list(Sample = 1:6, n = c(4L, 13L, 9L, 5L, 11L, 14L),
r = c(0.93, 0.57, 0.46, -0.09, 0.12, 0.32)), .Names = c("Sample",
"n", "r"), class = "data.frame", row.names = c(NA, -6L))
weightedMeanZr <- function(r,n) {
require(psych)
Zr <- fisherz(r)
ZrBar <- sum(Zr*(n-3))/(sum(n-3))
attr(ZrBar,"original.value") <- ZrBar
class(ZrBar) <- "ZrBar"
attr(ZrBar,"names") <- "ZrBar"
return(ZrBar)
}
h <- taskCallbackManager() #create the callback system
# add a callback
h$add(function(expr, value, ok, visible) {
cat("In handler",george,"\n")
ZrBars <- names(which(lapply(sapply(ls(name=.GlobalEnv,all=TRUE),get),class) == "ZrBar"))
for (i in ZrBars) {
thisone <- get(i)
if(!attr(thisone,"original.value") == thisone) {
attr(thisone,"names") <- NULL
attr(thisone,"class") <- NULL
attr(thisone,"original.value") <- NULL
assign(i,thisone,envir=.GlobalEnv)
}
}
return(TRUE)
}, name = "simpleHandler")
#create some objects of the class
thisone <- weightedMeanZr(runif(10),4:13)
thistoo <- weightedMeanZr(runif(10),4:13)
thisone + 1 #class kept, a print method could be added to resolve this issue
#if we store the result, it goes away as desired
(um <- thisone + 1) #class gone\
#clean out workspace so the callback system doesn't linger
removeTaskCallback("R-taskCallbackManager")
Upvotes: 2
Reputation: 115435
You can use unname
to remove names
fisherz2r(with(bdata,unname(weightedMeanZr(r,n))))
# or
unname(fisherz2(with(bdata,weightedMeanZr(r,n))))
or as.vector
, which in this case will strip the names
Upvotes: 4