How to call a function for each row of data.frame?

I have a function with several parameters. This function returns data.frame.

I have another data.frame file.

Now I would like to name my function for each row of my data.frame (as parameters). The resulting data.frames that I would like to modify.

So, I thought something like

do.call(rbind, apply(df, 1, f))

- my friend.

But: During this call, df is converted to a matrix. In this process, all numbers are converted to characters. Therefore, I have to change my function to convert. This is clumsy, and I'm afraid that I missed something.

So my question is: how can I do this?

See the following code for an example:

Sys.setenv(LANG = "en")
# Create data.frame
df <- data.frame(
  a = c('a', 'b', 'c'),
  b = c(1, 2, 3),
  stringsAsFactors = FALSE
)

# My function 
f <- function(x) {
  data.frame(
    x = rep(paste(rep(x[['a']], x[['b']]), collapse=''),x[['b']]),
    y = 2 * x[['b']],
    stringsAsFactors = FALSE
  )
}

apply(df, 1, f)

Here I get the error message:

Error in 2 * x[["b"]] : non-numeric argument to binary operator 

Therefore, I change the function f to the function g:

g <- function(x) {
  data.frame(
    x = rep(paste(rep(x[['a']], as.numeric(x[['b']])), collapse=''), as.numeric(x[['b']])),
    y = 2 * as.numeric(x[['b']]),
    stringsAsFactors = FALSE
  )
}

Now i can call

 do.call(rbind, apply(df, 1, g))

and i get

    x y
1   a 2
2  bb 4
3  bb 4
4 ccc 6
5 ccc 6
6 ccc 6

I tried using a for loop.

result <- f(df[1,])
for(i in 2:nrow(df)){
  result <- rbind(result, f(df[i,]))
}
result

. R-way. for-loops "R-ish". , . , df .

, base-R dplyr/tidyverse?

+4
3

, apply() data.frames. . , , data.frame.

f <- function(a, b) {
  data.frame(
    x = rep(paste(rep(a, b), collapse=''), b),
    y = 2 * b,
    stringsAsFactors = FALSE
  )
}

map() ( , )

purrr::map2_df(df$a, df$b, f)

( , )

purrr::pmap_df(df, f)
+5

, data.table:

library(data.table)
setDT(df)
df[ , .(x = rep(paste(rep(a, b), collapse = ''), b), y = 2*b), 
   keyby = seq_len(nrow(df))]
#    seq_len   x y
# 1:       1   a 2
# 2:       2  bb 4
# 3:       2  bb 4
# 4:       3 ccc 6
# 5:       3 ccc 6
# 6:       3 ccc 6

keyby = seq_len(nrow(df)) - clunkiest ; , , data.table,  , # 1063

+4

tidyverse answer:

> df %>% split(1:nrow(df)) %>% map(f) %>% bind_rows()
    x y
1   a 2
2  bb 4
3  bb 4
4 ccc 6
5 ccc 6
6 ccc 6

You can splitdf line by line (which gives you a list of tibles), then a mapfunction for each line (where the function returns a data frame), and then bind_rows()everything back.

0
source

Source: https://habr.com/ru/post/1691997/


All Articles