I am writing a function where in one or more of the arguments are vectors generated by a loop within the function.
For ex:
myfunc<-function(rep, n, arm1, arm2)
{
for(i in 1:rep)
{
x<-rnorm(n,0,4)
y<-rnorm(n,0,5)
res[i]<-t.test(arm1,arm2)
}
return(res)
}
Now I would like to call the function as
myfunc(rep = 10, n=10, arm1 = x, arm2 = x) or
myfunc(rep = 10, n=10, arm1=x,arm2 = y)
The idea is compare different arms.
Hope I have stated my problem clearly.
Your help is highly appreciated.
Let's see if I got it...
You want run rep tests, each with two vetors of n normal random variates. And you want to be able to change the arguments... Frankly, this is not the best way to program.. BUT, I will try to help you.
First things first: you can't assign to an arbitrary position of the result res before creating the variable. So I'll add res <- list() to your code. Also t.test returns more information, so it must be appended to a list object, with double square brackets.
Now, for the arguments, you must make R understand that arm are symbol arguments, to be evaluated inside the function's environment. So you must capture it's expression using substitute and pass it to eval function:
myfunc<-function(rep, n, arm1, arm2)
{
res <- list() ###
for(i in 1:rep)
{
x<-rnorm(n,0,4)
y<-rnorm(n,0,5)
res[[i]]<-t.test(eval(substitute(arm1)),eval(substitute(arm2))) ###
}
return(res)
}
Try it...
A better way to do this is as follows:
newfunc <- function(rep, n, sd1, sd2)
{
lapply(1:rep, function(.) t.test(rnorm(n,0,sd1), rnorm(n,0,sd2)))
}
Now sd1 and sd2 are the standard deviations parameters.
Related
Incredibly basic question. I'm brand new to R. I feel bad for asking, but also like someone will crush it:
I'm trying to generate a number of vectors with a for loop. Each with an unique name, numbered by iteration. The code I'm attaching throws an error, but I think it explains what I'm trying to do in principle fairly well.
Thanks in advance.
vectorBuilder <- function(num){
for (x in num){
paste0("vec",x) <- rnorm(10000, mean = 0, sd = 1)}
}
numSeries <- 1:10
vectorBuilder(numSeries)
You can write the function to return a named list :
create_vector <- function(n) {
setNames(replicate(n, rnorm(10000), simplify = FALSE),
paste0('vec', seq_len(n)))
}
and call it as :
data <- create_vector(10)
data will have list of length 10 with each element having a vector of size 10000. It is better to keep data in this list instead of creating lot of vectors in global environment. However, if you still want separate vectors you can use list2env :
list2env(data, .GlobalEnv)
Suppose I have two vectors. Suppose further that I would like my function takes only one values of each vector and return me the output. Then, I would like another function to check the values of each run. If the output of the previous run is smaller than the new one. Then, I would like my function to stop and return me all the previous values. My original function is very complicated (estimation models). Hence, I try to provide an example to explain my idea.
Suppose that I have these two vectors:
set.seed(123)
x <- rnorm(1:20)
y <- rnorm(1:20)
Then, I would like to write a function which only takes one values of each vector and multiplied them. Then, return me the output. Then, I would like the function to check if the previous multiplication is smaller than the new one or not. If yes, then stop and return me all the previous multiplication.
I tried this:However, this functions takes all the values at once and return me a list of the multiplication. I was thinking about using lapply, to fit one element at a time but I do not know how to work with the conditions.
myfun <- function(x, y, n){
multi <- list()
for ( i in 1:n){
multi[[i]] <- x[[i]]*y[[i]]
}
return(multi)
}
myfun(x,y,10)
Here is another try
x <- rnorm(1:20)
y <- rnorm(1:20)
myfun <- function(x, y){
multi <- x*y
return(multi)
}
This is the first function. I would like to run it element by element. Each time, I would like it to returns me only one multiplication result. Then, another function (wrapper function) check the result. It the second output of the first function (multiplication function) is larger than the first one, then stop, otherwise keep going.
I would like to write a function which only takes one values of each vector and multiplied them. Then, return me the output. Then, I would like the function to check if the previous multiplication is smaller than the new one or not.
I would like the multiplication in a separate function. Then, I would like to check its output. So, I should have a warper function.
You can apply a for loop with a stopping condition, similar to what you have already:
# example input
set.seed(123)
x <- rnorm(1:20)
y <- rnorm(1:20)
# example function
f = function(xi, yi) xi*yi
# wrapper
stopifnot(length(x) == length(y))
res = vector(length(x), mode="list")
for (i in seq_along(x)){
res[[i]] = f(x[[i]], y[[i]])
if (i > 1L && res[[i]] > res[[i-1L]]) break
}
res[seq_len(i)]
Comments:
It is better to predefine the max length res might need (here, length(x)), rather than expanding it in the loop.
For this function (multiplication), there is no good reason to proceed elementwise. R's multiplication function is vectorized and fast.
You don't need to use a list-class output for this function, since it is returning doubles; res = double(length(x)) should also work.
You don't need to use list-style accessors for x, y and res unless lists are involved; res[i] = f(x[i], y[i]) should work, etc.
I want to make a function in terms of x and coef for multiple values of x so that the output is a vector, like I've tried here:
directpoly<-function(x,coef) {
for(n in length(coef)) {
total<-sum(coef*x^(0:(n-1)))
}
total
}
This works when I input one value for x and any vector for the coefficient values, but I want more than that. I want to input a certain amount of values for the coefficients, say c(5,9,-2), and have the function produce three different values, one for each input of x for, say, x<-2:4. So in that case I'd want output 15, 14, 9. Any ideas? I am new so all help is appreciated.
Edit: I took out an "<-" that I accidentally put in there. Sorry if that was any cause for confusion. Also what I want in the end is a function
P(x) = c1 + c2*x + ... + cn*x^n-1
Does this work?
directpoly <- function(x, coef) {
seqcoef <- seq_along(coef) - 1
sapply(x, function(z) sum(coef*z^seqcoef))
}
directpoly(2:4, c(5,9,-2))
# [1] 15 14 9
If so, the trick to solving this is two-steps:
Determine what you want to do with each value of x (no vector). In this case, it's simply from among:
sum(coef*x^(1:length(coef)-1))
sum(coef*x^(0:(length(coef)-1)))
sum(coef*x^(seq_along(coef)-1))
Because I'm eventually putting this into some loop/apply formulation, I don't need to recalculate the sequence each time, so I break it out:
seqcoef <- seq_along(coef) - 1
sum(coef*x^seqcoef)
Now that you know what to do with each x`, now map or apply over it:
sapply(x, function(z) ...)
where ... is what we determined above. For clear coding, many believe the technique of hard-defining this function is good, so something like:
directpoly1 <- function(x, coef, seqcoef = seq_along(coef) - 1) {
sum(coef*x^seqcoef)
}
directpoly <- function(x, coef) {
seqcoef <- seq_along(coef) - 1
sapply(x, directpoly1, coef, seqcoef)
}
(I took a little more liberty with this version to enable running it explicitly with a scalar argument, primarily for unit-testing. It is not strictly necessary, so the function at the top of this answer should suffice.)
First, my English is not so correct, so I apologize in advance for any grammar mistakes/errors in my question.
I have this general function:
.my_fun <- function(x,y,...){
<body>
return(
list(
fun1 <- function(x){
<bodyfun1>
},
fun2 <- function(y){
<bodyfun2>
}, ....
)
)
}
to be used as auxiliary of:
.my_funfun <- .my_fun(x,y,...)
and use ".my_funfun" as a code starter given the args of "my_fun"
I have to return values on the given order and of course return the result of the functions included on the body of the list. Normally, I would process the functions separately, store the results in separate objects and put the values of those objects in a list, and return that list (simplest way to do it), but I'm required to keep the structure I showed before.
My question is: is there any way to solve the functions in the body of the list and return those values, keeping the given structure? Or is it impossible to use return that way? I have used return() as a premature function stopper and as a fancy printer for objects in control structures, but this usage is new to me.
If you need the specific code elements I can provide them.
Thanks in advance.
You could do this:
my_fun <- function(x,y) {
fun1 <- function(x) {
length(x)
}
fun2 <- function(y) {
sum(y)
}
list(fun1(x),fun2(y))
}
Ok, doing stuff around, I realized what my mistake on the code was. The thing is that when i call
myfun$fun1
I got no answer. The right way to make the list is
.my_fun <- function(x,y,...){
<body>
return(
list(
fun1 = function(x){
<bodyfun1>
},
fun2 = function(y){
<bodyfun2>
}, ....
)
)
}
So i can use the name s"fun1, fun2 (...) as names to call in axiliary function.s
Example:I want to make a linear congruent random generator, with the following code:
.rCongLin <- function(a, c, m, x0){
v1 <- x0
return(
list(seed=function(xw){
v1 <- xw},
nxt=function(){
v2 <- ((a*v1)+c)%%m
v3 <- v2/m
v1<<-v2
return(v3)
},
shw=function(){
return(list(a=a,c=c,m=m,x0=x0))}
)
)
}
The instruction:
.rCL <- .rCongLin(51864,35186,4153,1515)
starts the number generation given the function:
rCL=function(n){
replicate(n,.rCL$nxt())}
rCL(45)
where seed() restarts x0, nxt() calculates the numbers and shw() shows the internal state (values for calculation). rCL(n) returns n number of replicas.
The thing is that .rCL$x() (where x() is any fun of those mentioned) returns NOTHING if you use '<-' operator (change it so u have a demonstration of what im talking about), but it does return with '='.
The answer is that the functions work with '=' because names are ASSIGNED on the lists with '=' (u name things in lists with '=') and not with '<-'. Therefore, in order to make the funtions... "citable" in the body of the return(list(fun1, fun2...) you need to assign the names fun1, fun2... using '='.
It was a simple answer. Got confused in using '=' and '<-' because in the original code every assignment is done with '='. Its prone to confuse novel programmers like me :(
Thanks a lot for your help!
Again Im sorry for any gramatical mistakes in this answer.
I hope this helps more people.
I am trying to sample a population drawn from a normal distribution with a mean of 10.016 and a standard deviation of 0.8862719 (n=20), a thousand times. I want to create a loop to do this. I tried creating a function (stamendist) to draw random variables from a normal distribution with the abovementioned mean and standard deviation, but when I run the loop, I get an error message:
Error: could not find function "stamendist" (even though I ran the function before running the loop).
I tried running the loop without the object "stamendist" by just inputting rnorm(n=20,mean=10.016,sd=0.8862719), but the same error message persists.
Here is my code:
stamendist <- rnorm(n=20,mean=10.016,sd=0.8862719)
sampled.means <- NA
for(i in 1:1000){
y=stamendist(100)
sampled.means[i] <- mean(y)
}
Am I misunderstanding how a function works? I'm pretty new to R, so any help or advice would be appreciated.
You don't need a loop to obtain the vector of sample means:
n <- 1000
sampled.means <- colMeans(matrix(rnorm(n = 20 * n, 10.016, 0.8862719), ncol = n))
If you want stamentdist to be a function, you need to assign stamendist as a function. The general notation for a function is:
foo <- function(args, ...){
expressions
}
You must then decide which parameters you want the user to specify. In your specific example, I assume you want the user to specify how many observations. Here is how the function would look with that in mind:
stamendist <- function(n) {
rnorm(n=n,mean=10.016,sd=0.8862719)
}
In this line:
stamendist <- rnorm(n=20,mean=10.016,sd=0.8862719)
You assign 20 values to the vector named stamendist
In this line:
y=stamendist(100)
You try to call a function stamendist, which doesnt exist.
Move this lineinside the loop:
stamendist <- rnorm(n=20,mean=10.016,sd=0.8862719)
So you create a new set of random number for each iteration.
Then pass stamendist to the mean function. And you dont need y at all