How do I solve a function for a given x? - r

I have been browsing through quite some help pages, but I did not find the solution for my - probably - simple problem.
I defined a function
funB <- function(x) (0.8042851 +
((3.9417843-0.8042851)/(1+((x/0.4039609)^(-3.285016)))))
and would like to solve it for a given x (say, x = 0.2).
How do I do that? I have looked at uniroot() and polyroot(), but they did not seem to fit my function.

Just to be sure that there is a root where you are expecting it, plot the graph of funB.
curve(funB)
Define an auxiliary function, f, taking an extra argument and solve this new function for a = <target_value>.
f <- function(x, a) funB(x) - a
uniroot(f, interval = c(0, 1e3), a = 2)
#$root
#[1] 0.3485097
#
#$f.root
#[1] -0.0001305644
#
#$iter
#[1] 12
#
#$init.it
#[1] NA
#
#$estim.prec
#[1] 6.103516e-05

If you wanted to find the value of x such that funB(x) was equal to 0.2, you would do something like this:
funB <- function(x) (0.8042851 +
((3.9417843-0.8042851)/(1+((x/0.4039609)^(-3.285016)))))
target <- 0.2
uniroot(function(x) funB(x)-target, interval=c(-5,10))
but there's a problem. It's up to you to pick an interval value that brackets a root (i.e. funB(x)<0.2 for the lower value and >0.2 for the upper value, or vice versa. funB is NaN for x<0, 0.8042851 for x==0, and increasing for x>0 (try curve(funB, from=-5, to=100, n=1001) for example). So the solution you want (if I've guessed right about the meaning of your question) doesn't seem to exist.
note: in general a negative value raised to a negative power is NaN in R (even in cases where the answer "should" be defined, e.g. (-8)^(1/3) is the cube root of -8, which is -2 ...). If you're sure you know what you're doing you could replace (x/a)^b with sign(x)*(abs(x)/a)^b) ... (if you make this change, the function appears well-behaved for x>-0.4 and funB(x)-0.2 does have a root between -0.3 and -0.2 ... but I have no idea if this makes sense for your application or not)

Well, I guess I must like doing things the hard way. I just rearranged your function to find its inverse:
funC <- function(y) (((3.137499)/(y - 0.8042851) - 1)^(-1/3.285016)) * 0.4039609
So if I want to know when funB(x) == 3.7 I can do:
funC(3.7)
#> [1] 0.860193
and sure enough
funB(0.860193)
#> [1] 3.7
or indeed
funB(funC(1))
#> [1] 1
And as others have pointed out, x doesn't have a real value at funB(x) == 0.2 as you can see in this plot:
curve(funC, 0, 4)
Now, if you really want to know the complex root where funB(x) == 0.2 then you can modify funC like so:
funC <- function(y) (((3.137499)/(as.complex(y) - 0.8042851) - 1)^(-1/3.285016)) * 0.4039609
So now:
funC(0.2)
#> [1] 0.1336917+0.1894797i
And therefore the answer to your question is 0.1336917 +/- 0.1894797i
funB(complex(real = 0.133691691, imaginary = 0.1894797))
[1] 0.1999996+0i
Close enough.

funB <- function(x) (0.8042851 + ((3.9417843-0.8042851)/(1+((x/0.4039609)^(-3.285016)))))
# call the function with desired input
funB(0.2)
...and the output:
> funB(0.2)
[1] 1.087758
>

Related

Give one possible input for a desired output value in R

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

Simple, why (-1)^(1/3) returns NaN when used in function? [duplicate]

I'm trying to see if there is a function to directly get the real cube root of a negative number. For example, in Java, there is the Math.cbrt() function. I'm looking for the equivalent in R.
Otherwise, my current hack is:
x <- -8
sign(x) * abs(x)^(1/3)
which is very inelegant and cumbersome to type every time. Thx!
Sounds like you just need to define your own Math.cbrt() function.
That will turn performing the operation from something inelegant and cumbersome to something clean, expressive, and easy to apply:
Math.cbrt <- function(x) {
sign(x) * abs(x)^(1/3)
}
x <- c(-1, -8, -27, -64)
Math.cbrt(x)
# [1] -1 -2 -3 -4
In R you probably need to define a new function that limits the results to your goals:
> realpow <- function(x,rad) if(x < 0){ - (-x)^(rad)}else{x^rad}
> realpow(-8, 1/3)
[1] -2
> realpow(8, 1/3)
[1] 2
It's possible to make an infix operation if you quote the operator and use surrounding "%" signs in its name. Because its precedence is low, you will need to use parentheses, but you already appear to know that.
> `%r^%` <- function(x, rad) realpow(x,rad)
> -8 %r^% 1/3
[1] -2.666667 # Wrong
> -8 %r^% (1/3)
[1] -2 #Correct
Agree with incorporating the questioner's version for its vectorized capacity:
`%r^%` <- function(x, rad) sign(x)*abs(x)^(rad)
In Java something like this :
There are 3 cube-roots. Assuming you want the root that is real, you should do this:
x = 8; // Your value
if (x > 0)
System.out.println(Math.pow(x, 1.0 / 3.0));
else
System.out.println(-Math.pow(-x, 1.0 / 3.0));

Is there an elegant, built-in way to do modulo indexing in R?

Currently, I have
extract_modulo = function(x, n, fn=`[`) fn(x, (n-1L) %% length(x) + 1L)
`%[mod%` = function (x, n) extract_modulo(x, n)
And then:
seq(12) %[mod% 14
#[1] 2
Is this already built into R somewhere? I would think so, because R has several functions that recycle values (e.g., paste). However, I'm not finding anything with help('[['), ??index, or ??mod. I would think an R notation for this would be something like seq(12)[/14/] or as.list(seq(12))[[/14/]], for example.
rep_len() is a fast .Internal function, and appropriate for this use or when recycling arguments in your own function. For this particular case, where you're looking for the value at an index position beyond the length of a vector, rep_len(x, n)[n] will always do what you're looking for, for any nonnegative whole number 'n', and any non NULL x.
rep_len(seq(12), 14)[14]
# [1] 2
rep_len(letters, 125)[125]
# [1] "u"
And if it turns out you didn't need to recycle x, it works just as fine with an n value that is less than length(x)
rep_len(seq(12), 5)[5]
# [1] 5
rep_len(seq(12), 0)[0]
# integer(0)
# as would be expected, there is nothing there
You could of course create a wrapper if you'd like:
recycle_index <- function(x, n) rep_len(x, n)[n]
recycle_index(seq(12), 14)
# [1] 2

comparing two numerical variables in R

I have run the R function stl() function and use its generated residuals for grubbs test. The code is the following:
stl.res = stl(dataset, s.windows='periodic')
residuals = as.numeric(strl.res$time.series[, "remainder"])
grubbs.result = grubbs.test(residuals)
strsplit(grubbs.result$alternative," ")[[1]][3]
## [1] "38.4000349179783"
outlier = as.numeric(strsplit(grubbs.result$alternative," ")[[1]][3])
outlier
## [1] 38.40003492
which(residuals == outlier)
## integer(0)
My question is why the return value of which() is 0. Actually residuals[1920] = 38.4000349179783. So the call of which() should return a value of 1921, not 0. I guess this is a problem with precision. I have tried many ways, but not managed to solve it.
If it's really a precision issue (which would be R FAQ 7.31), then there are various ways to get around it.
# this is an approximation of your test
x <- c(1, 2, 38.4000349179783, 4, 5)
y <- 38.40003492
> x == y
[1] FALSE FALSE FALSE FALSE FALSE
# so which doesn't return anything
# one basic approach
> which(abs(x - y) < .00001)
[1] 3
You could also rig up something using all.equal(), but checking for a difference less than your pre-selected limit is probably easiest.
Maybe you can use isTrue() and all.equal() as below:
which(sapply(residuals, function(v) isTrue(all.equal(v,outlier))) == T)

How to apply a function to each element of a vector in R

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

Resources