Q: function to sucessively subtract columns from the prior columns in a dataframe and save in new dataframe H, I'm fairly new to R and trying to write a function to create a new dataframe that depicts the results of substracting every two columns that are next to each other in the original dataset. Imagine this was may data (although I have many variables)
obs  var1   var2   var3    
1     5      10     14   
2     6      11     15   
3     7      12     16   
4     8      13     17    

The output should look something like this
obs var2_1 var3_2
1     5       4
2     5       4
3     5       4
4     5       4

Thank you very much in advance!

A: This is basically -
df[-c(1, 2)] - df[-c(1, ncol(df))] 

#  var2 var3
#1    5    4
#2    5    4
#3    5    4
#4    5    4


To make it more scalable and inline with your expected output -
#Create a temporary dataframe to keep only the columns we are interested in
temp_df <- df[-1]
#Save ncol value in a variable to avoid recalculating
n <- ncol(temp_df)
#Create new column names
new_cols <- paste0('var', 2:n,'_', 1:(n-1))
#add the calculated columns to temporary df
temp_df[new_cols] <- temp_df[-1] - temp_df[-n]
#keeping only interested columns. 
cbind(df[1], temp_df[new_cols])

#  obs var2_1 var3_2
#1   1      5      4
#2   2      5      4
#3   3      5      4
#4   4      5      4


A: @Mael's answer is certainly more compact, but you could also do this with dplyr:
You can create a vector of variable names that are going to be involved in the subtraction.  Then, you loop over the names, starting with the second one.  You can make a variable that is the ith one minus the previous one.
library(dplyr)
dat <- tibble::tribble(
  ~obs,  ~var1,   ~var2,   ~var3,    
1,     5,      10,     14,   
2,     6,      11,     15,   
3,     7,      12,     16,   
4,     8,      13,     17)   

ndat <- names(dat)
## remove obs from list of variables
ndat <- ndat[-1]
for(i in 2:length(ndat)){
  newvar <- paste(ndat[i], ndat[(i-1)], sep="_")
  dat <- dat %>% 
    mutate( {{newvar}} := .data[[ndat[i]]] - .data[[ndat[(i-1)]]])
}
dat %>% select(-all_of(ndat))
#> # A tibble: 4 × 3
#>     obs var2_var1 var3_var2
#>   <dbl>     <dbl>     <dbl>
#> 1     1         5         4
#> 2     2         5         4
#> 3     3         5         4
#> 4     4         5         4

Created on 2023-03-01 with reprex v2.0.2

A: A dplyr solution:
library(dplyr)

df %>%
  mutate(pick(var2:var3) - pick(var1:var2), .keep = "unused")

#   obs var2 var3
# 1   1    5    4
# 2   2    5    4
# 3   3    5    4
# 4   4    5    4


A: You can do a rowwise difference with apply. The second parameter, 1, means that the function diff is applied on rows. Convert to data.frame if needed.
cbind(df[1], t(apply(df[-1], 1, diff)))

  obs var2 var3
1   1    5    4
2   2    5    4
3   3    5    4
4   4    5    4


A: It could also be achieved with pivoting:
library(dplyr)
library(tidyr)

df |>
  pivot_longer(-obs, names_prefix = "var") |>
  mutate(name = paste0("var", name, "_", lag(name)),
         value = value-lag(value),
         .by = "obs") |>
  na.omit() |>
  pivot_wider(id_cols = obs)

Output:
# A tibble: 4 × 3
    obs var2_1 var3_2
  <dbl>  <dbl>  <dbl>
1     1      5      4
2     2      5      4
3     3      5      4
4     4      5      4


A: For problems like this we can use dplyover::over(). Below we loop over the numbers 2:3 and construct the variable names inside .("") evaluating the expression in {} where .x is the number of the current loop.
The .names argument lets us create names on the fly. Here {x} evaluates to the current loop.
.keep = "unused" will drop all the columns we used for the computation.
One advantage over some of the other approaches is that we don't assume that the column names are in the correct order. The columns can be in any order (e.g. var2 var1 var3) and the values will still be calculated correctly.
library(dplyr)
library(dplyover) # https://timteafan.github.io/dplyover/
 

dat %>% 
  mutate(over(2:3,
              ~ .("var{.x}") - .("var{.x-1}"),
              .names = "var{x}_{x-1}"),
         .keep = "unused")

#> # A tibble: 4 x 3
#>     obs var2_1 var3_2
#>   <dbl>  <dbl>  <dbl>
#> 1     1      5      4
#> 2     2      5      4
#> 3     3      5      4
#> 4     4      5      4

Data from OP
dat <- tibble::tribble(
  ~obs,  ~var1,   ~var2,   ~var3,    
  1,     5,      10,     14,   
  2,     6,      11,     15,   
  3,     7,      12,     16,   
  4,     8,      13,     17)  

Disclaimer: The package is not on CRAN and I'm the maintainer.
Created on 2023-03-01 by the reprex package (v2.0.1)
