AennaPhD
AennaPhD

Reputation: 147

R, data frame manipulation

I have the following data frame in R.

X1 <- c(451,2,6,2,7)
X2 <- c(0,1,6,3,4)
df <- data.frame(X1, X2)

I would like to add two extra columns (X3 and X4), where the first row is mirrored (X3=X2 and X1=X4), and from the second row onwards, X3 equals X4 from the previous row plus one, and X4 equals X3 (same row) plus X1 (same row).

The final output should look like this

X1 <- c(451,2,6,2,7)
X2 <- c(0,1,6,3,4)
X3 <- c(0,452,455,462,465)
X4 <- c(451,454,461,464,472)
df <- data.frame(X1, X2, X3, X4)

Do you have any suggestions on how to do this in R?

Upvotes: 3

Views: 94

Answers (3)

AnilGoyal
AnilGoyal

Reputation: 26218

tidyverse style using purrr::accumulate.

  • accumulate or accumulate2 rolls out result of previous iteration. This result of previous iteration can be used as ..1 in lambda formula
  • so our formula is ..1 + ..2 + 1 which is result of previous iteration + first argument and 1 (can also be written as ~ .x + .y + 1
  • Here I have stripped last value of first argument and
  • took first value of X2 as initial value (.init) instead.
X1 <- c(451,2,6,2,7)
X2 <- c(0,1,6,3,4)
df <- data.frame(X1 = X1, X2 = X2)
library(tidyverse)
df %>% mutate(X3 = unlist(accumulate(X1[-nrow(.)], .init = first(X2), ~ (..1 + ..2 + 1))),
              X4 = X3 + X1)
#>    X1 X2  X3  X4
#> 1 451  0   0 451
#> 2   2  1 452 454
#> 3   6  6 455 461
#> 4   2  3 462 464
#> 5   7  4 465 472

Created on 2021-06-08 by the reprex package (v2.0.0)

Upvotes: 3

Anoushiravan R
Anoushiravan R

Reputation: 21908

Although there are much more efficient ways of going about this, writing a for loop is also a good idea:

X3 <- rep(df1$X2[1], nrow(df))
X4 <- c(df$X1[1], rep(0, nrow(df) - 1))

for(i in 2:nrow(df)) {
  X3[i] <- X4[i - 1] + 1
  X4[i] <- X3[i] + df$X1[i]
}

cbind(df, as.data.frame(cbind(X3, X4)))

   X1 X2  X3  X4
1 451  0   0 451
2   2  1 452 454
3   6  6 455 461
4   2  3 462 464
5   7  4 465 472

Upvotes: 3

Onyambu
Onyambu

Reputation: 79228

You could do:

a <- df$X1
a[1] <- a[1] - 1
b <- cumsum(a+1)

transform(df, X3 = c(X2[1], head(b+1, -1)), X4 = b)
  X1 X2  X3  X4
1 451  0   0 451
2   2  1 452 454
3   6  6 455 461
4   2  3 462 464
5   7  4 465 472

Upvotes: 3

Related Questions