【问题标题】:How to use apply to generate a data frame row by row?如何使用apply逐行生成数据框?
【发布时间】: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))
}

我一直在搞乱sapplylapply、一堆转置等但没有成功(例如,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 &lt;img=...&gt; 用于显示它的简介,绘图是否在缓存中,以及绘图使用了哪些参数。

所有这些都用于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 可能确实有害,尤其是在边缘情况下(例如,一列变成一个向量...),因为您不确定结果...

标签: r dataframe apply


【解决方案1】:

do.call(rbind, lapply(i, f)) 会按照您的要求执行...但也会这样做:

data.frame(img=letters[i], cached=F, i=i, stringsAsFactors=F)

照样:

f(i)

【讨论】:

  • 或使用plyr::ldply(i, f)
  • 我也可以,哈德利,因为我已经在生成实际绘图的代码中使用了 plyr 和 ggplot...
  • 非常有用且优雅
【解决方案2】:

这个呢?无需使用任何风格的apply 函数

foo <- function(x){
  i <- seq_len(x)
  data.frame(img=letters[i], cached=FALSE, i=i, stringsAsFactors=F)
}


  foo(5)
  img cached i
1   a  FALSE 1
2   b  FALSE 2
3   c  FALSE 3
4   d  FALSE 4
5   e  FALSE 5

【讨论】:

  • 抱歉,这不是我想要的。如上面我的 cmets 所示,玩具示例太简单了;我会改写我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-04
  • 2020-06-05
  • 2019-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多