我有一个带有几个参数的函数。此函数返回data.frame。
我有另一个data.frame。
现在我想为data.frame的每一行调用我的函数(作为参数)。结果data.frames我想rbind。
所以我想像
do.call(rbind, apply(df, 1, f))
是我的朋友。
但是:在此调用期间,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)
我收到错误:
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解决方案?
答案 0 :(得分: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
)
}
然后你可以使用更传统的map()
样式方法(如果仅使用两列,则特别容易)
purrr::map2_df(df$a, df$b, f)
使用更多列(和与参数名称匹配的列名称),您可以使用
purrr::pmap_df(df, f)
答案 1 :(得分:4)
我相信你可以在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))
部分是最笨拙的部分;这尤其是data.table
的一些增强请求的主题,
例如,#1063
答案 2 :(得分:1)
> 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()
一切都在一起。