【问题标题】:Applying function using multiple columns as argument , function returns a data.frame使用多列作为参数应用函数,函数返回一个data.frame
【发布时间】:2017-11-04 12:37:20
【问题描述】:

我正在尝试应用一个使用数据框的多列作为参数的函数,该函数为每一行返回一个数据框。我可以在这里使用 for 循环,但想检查是否有其他方法可以做到这一点

这里提供了一个简单的例子。我原来的问题稍微复杂一些。

DF1<-data.frame(start=seq(from=1, to=5, by=1),end=seq(from=10, to=14, by=1))

rep_fun <- function(x,y)
{
  data.frame( A=seq(x, y)) #produces a sequence between x and y
}

DF2<-data.frame()
for (i in 1:nrow(DF1)){
  temp<-data.frame(rep_fun(DF1$start[i],DF1$end[i]))
 DF2<-rbind(temp,DF2) # this contains a dataframe that has a sequence between 'start' and 'end' for  each row in DF1 

}

我能够通过 for 循环获得的预期结果如下所示。此处并未显示所有行。第 1 到 10 行,显示 DF1 中第 5 行对应的序列

> DF2
    A
1   5
2   6
3   7
4   8
5   9
6  10
7  11
8  12
9  13
10 14
11  4
12  5

【问题讨论】:

  • 我相信这是 xy 问题的一个例子。但这是一种可能的方法:as.vector(apply(DF1, 1, function(x) x[1] : x[2]))
  • 正如我所提到的,我原来的问题更复杂。我原始问题中的 rep_fun 等效项将返回多行多列数据框。

标签: r function apply


【解决方案1】:

1) lapplyDF1 拆分为nrow(DF1):1,使其以相反的顺序出现,然后lapply 在该列表上,rbind 其组件在一起。没有使用任何包。

DF3 <- do.call("rbind", lapply(split(DF1, nrow(DF1):1), with, rep_fun(start, end)))
rownames(DF3) <- NULL

identical(DF2, DF3)
## [1] TRUE

2) 地图或此替代方案:

fun <- function(x) with(x, rep_fun(start, end))
DF4 <- do.call("rbind", Map(fun, split(DF1, nrow(DF1):1), USE.NAMES = FALSE))

identical(DF4, DF2)
## [1] TRUE

3) Map/rev 与 (2) 一样,这里使用 Map,但这次直接使用 rep_fun。此外,它使用rev 在计算之后对输出进行排序,而不是使用split 在计算之前对输入进行排序。

DF5 <- do.call("rbind", with(DF1, rev(Map(rep_fun, start, end))))

identical(DF5, DF2)
## [1] TRUE

【讨论】:

  • 说实话,逆转的事情不是必需的,但很高兴发现这是可能的!选项 3 是我要使用的选项。它比我原来的问题中的 For 循环选项快 3 倍!