R 将函数应用于每行数据帧和返回数据帧列表的有效方法
我有一个函数,它接受许多参数并返回一个数据帧。我还有一个数据框,其中每一行都包含我希望传递给函数的参数,并且我希望将生成的数据框集存储在一个列表中。做这件事的有效方法是什么?(我假设这是一种类似于apply的方法。) 例如,假设您有(无意义的)函数R 将函数应用于每行数据帧和返回数据帧列表的有效方法,r,R,我有一个函数,它接受许多参数并返回一个数据帧。我还有一个数据框,其中每一行都包含我希望传递给函数的参数,并且我希望将生成的数据框集存储在一个列表中。做这件事的有效方法是什么?(我假设这是一种类似于apply的方法。) 例如,假设您有(无意义的)函数 但是如何为数据帧的每一行运行myfunc并将结果存储在列表中呢?我知道如何对此进行基本的for循环,但我正在寻找运行得更快的东西—矢量化的东西。如果您想要一个答案列表,为什么不传递一个参数列表?首先将数据帧拆分为一个列表,然后lappy您的函数: l
但是如何为数据帧的每一行运行myfunc并将结果存储在列表中呢?我知道如何对此进行基本的for循环,但我正在寻找运行得更快的东西—矢量化的东西。如果您想要一个答案列表,为什么不传递一个参数列表?首先将数据帧拆分为一个列表,然后
lappy
您的函数:
listargs <- split(df,1:nrow(df))
lapply(listargs,myfunc)
$`1`
x y
1 1 1
2 2 1
3 3 1
4 4 1
$`2`
x y
1 2 2
2 3 2
3 4 2
4 5 2
$`3`
x y
1 3 3
2 4 3
3 5 3
4 6 3
require(data.table) ## 1.9.2+
fA <- function(x, y) {
data.frame(x = x:y, y = y:x)
}
dt = as.data.table(df)
result1 = dt[, list(ans = list(fA(x, y))), by=seq_len(nrow(dt))]
# seq_len ans
# 1: 1 <data.frame>
# 2: 2 <data.frame>
# 3: 3 <data.frame>
listargs您的“无意义”函数需要对apply
有一些意义才能工作。对于初学者,您将无法使用$
,因为apply
会将每一行视为基本命名向量
记住这一点,这里有一个重写(还有一个更“卑鄙”的意思):
同样,不要总是太快地注销
循环的<代码>应用
是优化的,但基本上隐藏了一个for循环
以下是一些速度比较:
## Function to use with `apply`
myfunc <- function(dfRow) {
data.frame(x = dfRow["y"]:dfRow["x"], y = mean(c(dfRow["x"], dfRow["y"])))
}
## Function to use with `lapply`
myfunc1<-function(dfRow){
return(data.frame(x=dfRow$x:dfRow$y,y=mean(dfRow$x,dfRow$y)))
}
## Sample data
set.seed(1)
df <- data.frame(x = sample(100, 100, TRUE),
y = sample(100, 100, TRUE))
如果您愿意使用外部软件包,那么下面是一个使用
数据的软件包
以下是一个简化功能的版本:
listargs <- split(df,1:nrow(df))
lapply(listargs,myfunc)
$`1`
x y
1 1 1
2 2 1
3 3 1
4 4 1
$`2`
x y
1 2 2
2 3 2
3 4 2
4 5 2
$`3`
x y
1 3 3
2 4 3
3 5 3
4 6 3
require(data.table) ## 1.9.2+
fA <- function(x, y) {
data.frame(x = x:y, y = y:x)
}
dt = as.data.table(df)
result1 = dt[, list(ans = list(fA(x, y))), by=seq_len(nrow(dt))]
# seq_len ans
# 1: 1 <data.frame>
# 2: 2 <data.frame>
# 3: 3 <data.frame>
在这里,我们将数据的子集,.SD
——一个特殊的变量,它携带属于每个组的数据,传递给函数fB
。再次执行result2$ans
应该会得到您的答案
嗯
哦,顺便说一句,在代码中使用空格是可以的;成本不高:)
myfunc <- function(dfRow) {
data.frame(x = dfRow["x"]:dfRow["y"], y = mean(c(dfRow["x"], dfRow["y"])))
}
apply(df, 1, myfunc)
# [[1]]
# x y
# 1 1 2.5
# 2 2 2.5
# 3 3 2.5
# 4 4 2.5
#
# [[2]]
# x y
# 1 2 3.5
# 2 3 3.5
# 3 4 3.5
# 4 5 3.5
#
# [[3]]
# x y
# 1 3 4.5
# 2 4 4.5
# 3 5 4.5
# 4 6 4.5
## Function to use with `apply`
myfunc <- function(dfRow) {
data.frame(x = dfRow["y"]:dfRow["x"], y = mean(c(dfRow["x"], dfRow["y"])))
}
## Function to use with `lapply`
myfunc1<-function(dfRow){
return(data.frame(x=dfRow$x:dfRow$y,y=mean(dfRow$x,dfRow$y)))
}
## Sample data
set.seed(1)
df <- data.frame(x = sample(100, 100, TRUE),
y = sample(100, 100, TRUE))
fun1 <- function() apply(df, 1, myfunc)
fun2a <- function() {
listargs <- split(df,1:nrow(df))
}
fun3 <- function() {
out <- vector("list", nrow(df))
for (i in 1:nrow(df)) {
out[[i]] <- data.frame(x = df$x[i]:df$y[i], y = mean(c(df$x[i], df$y[i])))
}
out
}
microbenchmark(fun2(), fun2(), fun3(), times = 20)
# Unit: milliseconds
# expr min lq median uq max neval
# fun1() 39.72704 39.99255 40.84243 43.77641 48.16284 20
# fun2() 74.92324 79.20913 82.15130 83.12488 100.51695 20
# fun3() 48.61772 49.59304 50.16654 56.17891 88.65290 20
require(data.table) ## 1.9.2+
fA <- function(x, y) {
data.frame(x = x:y, y = y:x)
}
dt = as.data.table(df)
result1 = dt[, list(ans = list(fA(x, y))), by=seq_len(nrow(dt))]
# seq_len ans
# 1: 1 <data.frame>
# 2: 2 <data.frame>
# 3: 3 <data.frame>
require(data.table) ## 1.9.2+
fB <- function(dat) {
data.frame(x = dat$x:dat$y, y = dat$y:dat$x)
}
dt = as.data.table(df)
result2 = dt[, list(ans = list(fB(.SD))), by=seq_len(nrow(dt))]
# seq_len ans
# 1: 1 <data.frame>
# 2: 2 <data.frame>
# 3: 3 <data.frame>