Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

apply function to every element in data.frame and return data.frame

UPDATE: before, I used the paste function as an example instead of an arbitrary myFun function. That problem was slightly easier, because paste can actually operate on vectors, while myFun can not.

I would like to apply my own function element-wise to every element in a data.frame, and get the modified data.frame as a return value.

Example:

> df <- data.frame(c(1,2,3), c(2,3,4))
> df
  c.1..2..3. c.2..3..4.
1          1          2
2          2          3
3          3          4
> df_x <- magical_apply_function(df, function(x) myFun
> df_x
  c.1..2..3. c.2..3..4.
1         myFun(1)         myFun(2)
2         myFun(2)         myFun(3)
3         myFun(3)         myFun(4)

I'm completely baffled to not be able to find the answer to this problem anywhere on the internet. Most resources talk about apply, lapply, and sapply but those only work on vectors/lists and they only return lists.

Are for loops really the only way to go here?

like image 591
PDiracDelta Avatar asked Feb 07 '18 11:02

PDiracDelta


People also ask

How will you apply a function to every data element in a DataFrame?

One can use apply() function in order to apply function to every row in given dataframe.

How do I apply a function to an entire DataFrame in R?

In R Programming Language to apply a function to every integer type value in a data frame, we can use lapply function from dplyr package. And if the datatype of values is string then we can use paste() with lapply.


3 Answers

df <- data.frame(c(1,2,3), c(2,3,4))
df[] <- lapply(df, function(x) paste(x,"x", sep=""))
df

df[] preserves the dataframe's structure.

like image 143
stochazesthai Avatar answered Oct 18 '22 05:10

stochazesthai


We can either use mutate_all from dplyr

library(dplyr)
df %>% 
     mutate_all(funs(paste0(., "x")))

Or with lapply from base R and convert it to data.frame

data.frame(lapply(df, paste0,  "x"))
like image 41
akrun Avatar answered Oct 18 '22 05:10

akrun


Can you not use apply(df, c(1,2), myFun)? Using the c(1,2) will apply the function to each item in your dataframe individually:

MARGIN a vector giving the subscripts which the function will be applied over. E.g., for a matrix 1 indicates rows, 2 indicates columns, c(1, 2) indicates rows and columns.

> temp<-data.frame(le=LETTERS[1:3], nu=20:22)
> temp
  le nu
1  A 20
2  B 21
3  C 22
> apply(temp, c(1,2), function(x) {gsub('d',x,'d1d1')})
     le     nu      
[1,] "A1A1" "201201"
[2,] "B1B1" "211211"
[3,] "C1C1" "221221"

The function isn't used correctly if you apply the function by rows:

> apply(temp, 1, function(x) {gsub('d',x,'d1d1')})
[1] "A1A1" "B1B1" "C1C1"
Warning messages:
1: In gsub("d", x, "d1d1") :
  argument 'replacement' has length > 1 and only the first element will be used
2: In gsub("d", x, "d1d1") :
  argument 'replacement' has length > 1 and only the first element will be used
3: In gsub("d", x, "d1d1") :
  argument 'replacement' has length > 1 and only the first element will be used
like image 8
eflynn90 Avatar answered Oct 18 '22 03:10

eflynn90