【发布时间】:2012-12-30 00:21:31
【问题描述】:
我想逐行生成一个数据帧,方法是在值列表上使用apply 的某种风格,并使用一个为每个值返回单行数据帧的函数。作为一个玩具示例,假设我的值是 i = 1:3 并且我有:
f <- function(i) {
return(data.frame(img=letters[i], cached=F, i=i, stringsAsFactors=F))
}
我一直在搞乱sapply、lapply、一堆转置等但没有成功(例如,d = sapply(1:3, f) 看起来很有希望,但似乎是我想要的转置,所以我尝试了d = t(sapply(1:3,f)),但它是一个矩阵;因此我尝试了下一个d = as.data.frame(t(sapply(1:3, f))),它显示正确(它打印出来的结果就像我想要的那样),但仍然是错误的,就像你想的那样找出您是否尝试对其进行子集化,例如 d[,1] 这实际上是一个列表)。
最后我得到了这个,它有效:
d = apply(data.frame(i=1:3), 2, f)$i
这给了我想要的框架:
img cached i
1 a FALSE 1
2 b FALSE 2
3 c FALSE 3
有没有更好/更简洁的方式来表达上述内容?对我来说,这一切都感觉很笨拙而且过于复杂。
编辑:正如几位读者所提到的,这个“玩具示例”确实太简单了,事实上,f(1:3) 就可以满足我的要求。实际功能是基于 Web 的指标仪表板的一部分,从各种数据库表中提取数据,并制作我打算缓存的适度复杂的图(大多数时候它们变化相对缓慢)。我猜相关的部分是该函数通常需要几个参数,而这些参数不是一个简单的序列1:n。所以,让我重写这个例子,让它更真实一点:
library(digest)
gkey <- function(...) {
args <- list(...)
return(digest(paste(args,sep=".",collapse=".")));
}
f <- function(conn, table, checknew.query, plot.query, plot.fun, params) {
latest.data = queryExec(conn, table, checknew.query, params)
key = gkey(table, latest.data, plot.query, plot.fun, params)
out = getFromCacheOrPlot(key, conn, table, plot.query, plot.fun, params)
return(out)
}
其中queryExec 构建查询,执行它并检索结果,gkey() 根据其参数计算哈希键,getFromCacheOrPlot() 使用key 构建文件名(.png 图像),如果存在,则从缓存中检索它,否则生成它。它还返回一个 data.frame,其中有一行给我们文件名,一个 html <img=...> 用于显示它的简介,绘图是否在缓存中,以及绘图使用了哪些参数。
所有这些都用于wiki系统的插件中,某些页面有几十个或更多。
【问题讨论】:
-
do.call(rbind, lapply(i, f))会按照您的要求执行...但data.frame(img=letters[i], cached=F, i=i, stringsAsFactors=F)也会这样做...所以我想我不确定您在问什么。 -
我认为您需要一个更准确地代表您的真正问题的玩具示例,因为我的直接反应是简单地做
data.frame(img = letters[i],cached = rep(FALSE,length(i)),i = i),我猜这不是您想要的。跨度> -
你的方法对我来说似乎很不错,但我发现
do.call(rbind, lapply(i, f))更清晰... -
当我使用
sapply时,我经常指定simplify = FALSE并手动调整我的数据(使用do.call)。 -
@RomanLuštrik:我想强调您的建议。我基本上也经常这样做。
simplify=TRUE可能确实有害,尤其是在边缘情况下(例如,一列变成一个向量...),因为您不确定结果...