if...else statement runs both parts of the code - r

I need my code to check a vector to see if any of the values are negative and return an error if one or more are. If none are negative, I need it to find the geometric mean of the values. The problem is when there are negative values my code is giving both the error message and the geometric mean, which I don't want to have happen.
gm=function(x){
n=length(x)
for(i in 1:n){
if(x[i]<0){
cat("ERROR: x value is negative")
break
}else{
y=prod(x)^(1/n)
}
}
y
}
gm(x)

You should avoid looping through a vector and checking a condition. Instead, you could use any to check if the condition holds for any of the elements of the vector:
gm <- function(x) {
if (any(x < 0)) {
stop("x contains a negative element")
} else {
prod(x)^(1/length(x))
}
}
You can see it in action:
gm(c(4, 16))
# [1] 8
gm(c(-4, 16))
# Error in gm(c(-4, 16)) : x contains a negative element

Related

Square root of a vector using tryCatch statement

I want to write a function that returns the square root of vector x. I want it to have a tryCatch statement so that when x equals a negative number, it returns x as is and also issues a warning statement that x has negative numbers. The output should say NaN. So far I have this:
sqrt_x<-function(x){
if (x<0){
warning("x is negative")
}
Where do I put the tryCatch statement?
Another attempt at writing this function is here:
sqrt_x<- function(x){
tryCatch(
expr={
sqrt(any(x))
},
warning=function(w){
message("x is negative")
print(w)
}
)
}
Got it! Thank you all for your help
sqrt_x<-function(x){
result <-
tryCatch({
sqrt(x)},
warning = function(w) {
warning('x contains negative numbers')
x
})
return (result)
}

Error code Missing value where TRUE/FALSE needed in R

I keep getting this error message when I run my code, and I'm not sure what I need to do to fix it.
My code is as follows:
gwmh<-function(target,N,x,sigmasq){
p<-add.var()
samples<-c(x,p)
for(i in 2:N){
prop<-rnorm(1,0,sqrt(sigmasq))
if(runif(1)<min(1,(target(x+abs(prop)*p))/target(x))){
x<-x+prop
samples<-rbind(samples,c(x,p))} else{
p<--p
samples<-rbind(samples,c(x,p))
}
}
samples[(1:N)] ##delete after testing
}
The error says:
Error in if (runif(1) < min(1, (target(x + abs(prop) * p))/target(x))) { :
missing value where TRUE/FALSE needed
(add.var is a function i created to generate p in {-1,1} randomly)
I tested my comment and feel more comfortable offering it as an answer.
Try the following
if(TRUE){print("Test")}
# prints "Test"
if(FALSE){print("Test")}
# prints nothing
if(NA){print("Test")}
# throws your error
So within this expression:
runif(1)<min(1,(target(x+abs(prop)*p))/target(x))
the result is neither TRUE or FALSE but NAand seeing as runif()should not throw any missings it has to be in the rhs of the comparison.
Assuming that target, x, and sigmasq are all values from a df and not functions there is probably a missing value there. If this is the case and also intended you have to add an exception for catching and handling these missings that might look like this:
# test being your test expression
if(
if(is.na(test) {Do Stuff for missing values}
else {original IF statement}
You need to add na.rm=TRUE to the min function to account for possible NA in x.
Your function will fail if x contains NA.
target <- function(x) dnorm(x, 0, 1)
add.var <- function() runif(1, -1, 1)
gwmh <- function(target,N,x,sigmasq){
p <- add.var()
samples<-c(x,p)
for(i in 2:N){
prop<-rnorm(1,0,sqrt(sigmasq))
if(runif(1) < min(1, (target(x+abs(prop)*p))/target(x), na.rm=TRUE)){ # <- Here
x<-x+prop
samples<-rbind(samples,c(x,p))} else{
p<--p
samples<-rbind(samples,c(x,p))
}
}
samples[(1:N)] ##delete after testing
}
Now try:
gwmh(target, N=2, x=c(1,2,NA,3), sigmasq=2)
# [1] 1.00 3.14

Why does this work as a for loop but not within a function?

I'm trying to write a function that identifies if a number within a numerical vector is odd or even. The numerical vector has a length of 1000.
I know that the for loop works fine, and I just wanted to generalize it in the form of a function that takes a vector of any length
out<-vector()
f3<- function(arg){
for(i in 1:length(arg)){
if((arg[i]%%2==0)==TRUE){
out[i]<-1
}else{out[i]<-0
}
}
}
When run within a function, however, it just returns a NULL. Why is that, or what do I need to do to generalize the function work with any numerical vector?
As already mentioned by PKumar in the comments: Your function doesn't return anything, which means, the vector out exists only in the environment of your function.
To change this you can add return(out) to the end of your function. And you should also start your function with creating out before the loop. So your function would look like outlined below.
Note, that I assume you want to pass a vector of a certain length to your function, and get as a result a vector of the same length which contains 1 for even numbers and 0 for odd numbers. f3(c(1,1,2)) would return 0 0 1.
f3 <- function(arg){
out <- vector(length = length(arg), mode = "integer")
for(i in 1:length(arg)){
if((arg[i]%%2==0)==TRUE){ # note that arg[i]%%2==0 will suffice
out[i]<-1
} else {out[i]<-0
}
}
return(out) # calling out without return is enough and more inline with the tidyverse style guide
}
However, as also pointed out by sebastiann in the comments, some_vector %% 2 yields almost the same result. The difference is, that odd numbers yield 1 and even numbers 0. You can also put this into a function and subtract 1 from arg to reverse 0 and 1 :
f3 <- function(arg){
(arg-1) %% 2
}
A few thing to note about your code:
A function must return something
The logical if((arg[i]%%2==0)==TRUE) is redundant. if(arg[i]%%2==0) is enough, but wrong, because arg[i] does not exist.
the length(arg) is the length(1000) which, if ran, returns 1
You should change arg[i] with i and assign to i all the values from 1:1000, as follows:
R
out <-vector()
f3 <- function(arg){
for(i in 1:arg){
if(arg[i] %% 2 == 0){
out[i] <- 1
}
else{
out[i] <- 0
}
}
return(out)
}
f3(1000)

Why would this 'sapply' function in R return an invalid response given my function?

CountNew <- function(x){
if (x==0) y <- 1
return(y)
}
allCF$NewECount >- sapply(allCF$Count, CountNew)
Using the above code, if a value in EquipCount in allCF is currently equal to 0, I want to change it to 1 while keeping the other values the same, then maintain the values of the rest of the values not equal to 0. I made sure these were numbers (not factors) through the str(rawCF) command
But then I get the following error:
Error in FUN(X[[i]], ...) : object 'y' not found
What is causing this problem?
The code logic is wrong.
What if the element does not satisfy x==0? The function will return a y which is not defined. Add one line will solve it:
Solution 1
allCF <- data.frame(Count=c(0,0,-1))
CountNew <- function(x){
y=x
if (x==0) y = 1
return(y);
}
allCF$NewECount <- sapply(allCF$Count, CountNew)
Solution 2: Vectorize your CountNew function
allCF <- data.frame(Count=c(0,0,-1))
CountNew <- Vectorize(function(x){
if (x==0) return(1);
return(x);
}
)
allCF$NewECount <- sapply(allCF$Count, CountNew)
Now you may do CountNew(allCF$Count) directly.

Write a function in R to find perfect numbers

I am a beginner in R and am attempting the following question:
Create a function in R which takes as its
input a natural number N and returns as an output the list of
all perfect numbers between 1 and N.
There are 3 steps here:
1. Check the list of factors
2. Check whether it is a perfect number
3.check from 1 to 10000
factorlist<-function(n){
if(n<2){return("Invalid Input")}
if(n%%1!=0){return("Invalid Input")}
vec<-0
for(i in 1:(n-1)){
if(n%%i==0){
vec[length(vec)]<-i
vec<-c(vec,0)
}
}
vec<-vec[-length(vec)]
return(vec)
}
perfectcheck<-function(n){
if(n-sum(factorlist(n)) ==0) {return("Perfect Number")}
else{return("Not Perfect Number")}
}
perfectcheckN<-function(N){
for(i in 1:N){
if(perfectcheck(i)=="Perfect Number"){
vec[length(vec)]<-i
vec<-c(vec)
}
}
vec<-vec[-length(vec)]
return(vec)
}
and i got the following error for my third step
Error in sum(factorlist(n)) : invalid 'type' (character) of argument
I spent like few hours and still could not figure out my mistake, please help. Thanks!
The output of factorlist(i) is character when i==1.
There's a lot of loops and ifs in your code. You can just do
facs <- function (x) {
x <- as.integer(x)
div <- seq_len(abs(x) - 1L)
div[x%%div == 0L]
}
perfectcheckN <- function(N){
out <- 1:N
out[sapply(out, function(x) x == sum(facs(x)))]
}

Resources