Reputation: 147
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
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..1 + ..2 + 1
which is result of previous iteration
+ first argument
and 1
(can also be written as ~ .x + .y + 1
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
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
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