Suppose my function d below can output the same answer for a different combination of its two input values.
For example, to output 0.8164966, one can input d(2, 12) or similarly d(1, 3) and many more combinations of the two input values.
Question Is there a way to get just one possible pair of input values IF I provide the desired output d?
For example, if I desire to have a d = 0.8164966, can R give me just 1 and 3 as one pair of possible input values that lead to a d = 0.8164966?
NOTE: I'm asking how to solve for only one pair of possible (there are many) input values given any d (the output).
d <- function(mean_dif, Vmax) mean_dif/sqrt(Vmax/2)
d(2, 12) # 0.8164966
d(1, 3) # 0.8164966
If you want this to work for a general d, you need to give the solver a hint. For example, is there guaranteed to be a solution with the first argument equal to 1? What's the range of possible values for the second argument if the first is 1?
With the d you give, the answers are "yes, it's guaranteed", and an explicit solution is Vmax = 2/d^2, i.e.
inv_d <- function(d) {
c(mean_dif = 1, Vmax = 2/d^2)
}
and you get
inv_d(pi)
# mean_dif Vmax
# 1.0000000 0.2026424
Now, if you didn't know that solution for Vmax, you could try using uniroot:
inv_d <- function(dval) {
Vmax <- uniroot(function(Vmax) d(1, Vmax) - dval, c(0, 10/dval^2))$root
c(mean_dif = 1, Vmax = Vmax)
}
inv_d(pi)
# mean_dif Vmax
# 1.0000000 0.2026534
In this case the solution is a bit less accurate.
If you can't get the interval or the guarantee, then in general there's no solution, but you might be able to try a bunch of different guesses and sometimes get lucky.
This boils down to converting a decimal to a rational number. One way to do this is using MASS::fractions. That means we can write your inverse function like this:
inv_d <- function(d) {
ratio <- MASS::fractions(d^2/2)
result <- as.numeric(strsplit(attr(ratio, "fracs"), "/")[[1]])
result[1] <- result[1]^2
setNames(result, c("mean_dif", "Vmax"))
}
So you can do:
inv_d(d(2, 12))
#> mean_dif Vmax
#> 1 3
inv_d(d(1, 3))
#> mean_dif Vmax
#> 1 3
inv_d(d(5, 100))
#> mean_dif Vmax
#> 1 4
Related
I want to create a function that transforms its object.
I have tried to transform the variable as you would normally, but within the function.
This works:
vec <- c(1, 2, 3, 3)
vec <- (-1*vec)+1+max(vec, na.rm = T)
[1] 3 2 1 1
This doesn't work:
vec <- c(1, 2, 3, 3)
func <- function(x){
x <- (-1*x)+1+max(x, na.rm = T))
}
func(vec)
vec
[1] 1 2 3 3
R is functional so normally one returns the output. If you want to change
the value of the input variable to take on the output value then it is normally done by the caller, not within the function. Using func from the question it would normally be done like this:
vec <- func(vec)
Furthermore, while you can overwrite variables it is, in general, not a good
idea. It makes debugging difficult. Is the current value of vec the
input or output and if it is the output what is the value of the input? We
don't know since we have overwritten it.
func_ovewrite
That said if you really want to do this despite the comments above then:
# works but not recommended
func_overwrite <- function(x) eval.parent(substitute({
x <- (-1*x)+1+max(x, na.rm = TRUE)
}))
# test
v <- c(1, 2, 3, 3)
func_overwrite(v)
v
## [1] 3 2 1 1
Replacement functions
Despite R's functional nature it actually does provide one facility for overwriting although the function in the question is not really a good candidate for it so let us change the example to provide a function incr which increments the input variable by a given value. That is, it does this:
x <- x + b
We can write this in R as:
`incr<-` <- function(x, value) x + value
# test
xx <- 3
incr(xx) <- 10
xx
## [1] 13
T vs. TRUE
One other comment. Do not use T for true. Always write it out. TRUE is a reserved name in R but T is a valid variable name so it can lead to hard to find errors such as when someone uses T for temperature.
If I have a set of values such as
c(1,2,5,6,7,15,19,20)
and I want to randomly select 2 values where the sum equals 20. From the above list possible samples that I would like to see would be
[19,1], [15,5]
How do I do this in R. Any help would be greatly appreciated.
This computes all possible combinations of your input vector, so if this is very long, this might be a problem.
getVal <- function(vec,val) {
comb = combn(vec, 2)
idx = colSums(comb) == val
if (sum(idx)) {
return(comb[,idx][,sample(sum(idx),1)])
}
return(FALSE)
}
vec = (c(1,4,6,9))
val = 10
getVal(vec,val)
>>[1] 1 9
val = 11
>>[1] FALSE
getVal(vec,val)
For a small vector of values you can do an exhaustive search by working out all the combinations of pairs in the values. Example:
> values = c(1,2,5,6,7,15,19,20)
> pairs = matrix(values[t(combn(length(values),2))],ncol=2)
That is a 2-column matrix of all pairs from values. Now sum the rows and look for the target value of 20:
> targets = apply(pairs,1,sum)==20
> pairs[targets,]
[,1] [,2]
[1,] 1 19
[2,] 5 15
The size of pairs increases such that if you have 100 values then pairs will have nearly 5000 rows.
You can do this with the sample()-functie and a while-loop. It isn't the prettiest solution but a simple to implement one for sure.
First you sample two values from the vector and store them in an object, like:
values <- c(1, 2, 5, 6, 7, 15, 19, 20)
randomTwo <- sample(values, 2)
Then you start you while-loop. This loop checks if sum of the two sampled values modulo 10 equals 0 (I assumed you meant modulo from the examples in your question, see https://en.wikipedia.org/wiki/Modulo_operation to see what it does). If the operation does not equal 0 the loop samples two new values until the operation does equal zero, and you get your two values.
Here's what it looks like:
while (sum(randomTwo) %% 10 != 0) {
randomTwo <- sample(values, 2)
}
Now this might take more iterations than checking all combo's, and it might take less, depending on chance. If you have just this small vector than it's a nice solution. Good luck!
In a way where you don't need to compute a inmense matrix (way faster):
findpairs=function(a,sum,num){
list=list()
aux=1
for (i in 1:length(a)){
n=FALSE
n=which((a+a[i])==sum)
if (length(n)){
for (j in n){
if (j!=i){
list[[aux]]=c(a[i],a[j])
aux=aux+1
}
}
}
}
return(sample(list[1:(length(list)/2),num))
}
a=c(1,2,5,6,19,7,15,20)
a=a[order(a)]
sum=20
findpairs(a,sum,2)
[[1]]
[1] 5 15
[[2]]
[1] 1 19
Issue is that it gives repetition.
edit
Solved. Just take half of the list as the other half will be the same pairs the other way around.
function(q,b,Data1,Data2){
x<-sum(
ifelse(Data1[13+q,b]/Data1[12+q,b]>Data2[13+q,1]/Data2[12+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[11+q,b]>Data2[13+q,1]/Data2[11+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[10+q,b]>Data2[13+q,1]/Data2[10+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[9+q,b]>Data2[13+q,1]/Data2[9+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[8+q,b]>Data2[13+q,1]/Data2[8+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[7+q,b]>Data2[13+q,1]/Data2[7+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[6+q,b]>Data2[13+q,1]/Data2[6+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[5+q,b]>Data2[13+q,1]/Data2[5+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[4+q,b]>Data2[13+q,1]/Data2[4+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[3+q,b]>Data2[13+q,1]/Data2[3+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[2+q,b]>Data2[13+q,1]/Data2[2+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[1+q,b]>Data2[13+q,1]/Data2[1+q,1],1,0)
)/12
}
Is there a way to simplify this? (no characters, only numbers in the data sets)
Thank you
Two pieces of knowledge you can combine to improve your code:
Firstly, you can divide a single number by a vector and R will return a vector with elementwise divisions. For example:
5 / c(1,2,3,4,5,6)
# [1] 5.0000000 2.5000000 1.6666667 1.2500000 1.0000000 0.8333333
The numerator on both sides of the inequality are the same all the time, you can use the above. So instead of explicitly calling it for every inequality, you can just call it once.
Secondly, an expression with TRUE or FALSE will be coerced to 1 and 0 when you try to perform arithmetic operations (in your case division, or calculating a mean). Inequalities return TRUE or FALSE values. Explicitly telling R to convert them to 0 and 1 is wasted energy, because R will automatically do it in your last step.
Putting this together in a simplified function:
function(q, b, Data1, Data2){
qseq <- (1:12) + q # Replaces all "q+1", "q+2", ... , "q+12"
dat1 <- Data1[qseq, b] # Replaces all "Data1[q+1, b]", ... "Data1[q+12, b]"
dat2 <- Data2[qseq, 1] # Replaces all "Data2[q+1, 1]", ... "Data2[q+12, 1]"
mean( Data1[13+q, b]/dat1 > Data2[13+q, 1]/dat2 )
this simplify a bit:
function(q,b,Data1,Data2){
data1_num <- Data1[13+q,b]
data2_num <- Data2[13+q,1]
x <- 0
for (i in 1:12) {
x <- x + ((data1_num/Data1[i+q,b]) > (data2_num /Data2[i+q,1]))
}
x <- x /12
#return(x)
}
But If you provide data example, and the output your expecting, i'm sure there is way to simplify it better
I am trying to write a program in R to sum n random number. However, when I try it for some numbers it won't work.
For example,
## rm(list=ls())
random.sum <- function(n) {
x[1:n] <- ceiling(10*runif(n))
cat("x:", x[1:n], "\n")
return(sum(x))
}
x <- rep(100, 10)
show(random.sum(10))
show(random.sum(5))
when I try to sum 10 random numbers it will give me the correct sum which is
show(random.sum(10))
x: 1 3 10 1 3 2 8 6 7 9
[1] 50
However, when I try it for the next one which is 5, it won't work,
show(random.sum(5))
x: 7 5 6 2 9
[1] 529
I am not sure what I am doing wrong
The easiest way would be something like this (updated as per #Axeman's comment):
sum(sample(1:10, 10, replace = TRUE))
where the first "10" is your n and min and max define the value range for runif.
Also keep x local to the function:
random.sum <- function(n) {
x <- sample(1:10, 10, replace = TRUE)
cat("x:", x, "\n")
return(sum(x))
}
The reason for your error is the variable scoping rules of R. Your variable x in global scope is copied upon modification, but maintains the dimension of the global declaration. If you sum over only the first n elements with sum(x[1:n]) you will get the correct answer.
Now, that begs the question, are you trying to modify the global object x inside the function? If that is your intent, the superassignment operator <<- can be used. See the R intro section 10.5 "Assignments within functions" for details.
Let's say I want to multiply each even element of a vector by 2 and each odd element of a vector by 3. Here is some code that can do this:
v <- 0:10
idx <- v %% 2 == 0
v[idx] <- v[idx] * 2
v[!idx] <- v[!idx] * 3
This would get difficult if I had more than two cases. It seems like the apply family of functions never deals with vectors so I don't know a better way to do this problem. Maybe using an apply function would work if I made transformations on the data, but it seems like that shouldn't be something that I would need to do to solve this simple problem.
Any ideas?
Edit: Sorry for the confusion. I am not specifically interested in the "%%" operator. I wanted to put some concrete code in my question, but, based on the responses to the question, was too specific. I wanted to figure out how to apply some arbitrary function to each member of the list. This was not possible with apply() and I thought sapply() only worked with lists.
You can do:
v <- v * c(2, 3)[v %% 2 + 1]
It is generalizable to any v %% n, e.g.:
v <- v * c(2, 3, 9, 1)[v %% 4 + 1]
Also it does not require that length(v) be a multiple of n.
You can use vector multiplication to do what you want:
tmp <- 1:10
tmp * rep(c(3,2), length(tmp)/2)
This is easy to extend to three or more cases:
tmp * rep(c(3,2,4), length(tmp)/3)
Easiest would be:
v*c(2,3) # as suggested by flodel in a comment.
The term to search for in the documentation is "argument recycling" ... a feature of the R language. Only works for dyadic infix functions (see ?Ops). For non-dyadcic vectorized functions that would not error out with some of the arguments and where you couldn't depend on the structure of "v" to be quite so regular, you could use ifelse:
ifelse( (1:length(v)) %% 2 == 0, func1(v), func2(v) )
This constructs two vectors and then chooses elements in the first or second based on the truth value of hte first argument. If you were trying to answer the question in the title of your posting then you should look at:
?sapply
Here is an answer allowing any set of arbitrary functions to be applied to defined groups within a vector.
# source data
test <- 1:9
# categorisations of source data
cattest <- rep(1:3,each=3)
#[1] 1 1 1 2 2 2 3 3 3
Make the function to differentially apply functions:
categ <- function(x,catg) {
mapply(
function(a,b) {
switch(b,
a * 2,
a * 3,
a / 2
)
},
x,
catg
)
}
# where cattest = 1, multiply by 2
# where cattest = 2, multiply by 3
# where cattest = 3, divide by 2
The result:
categ(test,cattest)
#[1] 2.0 4.0 6.0 12.0 15.0 18.0 3.5 4.0 4.5