Seb
Seb

Reputation: 53

Creating new column dataframes function and lapply: providing too many variables

I am currently trying to write a simple custom function which creates a new column in an existing data.frame, based on a multiplication of two existing columns.

Following that I would like to apply the function across multiple data.frames in the global environment with lapply.

I however already fail to write the custom function, as I am getting the follow error (based on my example data posted below): "In [<-.data.frame(*tmp*, i, value = list(A = 1:20, B = c(1L, : provided 3 variables to replace 2 variables"

I am aware that this is an absolute basic question, but I have not found a fitting answer to this specific question online and simply cant wrap my head around it myself.

Thanks in advance for any help!

I have already tried using "return(x[i])" at the end of the function, as it has been recommended in other posts, or also leaving out the [i] (which I am only using as I saw it another question), which did not change anything.

Using this function gives the error stated above

set.seed(40)
A <- seq(1:20)
B <- rbinom(A, 1, 0.5)
df1 <- data.frame(A, B)

set.seed(40)
C <- as.numeric(seq(1:50))
D <- as.numeric(rbinom(C, 1, 0.5))
df2 <- data.frame(C, D)

FUN = function(x, i){
  x[i]$Mul = x[i]$A*x[i]$B
}

FUN(df1)

This function correctly gives the new values but of course does not create a new column in the existing data.frame

FUN = function(x, i){
   x[i]$A*x[i]$B
}

FUN(df1)

I would then like to apply the function with to all other data.frames including "df" in the name

lapply(mget(ls(pattern="df")), FUN)

I excpet to have a new column in df, df$Mul, with the values c( 1 2 3 0 0 0 0 8 0 0 0 12 0 0 15 16 0 18 0 20). Such a column, I cant manage to create.

Upvotes: 2

Views: 126

Answers (2)

akrun
akrun

Reputation: 887118

We can use tidyverse methods

library(tidyverse)
mget(ls(pattern = "^df\\d+$")) %>%
     map(~ .x %>%
            mutate(mult = (!! rlang::sym(names(.x)[1])) *
                          (!! rlang::sym(names(.x)[2]))))

Or using reduce

mget(ls(pattern = "^df\\d+$")) %>% 
    map(~ .x %>% 
             mutate(mult = reduce(., `*`)))

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 388982

You could get all the dataframes together in a list using mget

list_df <- mget(ls(pattern="df"))

Change the function using transform

FUN = function(x){
   transform(x, mult = x[, 1]  * x[, 2])
}

and apply it to list of dataframes

list_df <- lapply(list_df, FUN)

You'll have all the dataframes with new column. Although, it is better to keep such dataframes in list instead of having objects of multiple dataframes in the global environment. However, if you want the dataframes separately again you can do

list2env(list_df,envir=.GlobalEnv)

Upvotes: 0

Related Questions