How do I assign with square brackets in R? - r

I have the following problem. I want to assign with square brackets, but the assign function won't let me do it. The following code is an example from the R documentation for the assign function.
a <- 1:4
assign("a[1]", 2)
a[1] == 2 # FALSE
get("a[1]") == 2 # TRUE
I want to access a[1] so that a[1] == 2 becomes TRUE. Instead, the assign function creates an object called "a[1]". How do I fix this problem? Are there alternatives? Thank you in advance.

Related

NA values as conditions on a IF statement in R

My goal is to categorize the rows on my dataset depending on the values of two different dates.
if(!exists(MY_DATA$Date_1) & exists(MY_DATA$Date_2)) {
MY_DATA$NEW_COL <- c("Category_1")
} else {
MY_DATA$NEW_COL <- c("Category_2")
}
But it isn't working, I'm currently trying a simplified version as follows:
if(!exists(MY_DATA$Date_1)){
MY_DATA$NEW_COL <- c("Category_1")
}
However, it seems that this only reads the value on the first row, and it either gives me a column with all values as Category_1 or no column at all.
Also I have tried this with is.na(), is.null() and exists().
However, it seems that this only reads the value on the first row, and it either gives me a column with all values as Category_1 or no column at all.
This is because if statement requires a vector of length 1. When given a vector with length more than 1, it will only read the first member to make the decision TRUE or FALSE.
The ifelse function can accept vector argument and will return a vector of logical TRUE/FALSE. It may be suitable for your needs.
Rephrasing originally a comment by #r2evans, the use of exists() is to check if a variable is already defined in the R environment. exists() takes a character vector of length 1 as argument, otherwise it will check only the first member.
a = 1
b = 1
exists("a")
[1] TRUE
exists(c("a", "b"))
[1] TRUE
exists(c("ab", "a", "b"))
[1] FALSE
However it's worth noting that exists() does not check if a value is inside a vector. If you are trying to check if a value is in a vector, you'll want operator %in% instead.
The solution will largely depend on your precise implementations.
p.s. This is originally intended as a comment, but is too long as a comment.
Thanks everyone for your support, ifelse did the trick.
The following worked for me:
MY_DATA$NEW_COL <- c("Category_2")
MY_DATA$NEW_COL <- ifelse(!is.na(MY_DATA$Date_1),"Category_1","Category_2")

for loop with if statements (both iterates over a list) gave warnings in r

I have two lists, each list contains two vectors i.e,
x <- list(c(1,2),c(3,4))
y <- list(c(2,4),c(5,6))
z <- list(c(0,0),c(1,1), c(2,3),c(4,5))
I would like to use for loop to iterate over the first list and if statement for the second list as follows:
for (j in 1:seq(x)){
if(y[[j]] == c(2,4))
z[[j]] <- c(0,0)
}
I would like to iterate over the first list and for each iteration I would like to give a condition for the second list. My function is complex, so I upload this example which is similar to what I am trying to do with my original function. So that is, I would like to choose the values of z based on the values of y. For x I just want to run the code based on the length of x.
When I run it, I got this message:
Warning messages:
1: In 1:seq(x) : numerical expression has 2 elements: only the first used
2: In if (y[[j]] == c(2, 4)) y[[j]] <- c(0, 0) :
the condition has length > 1 and only the first element will be used
I search this website and I saw similar question but it is not helpful (if loop inside a for loop which iterates over a list in R?). This question is just for the first part my question. So, it does not help me with my problem.
any help please?
The first warning is caused by using seq() which returns a [1] 1 2 in combination with the colon operator which creates a sequence between the LHS and RHS. Both values on the left and right of the colon must be of length 1. Otherwise it will take the first element and discard the rest. So 1:seq(x) is the same as writing 1:1
The second warning is that the if statement gets 2 logical values from your condition:
y[[1]] == c(2, 4)
[1] TRUE TRUE
If you want to test if elements of the vector are the same you can use your notation. If you want to test if the vectors are the same, you can use all.equal.
isTRUE(all.equal(y[[1]], c(2,4)))
[1] TRUE
It returns TRUE if vectors are equal (but not FALSE if they are not, which is why it needs to be used along with isTRUE()).
To get rid of the warnings, you can do:
for (j in seq_along(x)){
if (isTRUE(all.equal(y[[j]], c(2,4)))) {
z[[j]] <- c(0,0)
}
}
Note: seq_along() is a fast primitive for seq()
For the first part, seq() will returns [1] 1 2. So, you need to use j in seq(x) or j in 1:length(x).
and for the second part, as the command you used generates TRUE and FALSE as many as the elements in the vectors, you can use setequal(x,y). This command will check whether two objects are equal or not. two objects can be vectors, dataframes, etc, and the result is TRUE or FALSE.
The final code can be:
for (j in 1:length(x)){
if (setequal(y[[j]], c(2,4)) == TRUE) {
z[[j]] <- c(0,0)
}
}
or:
for (j in seq(x)){
if (setequal(y[[j]], c(2,4)) == TRUE) {
z[[j]] <- c(0,0)
}
}

How to use lapply in R to evaluate elements of a list?

My apologies if this has been answered somewhere else. I've defined two functions in R and then nested them with good results. Now I would like to evaluate these two nested functions by changing a variable in the second function. I've tried creating a list for the changing variable and then using lapply to evaluate each element, but I'm getting an error.
My code looks something like this:
# First function
FirstFun <- function(a, b, c, d) {
answer1 <- (a + b)/(1-(0.2*(c/d))-(0.8*(c/d)^2))
return(answer1)
}
# First function evaluated
FirstFun(13,387,1728,1980)
# Second function
SecondFun <- function(answer1,c,d) {
answer2 <- answer1*(1-(0.2*(c/d))-(0.8*(c/d)^2))
return(answer2)
}
# Nested function evaluated
SecondFun(FirstFun(13,387,1728,1980),1728,1980)
# Nested function evaluated with elements of a list
c <- list(0:1980)
lapply(c, SecondFun(FirstFun(13,387,1728,1980),c,1980))
if I under stand you correctly - you are looking for :
SecondFun(FirstFun(13,387,1728,1980),0:1980,1980)
or maybe this :
SecondFun(FirstFun(13,387,1728,0:1980),0:1980,1980)
both return a numeric vector of length 1981.
2 things -
1. no need for a list. a range would work.
2. calling a variable 'c' is a bad idea..... c is reserved

Assign to list index in specific environment using `get`

If I make an environment with a list in it, and want to assign values to that list, why does the following fail when using get and assign?
res <- new.env()
res$calls <- vector("list", 100)
res$counter <- 1
## works fine
res$calls[[1]] <- 1
## Fails, why?
get("calls", envir=res)[[get("counter", envir=res)]] <- 2
## doesnt make the assignment
val <- get("calls", envir=res)[[get("counter", envir=res)]]
assign("val", 2, envir=res)
I think the following will address your issue:
get("calls", envir=res)[[get("counter", envir=res)]] <- 2 fails because get is not a replacement function. On the other hand res$calls[[1]] <- 1 is actually a replacement function which you can see if you type help('[[<-'). This is the function used when you make an assignment. I think the reason why get has no replacement counterpart i.e. (get<-) is that there is a specific function to do this, which is called assign (as per #TheTime 's comment).
For the second case val <- get("calls", envir=res)[[get("counter", envir=res)]] is created in the global environment. When you use assign("val", 2, envir=res) a res$val variable is created inside the res environment which you can see below:
> res$val
[1] 2
However, val remains the same on the global environment as 1:
> val
[1] 1
So, You probably won't be able to do the assignment with either get or assign. get won't allow it because it is not a replacement function and ?assign mentions:
assign does not dispatch assignment methods, so it cannot be used to set elements of vectors, names, attributes, etc.
So, you can just use the normal [[<- assignment method. #Frank in the comments provides a nice way like:
res[[ "calls" ]][[ res[["counter"]] ]] <- 2

Vector with elements equal to a function evaluated at a, a+1,... b .in R

I have two integers a and b (with a less than b), as well as a function f(x). Is there a way of getting the vector
x<-(f(a), ..., f(b))
from R without having to explicitly having to write it out? as my a and b vary.
Thanks for your help.
You can try something like the following :
foo <- function(x) x+1
a <- 1
b <- 5
sapply(a:b, foo)
But note that if you need this kind of behavior, you should vectorize your function, ie make it accept a vector as argument instead of a single integer. In my previous example, the sapply is not needed at all : + is vectorized, so I can just do :
foo(a:b)

Resources