如何为data.frame的每一行调用一个函数?

Jer*_*Who 4 r dataframe tidyverse

我有一个功能有几个参数.此函数返回data.frame.

我有另一个data.frame.

现在我想为data.frame的每一行调用我的函数(作为参数).结果data.frames我想rbind.

所以我想到了类似的东西

do.call(rbind, apply(df, 1, f))
Run Code Online (Sandbox Code Playgroud)

是我的朋友.

但是:在此调用期间,df被转换为矩阵.在此过程中,所有数字都将转换为字符.所以我必须修改我的功能才能重新转换.那太笨了,我怕我错过了什么.

所以我的问题是,我该怎么做?

例如,请参阅以下代码:

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)
Run Code Online (Sandbox Code Playgroud)

我在这里得到错误:

Error in 2 * x[["b"]] : non-numeric argument to binary operator 
Run Code Online (Sandbox Code Playgroud)

所以我将函数f改为函数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
  )
}
Run Code Online (Sandbox Code Playgroud)

现在我可以打电话了

 do.call(rbind, apply(df, 1, g))
Run Code Online (Sandbox Code Playgroud)

我明白了

    x y
1   a 2
2  bb 4
3  bb 4
4 ccc 6
5 ccc 6
6 ccc 6
Run Code Online (Sandbox Code Playgroud)

我试着使用for循环.

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

这确实有效.但这不可能是R-way.for-loops不是"R-ish"有太多可能出错的地方.也许df可以是空的,也可以只有一行.

那么什么是base-R或dplyr/tidyverse解决方案?

MrF*_*ick 5

嗯,apply()用于矩阵,不与data.frames一起使用.在这样的情况下确实应该避免.最好编写采用适当参数的函数,而不是要求传递data.frame行.

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

然后你可以使用更传统的map()风格方法(如果只使用两列,特别容易)

purrr::map2_df(df$a, df$b, f)
Run Code Online (Sandbox Code Playgroud)

使用更多列(和与参数名称匹配的列名称),您可以使用

purrr::pmap_df(df, f)
Run Code Online (Sandbox Code Playgroud)