'Add to the values in a column in a loop to generate new columns

I'm trying to create some sort of loop to generate a % of age over the next few years, in months. I have two columns, age and term. Dividing them gets me the % I'm looking for, but I need an easy way to add 1 to age, and keep term consistent, and use that to create a new column. Something like:

for i = n col_n<-data_set$term/(data_set$age + n) n=30



Solution 1:[1]

library(tidyverse)

# create example data frame
df <- tribble(~age, ~term,
              10,   5,
              12,   6)

# create function to add new column 
agePlusN <- function(df, n) {
  mutate(df, "col.{n}" := term/(age+ n))
}

# iterate through 1:30 applying agePlusN() 
walk(1:30, \(n) df <<- agePlusN(df, n))

This works, but the last step is a bit ugly. It should really use map instead of walk, but I couldn't quite figure out how to get it not to add new rows.

Attempt 2

# create function to add new column 
agePlusN <- function(df, n) {
  mutate(df, "col.{n}" := term/(age+n)) %>% 
  select(-term, -age)
}

# iterate through 1:30 applying agePlusN() 
df2 <- 
  map_dfc(1:30, \(n) agePlusN(df, n)) %>% 
  bind_cols(df, .)

Notes:

  • The := in mutate allows you to use glue() syntax in the names on the left hand side argument (eg. "col.{n}")
  • map_dfc() means map and then use bind_cols to combine all of the outputs
  • \(n) is equivalent to function(n)
  • The . in the call to bind_cols() isn't necessary but makes sure the 'age' and 'term' columns are put at the beginning of the resulting dataframe.

I still think this could be done better without having to call bind_cols, but I'm not smart enough to figure it out.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1