首页 文章

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

提问于
浏览
4

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

我有另一个data.frame .

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

所以我想到了类似的东西

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

是我的朋友 .

But: 在此调用期间,df将转换为矩阵 . 在此过程中,所有数字都将转换为字符 . 所以我必须修改我的功能才能重新转换 . 那个's clumsy and I'恐怕我想念一些东西 .

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

例如,请参阅以下代码:

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)

我在这里得到错误:

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

所以我将函数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
  )
}

现在我可以打电话了

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

我明白了

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

我试着使用for循环 .

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解决方案?

3 回答

  • 5

    好吧, apply() 用于矩阵,并且不需要编写采用适当参数的函数,而不需要传递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)
    
  • 4

    我相信你可以在_1218629中非常干净地做到这一点:

    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)) 部分是最笨拙的一部分;这尤其是 data.table 的一些增强请求的主题,例如#1063

  • 0

    tidyverse回答:

    > 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
    

    你可以 split df by rows(它给你一个字节列表),然后 map 函数到每一行(函数返回一个数据帧),然后 bind_rows() 它们全部重新组合在一起 .

相关问题