Alberto Aguilera
Alberto Aguilera

Reputation: 351

How to accumulate sum by row per column in R

I would like to do a rowsum (acumulate) per column in the same row. What I spect is something lik this:

test = data.frame(c(0,1,1,1,0,0),c(0,0,1,1,1,0),c(0,0,0,1,1,1),c(0,0,0,0,1,1),c(0,0,0,0,0,1))
colnames(test) = c('Position','Position1','Position2','Position3','Position4')
> test
  Position Position1 Position2 Position3 Position4
1        0         0         0         0         0
2        1         0         0         0         0
3        1         1         0         0         0
4        1         1         1         0         0
5        0         1         1         1         0
6        0         0         1         1         1

result = data.frame(c(0,1,2,3,0,0),c(0,0,1,2,3,0),c(0,0,0,1,2,3),c(0,0,0,0,1,2),c(0,0,0,0,0,1))
colnames(result) = c('Position','Position1','Position2','Position3','Position4')
> result
  Position Position1 Position2 Position3 Position4
1        0         0         0         0         0
2        1         0         0         0         0
3        2         1         0         0         0
4        3         2         1         0         0
5        0         3         2         1         0
6        0         0         3         2         1

The data.frame result is what I want.

Thanks

Upvotes: 0

Views: 506

Answers (2)

Andre Elrico
Andre Elrico

Reputation: 11480

As a similar alternative to @duckmayr

apply(test, 2, function(x) {x[x] <- 1:sum(x); x})

#     Position Position1 Position2 Position3 Position4
#[1,]        0         0         0         0         0
#[2,]        1         0         0         0         0
#[3,]        2         1         0         0         0
#[4,]        3         2         1         0         0
#[5,]        0         3         2         1         0
#[6,]        0         0         3         2         1

further detail:

{        
x[x] <-  # this is a special case because you want to replace the ones. 1 = TRUE in R internally. So you assign values where x == 1. More general would be to write x[x == 1]
1:sum(x) # 1:N makes a sequence from 1, 2, 3, ..., N. sum(x) will return the amount of ones in a col. Again, more general would be `sum(x == 1)`.
; x      # This part is similar to return(x), We want to return the changes we made in x.
}

Upvotes: 1

duckmayr
duckmayr

Reputation: 16910

At first I thought you just needed to apply cumsum() to each column, but it appears you also need to multiply the cumulative sum by the columns themselves to ensure the zeros are preserved:

test = data.frame(c(0,1,1,1,0,0),c(0,0,1,1,1,0),c(0,0,0,1,1,1),c(0,0,0,0,1,1),c(0,0,0,0,0,1))
colnames(test) = c('Position','Position1','Position2','Position3','Position4')
apply(test, 2, function(x) x * cumsum(x))
#>      Position Position1 Position2 Position3 Position4
#> [1,]        0         0         0         0         0
#> [2,]        1         0         0         0         0
#> [3,]        2         1         0         0         0
#> [4,]        3         2         1         0         0
#> [5,]        0         3         2         1         0
#> [6,]        0         0         3         2         1

Created on 2018-11-19 by the reprex package (v0.2.1)

If you truly just want a cumulative sum for each column, you can just use apply(df, 2, cumsum):

test = data.frame(c(0,1,1,1,0,0),c(0,0,1,1,1,0),c(0,0,0,1,1,1),c(0,0,0,0,1,1),c(0,0,0,0,0,1))
colnames(test) = c('Position','Position1','Position2','Position3','Position4')
apply(test, 2, cumsum)
#>      Position Position1 Position2 Position3 Position4
#> [1,]        0         0         0         0         0
#> [2,]        1         0         0         0         0
#> [3,]        2         1         0         0         0
#> [4,]        3         2         1         0         0
#> [5,]        3         3         2         1         0
#> [6,]        3         3         3         2         1

Created on 2018-11-19 by the reprex package (v0.2.1)

Upvotes: 2

Related Questions