这是一个有效的循环实现吗?

时间:2012-01-12 05:17:09

标签: r

似乎每个涉及R中循环的问题都会遇到“循环错误”和“你做错了”,建议使用listtapply或诸如此类。

我正在学习R,并且已经实现了以下循环来为每个因子级别创建图像文件,每次运行时因子级别的#都会改变:

for(i in unique(df$factor)) {
    lnam <- paste("test_", i, sep="")
    assign(lnam, subset(df, factor==i))
    lfile <- paste(lnam, ".png", sep="")
    png(file = lfile, bg="transparent")
        with(get(lnam), hist(x, main = paste("Histogram of x for ", i, " factor", sep="")))
    dev.off()
} 

这很有效。我想将它扩展为可能对这些子组(也输出到文件)等进行各种测试。

这是循环的有效合法使用吗?或者是否有一种优选的方法来涂抹这只猫?

2 个答案:

答案 0 :(得分:7)

一般来说,循环没有任何问题。有时,特别是当您处理文件或调用函数的副作用而不是输出时,循环比*apply调用更容易理解。但是,当您使用循环来模拟可以进行矢量化的操作时,它通常会慢得多,因此建议避免它们。

举个具体例子,我会发表以下评论:

  • 如果您想为某个因素中的每个级别执行某些操作,则使用levels(factor)而不是unique(factor)会更直接。
  • 您无需专门为每个要素级别创建新数据框。

考虑到这一点:

for(i in levels(df$factor))
{
    lf <- paste("test_", i, ".png", sep="")
    png(file=lf, bg="transparent",
        with(subset(df, factor == i), hist(x, ....)
    dev.off()
}

答案 1 :(得分:4)

在这种情况下,一个合理的选择是使用split将您的数据框转换为数据框列表,每个数据框包含具有特定因子级别的子集。

split_df <- split(df, df$factor)

正如科林所说,paste可以被矢量化,所以你只需要调用一次。

lfile <- paste("test_", names(split_df), ".png", sep = "")

将所有绘图代码分组到一个函数中。

draw_and_save_histogram <- function(data, file)
{
  png(file)
  with(data, hist(x))
  dev.off()  
}

现在,您可以更轻松地比较普通循环和*apply函数之间的差异(在本例中为mapply,因为我们需要两个输入)。

for(i in seq_along(split_df))
{
  draw_and_save_histogram(split_df[[i]], lfile[i])
}

mapply(
  draw_and_save_histogram,
  split_df,      
  lfile      
)

使用latticeggplot2绘制一个包含多个面板的图表,而不是绘制大量的直方图以保存在不同的文件中。

library(lattice)
histogram(~ x | factor, df)

library(ggplot2)
ggplot(df, aes(x)) + geom_histogram() + facet_wrap(~ factor)