How to use "if" within "apply" #2

I appreciate your help. I am still a very bigger with a lot of curiosity in R. I do know I must study by myself a lot more, but if you could spare your time, it would be a big help. I spent almost four days with this problem... anyway...

Conditions
There are two parameters.

a: ability
d: difficulty

The initial values of them are zero.

ability <- 0
difficulty <- 0

Both parameters will be repeatedly updated according to the gained response from x, y, and z.

If the response is 1, one will be added to a and one will be subtracted from b based on the previous value.
If the response is 0, one will be subtracted from a and one will be added to b based on the previous value.

if the response is 1: a^ = a + 1, b^ = b - 1
if the response is 0: a^ = a - 1, b^ = b + 1

Now I have a data set below.

x    y    z
1    0    0
1    1    0
1    1    0

At the end, applying the condition, the results of data (x, y, and z) should be like below:

x: a^ = 3, b^ = -3 [1, 1, 1]
y: a^ = 1, b^ = -1 [0, 1, 1]
z: a^ = -3, b^ = 3 [0, 0, 0]

To achieve this in R, I wrote the codes like below with very limited knowledge, but I only got a failure with warning messages.

ability <- 0
difficulty <- 0
res <- apply(data, 2, function(x, a = ability, d = difficulty){
	for (i in 1:3)
		if (x == 1){
			a[i] <- a+1
			d[i] <- d-1
		}
		else {
			a[i] <- a-1
			d[i] <- d+1
		}
		return(c(x, a, d))
	}
)

The warning messages I got are below:

1: In if (x == 1) { ...
the condition has length > 1 and only the first element will be used

I feel like I must use "ifelse" statement, but I do know how to apply it to this case (return data format).

I appreciate your help. Thank you in advance.

please look at this example, and see how it works. I think it will help


x<- c(1,0)
mycondition <- function(x){ifelse(x==0,"no","yes")}
simpletest <- mycondition(x)
  
myframe <- data.frame(y=(c(1,0,0)))

for(i in 1:3) {
  myframe$res[[i]] <- mycondition(myframe$y[[i]])
}
myframe
1 Like

Thank you very much for your quick advice, nirgrahamuk.

In this case, I would like to handle a set of simple calculation (not characters "Yes" or "No).
In addition, a result of calculation is to be updated based on the previous value, not simple replacement.

if the answer is 1: a+1 & d-1 is conducted.
if the answer is 0: a-1 & d+1 is conducted.

Based on your sample (data.frame), 1, 0, 0, a and d values are repeatedly updated like this.

1: a = 1, d = -1
0: a^ = a -1 = 1-1 = 0, d^ = d + 1= -1 + 1= 0
0: a^^= a^ -1 = 0 - 1 = -1, d^^ = d^ + 1 = 0 + 1 = 1

As the result, the final score of two values:

a = -1
d = 1

This is what I want to achieve. Following your advice, I tried, but, no success,,,

x <- c(1, 0)
a <- 0
d <- 0
mycondition <- function(x){ifelse(x == 0, a-1&d+1, a+1&d-1)}
simpletest <- mycondition(x)

myframe <- data.frame(y=c(1, 0, 0))

for(i in 1:3) {
  myframe$res[[i]] <- mycondition(myframe$y[[i]])
}
myframe
  y  res
1 1 TRUE
2 0 TRUE
3 0 TRUE

i called my stuff a and b instead of a and d...
anyway,
my approach is first calculate whether a variable should increase or decrease, then cumulatively sum the results of these increments.

x <- c(1, 0)

condition_a <- function(x){ifelse(x == 0, -1, 1)}
condition_b <- function(x){ifelse(x == 0, 1, -1)}
simpletest_a <- condition_a(x)
simpletest_b <- condition_b(x)
simpletest_a
simpletest_b
myframe <- data.frame(y=c(1, 0, 0))

for(i in 1:3) {
  myframe$a_inc[[i]] <- condition_a(myframe$y[[i]])
  myframe$b_inc[[i]] <- condition_b(myframe$y[[i]])
}

myframe

myframe$a <- cumsum(myframe$a_inc)
myframe$b <- cumsum(myframe$b_inc)

myframe
1 Like

I wouldn't have been able to reach at this stage without your kind help. I was excited to see how you deal with the process. I read lines many many times and studied a lot. Many many new things I learned. Thank you very much indeed.

I redesigned the codes to deal with the data.frame with three columns.

#conditions
res <- c(1, 0)
condition_a <- function(res){ifelse(res == 0, -1, 1)}
condition_b <- function(res){ifelse(res == 0, 1, -1)}
simpletest_a <- condition_a(res)
simpletest_b <- condition_b(res)

#column x
myframe.x <- data.frame(x=c(1, 1, 1))
for(i in 1:3) {
  myframe.x$a_inc[[i]] <- condition_a(myframe.x$x[[i]])
  myframe.x$b_inc[[i]] <- condition_b(myframe.x$x[[i]])
}
myframe.x$a <- cumsum(myframe.x$a_inc)
myframe.x$b <- cumsum(myframe.x$b_inc)

#column y
myframe.y <- data.frame(y=c(0, 1, 1))
for(i in 1:3) {
  myframe.y$a_inc[[i]] <- condition_a(myframe.y$y[[i]])
  myframe.y$b_inc[[i]] <- condition_b(myframe.y$y[[i]])
}
myframe.y$a <- cumsum(myframe.y$a_inc)
myframe.y$b <- cumsum(myframe.y$b_inc)

#column z
myframe.z <- data.frame(z=c(0, 0, 0))
for(i in 1:3) {
  myframe.z$a_inc[[i]] <- condition_a(myframe.z$z[[i]])
  myframe.z$b_inc[[i]] <- condition_b(myframe.z$x[[i]])
}
myframe.z$a <- cumsum(myframe.z$a_inc)
myframe.z$b <- cumsum(myframe.z$b_inc)

#output
myframe.x
myframe.y
myframe.z

I have two questions. Sorry for this.

In my sample, except the condition part, almost the same codes were repeated to deal with x, y, and z.
Considering the future case with more samples, is there any way to deal with these three values with one set?
Another question is about value z. If the set of responses is all zero (z=c(0, 0, 0). The b parameter is not calculated correctly.

> myframe.z
  z a_inc b_inc  a  b
1 0    -1       -1 NA
2 0    -1       -2 NA
3 0    -1       -3 NA

Thank you very much for your help and kind advice.

for(i in 1:3) {
  myframe.z$a_inc[[i]] <- condition_a(myframe.z$z[[i]])
  myframe.z$b_inc[[i]] <- condition_b(myframe.z$x[[i]])
}

In the application of condition_b(), you have a typo: You're supply data from a column called x, which doesn't exist.

1 Like

here is one step towards more automated / less repetition of code

library(tidyverse)
myframe <- data.frame(x=c(1, 1, 1),
                        y=c(0, 1, 1),
                        z=c(0, 0, 0))

condition_a <- function(res){ifelse(res == 0, -1, 1)}
condition_b <- function(res){ifelse(res == 0, 1, -1)}

myframe.a<- mutate_all(myframe,
           ~condition_a(.))

myframe.a<- mutate_all(myframe.a,
                       cumsum)
names(myframe.a) <- paste0("a_",names(myframe.a))
myframe.b <- mutate_all(myframe,
           ~condition_b(.))
myframe.b<- mutate_all(myframe.b,
                       cumsum)
names(myframe.b) <- paste0("b_",names(myframe.b))
bind_cols(myframe,myframe.a,myframe.b)
1 Like

here is further...

library(tidyverse)
myframe <- data.frame(
  x = c(1, 1, 1),
  y = c(0, 1, 1),
  z = c(0, 0, 0)
)

condition_a <- function(res) {
  ifelse(res == 0, -1, 1)
}
condition_b <- function(res) {
  ifelse(res == 0, 1, -1)
}


perform_calc <- function(indata, incondition, inname) {
  temp <- mutate_all(indata,~incondition(.))
  temp <- mutate_all(temp,cumsum)
  names(temp) <- paste0(inname, "_", names(temp))
  temp
}

perform_calc(myframe, condition_a, "a")
perform_calc(myframe, condition_b, "b")
1 Like

Thank you very much, dromano. I should have been more careful and double checked.

Thank you very much indeed, nirgrahamuk. That's what I wanted to do. I am reading the codes many times and have been studying referencing with some new packages and grammar that you introduced me with two samples.

Thank you very much!!!!!!!!!

you're very welcome. before long you will be helping others here :slight_smile:

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.