I write a R function using if & else if in it. See the code below:
i_ti_12 <- function(x){
if (x <= 44)
{ti = exp(-13.2238 + 0.152568*x)}
else if (x >= 49)
{ti = -0.01245109 + 0.000315605*x}
else (x > 44 & x < 49)
{ti = (x-44)*(i_ti_12(49))/(49-44) + (49-x)*(i_ti_12(44))/(49-44)}
return(ti)
}
I want to use this function's output, i_ti_12(49) within this function, but the above code doesn't work. The output is:
> i_ti_12(49)
Error: C stack usage 7974292 is too close to the limit
The simple solution is just replace i_ti_12(49) by -0.01245109 + 0.000315605*49, but its not a clear way to solve it and might not work in complex cases.
So I really want to know and to learn if there are clear methods to do this? I mean, like above simple example, write a conditional function using one condition's output in this function. Any help is highly appreciate.
Your last else is followed by a condition (x > 44 & x < 49), which actually is not correct. If you have (x > 44 & x < 49) there, that means you will execute that statement, and ti = (x-44)*(i_ti_12(49))/(49-44) + (49-x)*(i_ti_12(44))/(49-44) is something independent with your if-else structure.
In that case, when you call i_ti_12(49), your function does not know when the recursion should be terminated since you did not define that case.
You can try the code below:
i_ti_12 <- function(x){
if (x <= 44)
{ti = exp(-13.2238 + 0.152568*x)}
else if (x >= 49)
{ti = -0.01245109 + 0.000315605*x}
else
{ti = (x-44)*(i_ti_12(49))/(49-44) + (49-x)*(i_ti_12(44))/(49-44)}
return(ti)
}
such that
> i_ti_12(49)
[1] 0.003013555
Related
I am attempting to translate the function DISCRINV() which is an excel function available in the simtools excel add-in that was created by Roger Myerson into an R function. I believe i am close, but am having difficulty understanding the looping syntax of VBA.
The VBA code for this function is as follows:
Function DISCRINV(ByVal randprob As Double, values As Object, probabilities As Object)
On Error GoTo 63
Dim i As Integer, cumv As Double, cel As Object
If values.Count <> probabilities.Count Then GoTo 63
For Each cel In probabilities
i = i + 1
cumv = cumv + cel.Value
If randprob < cumv Then
DISCRINV = values.Cells(i).Value
Exit Function
End If
Next cel
If randprob < cumv + 0.001 Then
DISCRINV = values.Cells(i).Value
Exit Function
End If
63 DISCRINV = CVErr(xlErrValue)
End Function
Attempting to translate this directly from the VBA code i have come up with this (Not Correct):
DISCRINV <- function(R,V,P){
if(length(V) != length(P)){
print("ERROR NUMBER OF VALUES DOES NOT EQUAL NUMBER OF PROBABILITIES")
} else{
for (i in 1:length(P)){
cumv=cumv+P[i]
if (R < cumv){
DISCY1 = V[i]
return(DISCY1)
}
print(cumv)
if (R < cumv +0.001){
DISCY2 = V[i]
return(DISCY2)
}
}
}
}
Attempting to translate this through my understanding of what it is doing i have come up with this:
DISCRINV <- function(x,values,probabilities){
require(FSA)
precumsum <- pcumsum(probabilities)
middle <- c()
for (i in 1:(length(values)-2)){
if (precumsum[i+1] <= x & x < precumsum[i+2]){
middle[i] <- values[i+1]}
else{
middle[i] <- 0
}
}
firstrow <- ifelse(x < precumsum[2], values[1], 0)
lastrow <- ifelse(precumsum[length(precumsum)] <= x , values[length(precumsum)] , 0)
Gvector <- c(firstrow,middle,lastrow)
print(firstrow)
print(middle)
print(lastrow)
print(Gvector)
simulatedvalue <- sum(Gvector)
return(simulatedvalue)
}
The latter option works 99% of the time, but not when the first function parameter is over 0.5, the second parameter is a vector of values c(1000,2000) and the third parameter is a vector (0.5,0.5). The case of the latter option not working 100% of the time is what has led me to try to translate the function directly. Could someone please give some insight into where my translation is going wrong?
Additionally a description of the function is as follows:
DISCRINV(randprob, values, probabilities) returns inverse cumulative values for a discrete random variable. When the first parameter is a RAND, DISCRINV returns a discrete random variable with possible values and corresponding probabilities in the given ranges.
Thank you in advance for the insight!
For anyone that is interested, i was able to successfully translate this VBA script using this code
DISCRINV <- function(x,values,probabilities){
require(FSA)
precumsum <- pcumsum(probabilities)
middle <- c()
if(length(values <3 )){
if(x<0.5){
middle1 <- values[1]
return(middle1)
} else{
middle2 <- values[2]
return(middle2)
}
}
else{
for (i in 1:(length(values)-2)){
if (precumsum[i+1] <= x & x < precumsum[i+2]){
middle[i] <- values[i+1]}
else{
middle[i] <- 0
}
}
firstrow <- ifelse(x < precumsum[2], values[1], 0)
lastrow <- ifelse(precumsum[length(precumsum)] <= x , values[length(precumsum)] , 0)
Gvector <- c(firstrow,middle,lastrow)
print(firstrow)
print(middle)
print(lastrow)
print(Gvector)
simulatedvalue <- sum(Gvector)
return(simulatedvalue)
}
}
y <- as.integer(readline(prompt ="Enter a number: "))
factorial = 1
if (y< 0){
print("Error")
} else if (y== 0)
{
print("1")
} else
{
for(i in 1:y) {
factorial = factorial * i
}
return(factorial)
}
wondering why this is giving:
Error in if (y< 0) { : missing value where TRUE/FALSE needed
is it cause the first line has data type NA_integer?
There are three possible ways to pass values to the if statement.
y <- 1
if (y > 0) print("more")
This one works as expected.
y <- 1:3
if (y > 0) print("ignores all but 1st element")
As the warning message will tell you, only the first element was used to evaluate it. You could use any or all to make this right.
y <- NA
if (y > 0) print("your error")
This case actually gives you your error. I would wager a bet that y is somehow NA. You will probably need to provide a reproducible example (with data and the whole shebang) if you'll want more assistance. Note also that it helps visually structure your code to improve readability.
In the below R function, I was wondering how I could get R to evaluate whether the object input outputs n or es?
Note: I will need to know the exact output of input, so I canNOT be using identical() etc.
Here is what I have tried with no success:
d = function(n, es){
input = if(length(n) > 1) n else if(length(es) > 1) es else n
if(input == n) cat("yes") else cat("No") # IF `input` is `n` cat("yes") otherwise cat("no")
}
d(n = c(2, 3), es = 1)
try to use if(identical(n, input)) cat("yes") else cat("No"). == cannot be
This might be a silly question, but since I could not find the way to search it, I wanted to ask. I have the code below:
(m is a numeric value defined earlier)
if (0 < m <= 1.00){
print("a")
} else if (1.00 < m <= 2.00){
print("likely benign")
} else if (2.00 < m <= 3.00){
print("b")
} else if (3.00 < m <= 4.00){
print("c")
} else if (4.00 < m <= 5.00){
print("d")
} else if (5.00 < m <= 6.00){
print("e")
} else{
print("f")
}
It gives the error:
Error: unexpected '}' in " }"
but I used if in exactly the same way on the upper part of the code and there is no error from that part. How can I fix this? Thanks in advance.
We need to change the syntax to &
if(0 < m & m <= 1.00){
---
and also in all the else if conditions.
It is not clear whether m is of length 1 or >1. If it is length 1, use the & and if greater than 1, it may be better to use ifelse instead of if/else or if we are using if/else, use && instead of & as #ZheyuanLi suggested in the comments.
Please can anyone advise how I can turn the following statement into one that will do the same thing but NOT using ifelse please?
<-ifelse(y>=50, 0.2*x+0.8*y, ifelse(y<50 & x>70, y+10, ifelse(y<50 & x<70, y)))
x=80
y=60
So I the final code should give an answer of 64 - selecting the first condition. I will then test it to ensure the other 3 conditions give the correct result for varying values of x and y
Thanks a lot.
This should work:
finalmark <- (x * 0.2 + y * 0.8) * (y >= 50) + (y + 10 * (x > 70)) * (y < 50)
Something like this?
if(y>=50){
0.2*x+0.8*y
}else{
if(y<50 & x>70){
y+10
}else{
if(y<50 & x<70){
y
}else{
"OMG I did not expect this scenario"
}
}
}
try: y=45; x=70 to see why I have the last condition.
If y is a number then, once you've tested for y > = 50 then y must be less than 50 so don't keep testing for that. Similarly, once you've found x > 70 then you don't need the last ifelse. You don't have a return for x = 70. My guess is that you want to test for a <= or >= situation there.
ifelse(y>=50, 0.2*x+0.8*y, ifelse(x>70, y+10, y))
in scalar that's
if(y >= 50){
0.2*x+0.8*y
}else if(x > 70){
y+10
}else y
Given you seem to be having a hard time in general writing the logic I suggest you post a more complete question. It's possible (probable) that you're doing something here that you really don't want to do.
There are several approaches you can take. Below are a few examples of building a function 'f', so that 'f(x,y)' meets your criteria listed in the question using logic other than 'ifelse' statements.
Note: I'm also adding in one amendment to the original post, since 'x=70' would break the logic. I'm adding 'x>=70' to the second criterion.
Option 1: Use a standard 'if / else if / else' logic block. Personally, I like this option, because it's easily readable.
f <- function(x, y){
if (y>= 50){
return(0.2*x+0.8*y)
} else if (y < 50 & x >= 70){
return(y+10)
} else {
return(y)
}
}
Option 2: Combine your two logical tests (there are really only two) into a string, and use a switch. Note that the final and unnamed option is treated as an 'else'.
f <- function(x, y){
return(
switch(paste(x >= 70, y >= 50, sep=""),
TRUEFALSE = y + 10,
FALSEFALSE = y,
0.2*x+0.8*y
)
)
}
Option 3: Order your 'if' statements to reduce logical comparisons. This is the sort of thing to do if you have a large data set or very limited memory. This is slightly harder to troubleshoot, since you have to read the whole block to fully understand it. Option 1 is better if you don't have memory or cycle limitations.
f <- function(x, y){
if (y >= 50){
return(0.2*x+0.8*y)
} else {
if (x >=70){
return(y+10)
} else {
return(y)
}
}
}
There are other options, but these are the simplest that come readily to mind.