Nick Shields
Nick Shields

Reputation: 13

How to reference an element in the same row when looping through a data frame?

I'm creating a formula that iterates across all rows within my data frame, this dynamic formula changes by row and is linked to three variables within the first 3 columns.

I may be a bit off in my current approach as I'm fairly new to R, so please let me know if there's another solution I'm missing here when reading below.

I have so far tried lapplying a function that loops through every row and implements the changing formula to each series.

I have replicated my issue below with a smaller scale data set:

  1. The first three columns are the variables that I wish to use within the formula. The first for loop, is to keep these 3 columns values consistent.

  2. For all other observed values (a time series) I want to apply the following formula which takes the current values and then applies a functional form using the values in the referenced column.

The code below works when scale, alpha and beta are static numbers, however when I try referencing them by name I get NAs throughout with no error message in the console.

# Replicating problem using fake data

df <-  data.frame(
  scale =  c(0.1,0.2,0.3), 
  Alpha = c(100,200,300), 
  Beta = c(0.45, 0.84, 0.97), 
  Jan = c(1,2,3), 
  Feb = c(2,5,4), 
  Mar =c(5,3,2))

FormulaA <- lapply(df, function(df){ 

  series = numeric(length(df))

  # To keep initial values constant
  for (i in (1:3)){      
    series[i] = df[i]}

  # For all other time series data 
  for (i in (4:length(df))){      
    # Formula Structure below
    series[i] = ( ( ( df[i] * df[scale][i] ) * df[Alpha][i]) / (( df[i] * df[scale][i] ) + df[Beta][i] ) )

  } 
return(series)
})

I have tried a few methods to get this working, but none seem to stick.

The current output when using static numbers and combined with a do.call(rbind.data.frame, FormulaA) seems to get the format correct, but the numbers are not.

Desired output:

scale   Alpha   Beta    Jan Feb Mar
1    0.1     100     0.5     18.2    30.8    52.6 
2    0.2     200     0.8     64.5    108.7   83.3 
3    0.3     300     1.0     144.4   165.9   114.6 

Any help or guidance would be greatly appreciated, thank you for reading!

Upvotes: 1

Views: 649

Answers (1)

akrun
akrun

Reputation: 887891

We can use mutate_at to select the columns of interest and then do the calculation for each column

library(dplyr)
df %>% 
   mutate_at(vars(Jan:Mar), ~ round((. * scale * Alpha)/((. * scale) + Beta), 1))
#   scale Alpha Beta   Jan   Feb   Mar
#1   0.1   100 0.45  18.2  30.8  52.6
#2   0.2   200 0.84  64.5 108.7  83.3
#3   0.3   300 0.97 144.4 165.9 114.6

In base R, we can use lapply

df[4:6] <- lapply(df[4:6], function(x) 
    round((x * df$scale * df$Alpha)/((x * df$scale) + df$Beta), 1))

Upvotes: 3

Related Questions