I'd like to plot a function of x, where x is applied to a vector. Anyway, easiest to give a trivial example:
var <- c(1,2,3)
curve(mean(var)+x)
curve(mean(var+x))
While the first one works, the second one gives errors:
'expr' did not evaluate to an object of length 'n' and
In var + x : longer object length is not a multiple of shorter object length
Basically I want to find the minimum of such a function: e.g.
optimize(function(x) mean(var+x), interval=c(0,1))
And then be able to visualise the result. While the optimize function works, I can't figure out how to get the curve() to work as well.. Thanks!
The function needs to be vectorized. That means, if it evaluates a vector it has to return a vector of the same length. If you pass any vector to mean the result is always a vector of length 1. Thus, mean is not vectorized. You can use Vectorize:
f <- Vectorize(function(x) mean(var+x))
curve(f,from=0, to=10)
This can be done in the general case using sapply:
curve(sapply(x, function(e) mean(var + e)))
In the specific example you give, mean(var) + x, is of course arithmetically equivalent to what you're looking for. Similar shortcuts might exist for whatever more complicated function you're working with.
Related
This code is about inverting an index using clusters.
Unfortunately I do not understand the line with recognize<-...
I know that the function Vectorize applies the inner function element-wise, but I do not understand the inner function here.
The parameters (uniq, test) are not defined, how can we apply which then? Also why is there a "uniq" as text right after?
slots <- as.integer(Sys.getenv("NSLOTS"))
cl <- makeCluster(slots, type = "PSOCK")
inverted_index4<-function(x){
y <- unique(x)
recognize <- Vectorize(function(uniq,text) which(text %in% uniq),"uniq",SIMPLIFY = F)
y2 <- parLapply(cl, y, recognize, x)
unlist(y2,recursive=FALSE)
}
The
Vectorise()
function is just making a new element wise, vectorised function of the custom function
function(uniq,text) which(text %in% uniq).
The 'uniq' string is the argument of that function that you must specify you want to iterate over. Such that now you can pass a vector of length greater than one for uniq, and get returned a list with an element for the output of the function evaluated for every element of the input vector uniq.
I would suggest the author make the code a little clearer, better commented etc. the vectorise function doesn't need to be inside the function call necessarily.
Note
ParLapply()
isn't a function I recognise. But the x will be passed to the recognise function and the second argument text should presumably be defined earlier on, in the global environment, .GlobalEnv().
Consider a function f(x,y), where x is a vector (1xn) and data a matrix (nxm), returning a numeric scalar.
Now, I have a matrix A and a three-dimensional array B and would like to apply f across the first dimension of A and B.
Specifically, I would like f to be evaluated at x=A[1,] y=B[1,,], followed by x=A[2,] y=B[2,,] and so on, returning a vector of numeric scalars.
Is there a way to use any function of the "apply" family to solve this problem, thus avoiding a loop?
You can do:
sapply(1:nrow(A), function(i) f(A[i,], B[i,,]))
This is loop hiding because the looping is done inside of sapply(). I suppose in this case it is better to use a explicit loop:
result <- numeric(nrow(A))
for (i in 1:nrow(A)) result[i] <- f(A[i,], B[i,,]
testing<-function(formula=NULL,data=NULL){
if(with(data,formula)==T){
print('YESSSS')
}
}
A<-matrix(1:16,4,4)
colnames(A)<-c('x','y','z','gg')
A<-as.data.frame(A)
testing(data=A,formula=(2*x+y==Z))
Error in eval(expr, envir, enclos) : object 'x' not found
##or I can put formula=(x=1)
##reason that I use formula is because my dataset had different location and I would want
##to 'subset' my data into different set
This is the main flow of my code. I had done some search and seems to be no one ask this kind of stupid question or it is not possible to pass a formula in a if statement. Thank you in advance
if you just want subset of your data.frame create a character object representing the formula like this:
formula="2*x+y==z"
testing<-function(data,formula){with(data = data,expr = eval(parse(text = formula)))}
subset(A,testing(A,formula=formula))
#x y z gg
#2 2 6 10 14
You can change the formula as per your need.
If we need to evaluate it, one option is eval(parse
testing<-function(formula=NULL,data=NULL){
data <- deparse(substitute(data))
if(any(eval(parse(text=paste("with(", data, ",",
deparse(substitute(formula)), ")")))))
print("YESSS")
}
testing(data=A,formula=(2*x+y==z))
#[1] "YESSS"
When you call a function in R it evaluates its arguments first before executing the function.
For example, prod(2+2, 3) is first turned into prod(4, 3) before the function prod() is even called.
Thus, in your code, R starts by trying to solve (2*x+y==Z). It fails because there is no x object outside of the function code. So, it not even begin running testing().
To use your function correctly you should make it clear to R that it is not supposed to calculate (2*x+y==Z). Instead it should pass this information as is. You could do that using the functions expression() and eval().
testing<-function(formula=NULL,data=NULL){
if(with(data,eval(formula==T)){
print('YESSSS')
}
}
A<-matrix(1:16,4,4)
colnames(A)<-c('x','y','z','gg')
A<-as.data.frame(A)
testing(data=A,formula=expression(2*x+y==Z))
However, you will notice that there other problems with your code.
For Z is different than z. Notice that the in colnames you use z and in the formula Z.
The if() only works for when there is a single value of true or false. In your case, you will have one value for each row in A. When this happens, if() will only check if the first row fits the criteria.
If your purpose is subsetting, it is much more easier to do:
A.subset <- subset(A, 2*A$x+A$y == A$z)
After a discussion with my colleague,
here is a kind of solution
testing<-function(cx,cy,px,py,z,data=NULL){
list<-NULL
for(m in 1:nrow(data)){
if(cx*data$x[m]^px+cy*data$y[m]^py+data$z==0){
print(m)}
}
}
but this can deal with polynomial only and with a lot of arguments in the function. I am think of a way to reduce it as a general equation.or maybe this is the most easiest equation.
I have a some true and predicted labels
truth <- factor(c("+","+","-","+","+","-","-","-","-","-"))
pred <- factor(c("+","+","-","-","+","+","-","-","+","-"))
and I would like to build the confusion matrix.
I have a function that works on unary elements
f <- function(x,y){ sum(y==pred[truth == x])}
however, when I apply it to the outer product, to build the matrix, R seems unhappy.
outer(levels(truth), levels(truth), f)
Error in outer(levels(x), levels(x), f) :
dims [product 4] do not match the length of object [1]
What is the recommended strategy for this in R ?
I can always go through higher order stuff, but that seems clumsy.
I sometimes fail to understand where outer goes wrong, too. For this task I would have used the table function:
> table(truth,pred) # arguably a lot less clumsy than your effort.
pred
truth - +
- 4 2
+ 1 3
In this case, you are test whether a multivalued vector is "==" to a scalar.
outer assumes that the function passed to FUN can take vector arguments and work properly with them. If m and n are the lengths of the two vectors passed to outer, it will first create two vectors of length m*n such that every combination of inputs occurs, and pass these as the two new vectors to FUN. To this, outer expects, that FUN will return another vector of length m*n
The function described in your example doesn't really do this. In fact, it doesn't handle vectors correctly at all.
One way is to define another function that can handle vector inputs properly, or alternatively, if your program actually requires a simple matching, you could use table() as in #DWin 's answer
If you're redefining your function, outer is expecting a function that will be run for inputs:
f(c("+","+","-","-"), c("+","-","+","-"))
and per your example, ought to return,
c(3,1,2,4)
There is also the small matter of decoding the actual meaning of the error:
Again, if m and n are the lengths of the two vectors passed to outer, it will first create a vector of length m*n, and then reshapes it using (basically)
dim(output) = c(m,n)
This is the line that gives an error, because outer is trying to shape the output into a 2x2 matrix (total 2*2 = 4 items) while the function f, assuming no vectorization, has given only 1 output. Hence,
Error in outer(levels(x), levels(x), f) :
dims [product 4] do not match the length of object [1]
Instead of writing one vector subscript operation a line, such as:
x.and.y <- intersect(x, y)
idx.x <- match(x, x.and.y)
idx.x <- idx.x[!is.na(idx.x)]
I could chain them in one line:
x.and.y <- intersect(x, y)
idx.x <- subset(tmp <- match(x, x.and.y), !is.na(tmp))
In order to do that, I must give intermediate vector a name to be used in subscript operations. To make code even more concise, is there a way to refer to a vector anonymously? Like this:
x.and.y <- intersect(x, y)
idx.x <- match(x, x.and.y)[!is.na] ## illegal R
Considering intersect calls match, what you're doing is redundant. intersect is defined as:
function (x, y)
{
y <- as.vector(y)
unique(y[match(as.vector(x), y, 0L)])
}
And you can get the same result as your 3 lines of code by using %in%: x[y%in%x].
I realize this may not be representative of your actual problem, but "referring to a vector anonymously" doesn't really fit the R paradigm. Function arguments are pass-by-value. You're essentially saying, "I want a function to manipulate an object, but I don't want to provide the object to the function."
You could use R's scoping rules to do this (which is what mplourde did using Filter with an anonymous function), but you're going to create quite a bit of convoluted code that way.