Sthln
Sthln

Reputation: 71

Calculate a row based on previous row in a loop without packages

I'm trying to create a loop (without the use of packages) to calculate the rows of an array. Each row of the matrix is calculated with one of the values of the previous row (in the code, the variable B, from the second line, is the value of the C variable of the previous line). My attempt is written below:

df=data.frame(matrix(ncol = 4, nrow = 5))
names(df)=c("A", "B", "C", "D")

for (i in 1:nrow(df){
  df$A<-c(0, 0.25, 0.50, 0.75, 1.00)
  df$B<-ifelse(df$A==0, 0, C[i-1])
  df$C<-df$A*df$B)+1
  df$D<-df$C+5
}
df

The expected result is:

     A    B    C    D
1 0.00 0.00 1.00 6.00
2 0.25 1.00 1.25 6.25
3 0.50 1.25 1.63 6.63
4 0.75 1.63 2.22 7.22
5 1.00 2.22 3.22 8.22

What am I doing wrong?

Upvotes: 0

Views: 692

Answers (1)

IceCreamToucan
IceCreamToucan

Reputation: 28675

Inside the loop, you have to subset the columns to the row you're working on (row i) for the given loop iteration. Otherwise you're doing assignment on the whole column each time and not just one row. Also, the creation of A and D don't need to be in the loop.

df$A <- c(0, 0.25, 0.50, 0.75, 1.00)
for(i in 1:nrow(df)){
  df$B[i] <- ifelse(df$A[i] == 0, 0, df$C[i-1])
  df$C[i] <- df$A[i]*df$B[i] + 1
}
df$D <- df$C + 5

You can also do this using Reduce, but there's no consensus on whether this is any better, and many people will say using Reduce with accumulate = T is worse than just using a loop

df$A <- c(0, 0.25, 0.50, 0.75, 1.00)
df[, c('B', 'C')] <- 
  do.call(rbind, 
          Reduce(function(x, A) (A != 0)*x[2]*c(1, A) + 0:1, 
                 df$A, init = c(0, 0), accumulate = T))[-1,]
df$D <- df$C + 5

Upvotes: 2

Related Questions