How to create a percentage column based on the values present in every third row?

Viewed 48

I have a data frame containing the values of weight. I have a create a new column, percentage change of weight wherein the denominator takes the value of every third row.

df <- data.frame(weight = c(30,30,109,30,309,10,20,20,14))

# expected output
change_of_weight = c(30/109, 30/109, 109/109, 30/10,309/10,10/10,20/14,20/14,14/14)
3 Answers

Subset weight column where it's position %% 3 is zero and repeat each value three times.

df <- transform(df, change_of_weight=weight / rep(weight[1:nrow(df) %% 3 == 0], each=3))
df
  weight change_of_weight
1     30        0.2752294
2     30        0.2752294
3    109        1.0000000
4     30        3.0000000
5    309       30.9000000
6     10        1.0000000
7     20        1.4285714
8     20        1.4285714
9     14        1.0000000

You can create a group of every 3 rows and divide weight column by the last value in the group.

df$change <- with(df, ave(df$weight, ceiling(seq_len(nrow(df))/3), 
                      FUN = function(x) x/x[length(x)]))

Or using dplyr :

library(dplyr)
df %>%
  group_by(grp = ceiling(row_number()/3)) %>%
  mutate(change = weight/last(weight))

#  weight   grp change
#   <dbl> <dbl>  <dbl>
#1     30     1  0.275
#2     30     1  0.275
#3    109     1  1    
#4     30     2  3    
#5    309     2 30.9  
#6     10     2  1    
#7     20     3  1.43 
#8     20     3  1.43 
#9     14     3  1    

We can also use gl to create a grouping column

library(dplyr)
df %>%
   group_by(grp = as.integer(gl(n(), 3, n()))) %>%
   mutate(change = weight/last(weight))
# A tibble: 9 x 3
# Groups:   grp [3]
#  weight   grp change
#   <dbl> <int>  <dbl>
#1     30     1  0.275
#2     30     1  0.275
#3    109     1  1    
#4     30     2  3    
#5    309     2 30.9  
#6     10     2  1    
#7     20     3  1.43 
#8     20     3  1.43 
#9     14     3  1    

Or using data.table

library(data.table)
setDT(df)[, change := weight/last(weight), .(as.integer(gl(nrow(df), 3, nrow(df))))]
Related