Это правильная реализация цикла? - PullRequest
2 голосов
/ 12 января 2012

Кажется, что каждый вопрос, касающийся циклов в R, встречается с "Петли плохие" и "Вы делаете это неправильно" с советом использовать list, или tapply или что-то еще.

Я изучаю 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 ]

7 голосов
/ 12 января 2012

В циклах нет ничего плохого.Иногда, особенно когда вы работаете с файлами или вызываете функции для их побочных эффектов, а не для их выходных данных, за циклами легче следить, чем за *apply вызовами.Однако, когда вы используете цикл для имитации операции, которая может быть векторизована, она часто намного медленнее, поэтому рекомендуется избегать их.

Однако, учитывая ваш конкретный пример, я бы сделал следующие комментарии:1004 *

  • Если вы хотите что-то сделать для каждого уровня в факторе, более просто использовать 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()
}
4 голосов
/ 12 января 2012

В этом случае разумным вариантом является использование 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      
)

Вместо того, чтобы рисовать множество гистограмм для сохранения вВ разных файлах гораздо предпочтительнее нарисовать один график несколькими панелями, используя lattice или ggplot2.

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

library(ggplot2)
ggplot(df, aes(x)) + geom_histogram() + facet_wrap(~ factor)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...