Комментарии 9
Спасибо за статью! Бывает непросто перестать мыслить циклами :)
Было бы интересно увидеть список задач, где без циклов не обойтись. Например, у меня такой кейс: есть вектор с названиями файлов формата json, нужно последовательно их считывать, далее в каждом файле считывать несколько подсписков (для каждого файла кол-во подсписков разное). Сейчас это реализовано двумя циклами for: внешний для считывания файлов и внутренний для прохода по всем подспискам. Можно ли это реализовать более эффективно без циклов?
Было бы интересно увидеть список задач, где без циклов не обойтись. Например, у меня такой кейс: есть вектор с названиями файлов формата json, нужно последовательно их считывать, далее в каждом файле считывать несколько подсписков (для каждого файла кол-во подсписков разное). Сейчас это реализовано двумя циклами for: внешний для считывания файлов и внутренний для прохода по всем подспискам. Можно ли это реализовать более эффективно без циклов?
На моем ноутбуке расчеты занимают 39 секунд, хотя того же результата можно достичь за 0,009 секундыС точки зрения человека, далекого от R, это очень странная ситуация. Обработка массива данных всегда где-то под капотом сводится к циклу. Получается, что стандартная реализация цикла средствами языка несет столько накладных расходов, что выполняется в 4 тысячи раз медленнее «железного» цикла?
По-моему, эта проблема должна решаться оптимизациями на стороне компилятора — разворачивание циклов, SIMD и другие хитрости, как это делает, например, компилятор C. А добавлением целого семейства специализированных функций выглядит, как костыль.
Больше похоже на ленивое выполнение, когда в таблицу внесли запись вида «отдавать дополнительную колонку, в которой находится результат операции». А так как после этого данные никто и не читает, то реальной работы и не происходит.
Нет, просто во втором случае все работает параллельно. И R сам по себе на эту параллельность заточен. Вполне возможно что обычный цикл даже толком не оптимизирован — он не используется для больших данных. Но последнее — это уже домыслы.
for(row in 1:nrow(testDF))
testDF[row, 3] < — testDF[row, 1] + testDF[row, 2] # Ужас!
Согласен. «Ужас!». Но ведь — не «Ужас-ужас!»
Попробуйте «штатное» (т.е. без всяких библиотек) для R:
system.time(testDF$c<-testDF$a+testDF$b)
Будете приятно удивлены.
А про самый современный подход ничего не сказано. Функциональный подход на базе purrr. Интересующимся можно взглянуть для затравки на доклад с rstudio::conf 2017, почитать книгу R4DS, раздел "Итераторы". А еще есть более хитрые циклы, когда надо, например, применять функции с условием для определенных строк выбранных столбцов дата фрейма… А еще неплохо бы знать структуры данных и специфику используемых пакетов. Например, как быстро провести обработку data.frame с POSIXct с разными time-zone? Любой цикл "в лоб" даст безумное по исполнению время.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Разработка на R: тайны циклов