PDiracDelta
PDiracDelta

Reputation: 2558

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?

Upvotes: 17

Views: 22670

Answers (4)

eflynn90
eflynn90

Reputation: 101

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

Upvotes: 10

moodymudskipper
moodymudskipper

Reputation: 47300

See also these purrr functions

library(purrr)
modify(df,paste0,"x") # output is of the same type input, so `data.frame` here

#   c.1..2..3. c.2..3..4.
# 1         1x         2x
# 2         2x         3x
# 3         3x         4x

map_df(df,paste0,"x") # output is always tibble

# # A tibble: 3 x 2
#   c.1..2..3. c.2..3..4.
#        <chr>      <chr>
# 1         1x         2x
# 2         2x         3x
# 3         3x         4x

Upvotes: 4

stochazesthai
stochazesthai

Reputation: 697

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.

Upvotes: 19

akrun
akrun

Reputation: 886938

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"))

Upvotes: 11

Related Questions