Функции записи по сравнению с линейной интерпретацией в рабочем процессе R

Здесь много написано о разработке рабочего процесса в R для статистических проектов. Наиболее популярным рабочим процессом является модель LCFD Джоша Рейха. С main.R содержащим код:

source('load.R')
source('clean.R')
source('func.R')
source('do.R')

так что один source('main.R') запускает весь проект.

Q: Есть ли причина, по которой этот рабочий процесс предпочитает тот, в котором интерпретационная работа по строке load.R, clean.R и do.R заменяется функциями, которые вызывается main.R

Я не могу найти ссылку сейчас, но я где-то читал о том, что при программировании в R нужно преодолеть свое желание написать все в терминах вызовов функций, - что R был MEANT, чтобы быть написанным, это поэтапная интерпретирующая форма.

В: Действительно? Зачем?

Я был расстроен подходом LCFD, и я собираюсь, вероятно, написать все в терминах вызовов функций. Но прежде чем делать это, я хотел бы услышать от хороших людей SO о том, хорошая ли это идея или нет.

EDIT: проект, над которым я сейчас работаю, состоит в том, чтобы (1) читать в наборе финансовых данных, (2) очищать его (довольно активно), (3) оценивать некоторое количество, связанное с данными, используя мою оценку (4) Оценить то же количество с использованием традиционных оценок (5) Результаты отчета. Мои программы должны быть написаны таким образом, чтобы он выполнял работу (1) для разных эмпирических наборов данных, (2) для данных моделирования или (3) с использованием разных оценок. ТАКЖЕ, он должен следовать грамотному программированию и воспроизводимым руководящим принципам исследований, так что для новичков код должен запускать программу, понимать, что происходит и как ее настроить.

Ответ 1

Я не думаю, что есть один ответ. Лучше всего держать в уме относительные достоинства, а затем выбрать подход к этой ситуации.

1) . Преимущество использования функций не в том, что все ваши переменные остаются в рабочей области, и вы можете проверить их в конце. Это может помочь вам понять, что происходит, если у вас есть проблемы.

С другой стороны, преимущество хорошо спроектированных функций состоит в том, что вы можете unit test их. То есть вы можете тестировать их отдельно от остальной части кода, что облегчает их тестирование. Также, когда вы используете функцию, по модулю некоторых конструкций нижнего уровня, вы знаете, что результаты одной функции не будут влиять на других, если они не будут переданы, и это может ограничить ущерб, который одна функция может ошибочно обрабатывать, чтобы сделать чужую. Вы можете использовать средство debug в R для отладки ваших функций, и возможность одного шага через них является преимуществом.

2) LCFD. Относительно того, следует ли использовать разложение load/clean/func/do независимо от того, является ли его выполнение через source или функции вторым вопросом. Проблема с этим декомпозицией, независимо от того, выполняется ли ее через source или функции, - это то, что вам нужно запустить ее, чтобы иметь возможность протестировать следующее, чтобы вы не могли проверить их самостоятельно. С этой точки зрения это не идеальная структура.

С другой стороны, это имеет то преимущество, что вы можете заменить шаг загрузки независимо от других шагов, если вы хотите попробовать его на разных данных и можете заменить другие шаги независимо от нагрузки и чистых шагов если вы хотите попробовать другую обработку.

3) Нет. файлов. Возможно, существует третий вопрос, который подразумевается в том, что вы спрашиваете, должно ли все быть в одном или нескольких исходных файлах. Преимущество размещения файлов в разных исходных файлах заключается в том, что вам не нужно искать ненужные элементы. В частности, если у вас есть подпрограммы, которые не используются или не относятся к текущей функции, которую вы смотрите, они не будут прерывать поток, поскольку вы можете организовать их в других файлах.

С другой стороны, может быть преимущество в размещении всего в одном файле с точки зрения (а) развертывания, то есть вы можете просто отправить кому-то этот единственный файл и (b) улучшить удобство, поскольку вы можете поместить все в одном сеансе редактора, который, например, облегчает поиск, так как вы можете искать всю программу с помощью функций редактора, так как вам не нужно определять, в каком файле находится подпрограмма. Также последующие команды отмены позволяют вам перемещаться назад все единицы вашей программы и одно сохранение сохранят текущее состояние всех модулей, так как есть только один. (c) скорость, т.е. если вы работаете над медленной сетью, может быть быстрее сохранить один файл на вашей локальной машине, а затем просто написать его изредка, а не идти туда и обратно на медленный пульт.

Примечание.. Еще одна вещь, о которой стоит подумать, заключается в том, что использование пакетов может быть лучше для ваших потребностей по сравнению с файлами источников в первую очередь.

Ответ 2

Я думаю, что любой временный материал, созданный в файлах source'd, не будет очищен. Если я это сделаю:

x=matrix(runif(big^2),big,big)
z=sum(x)

и источник, который как файл, x зависает, хотя мне это не нужно. Но если я это сделаю:

ff=function(big){
 x = matrix(runif(big^2),big,big)
 z=sum(x)
 return(z)
}

и вместо источника, do z = ff (большой) в моем script, x-матрица выходит за пределы области видимости и поэтому очищается.

Функции обеспечивают аккуратное малое количество повторно используемых инкапсуляций и не загрязняют окружающую среду. В общем, у них нет побочных эффектов. Ваши построчные сценарии могут использовать глобальные переменные и имена, привязанные к набору данных в текущем использовании, что делает их непригодными для использования.

Я иногда работаю по очереди, но как только я получаю более пяти строк, я вижу, что мне действительно нужно сделать правильную функцию многократного использования, а чаще всего я снова использую повторное использование он.

Ответ 3

Никто не упомянул о важном аспекте при написании функций: нет смысла писать их, если вы не повторяете какое-либо действие снова и снова. В некоторых частях анализа вы будете делать одноразовые операции, поэтому нет смысла писать для них функцию. Если вам нужно повторить нечто большее, чем несколько раз, стоит потратить время и усилия на запись повторно используемой функции.

Ответ 4

Workflow:

Я использую нечто очень похожее:

  • Base.r: извлекает первичные данные, вызывает другие файлы (пункты с 2 по 5)
  • Функции .r: загружает функции
  • Параметры сюжета. r: загружает ряд общих параметров сюжета, которые я часто использую
  • Lists.r: загружает списки, у меня их много, потому что имена компаний, операторы и т.д. меняются со временем.
  • Recodes.r: большая часть работы выполняется в этом файле, в основном это очистка и сортировка данных.

До сих пор не было проведено никакого анализа. Это просто для очистки и сортировки данных.

В конце Recodes.r я сохраняю среду, которая будет перезагружена в мой фактический анализ.

save(list=ls(), file="Cleaned.Rdata")

С очисткой, настройками функций и графиками, я начинаю анализировать. Опять же, я продолжаю разбить его на более мелкие файлы, которые сфокусированы на темы или темы, такие как: демография, запросы клиентов, корреляции, анализ соответствия, графики и т.д. Я почти всегда запускаю первые 5 автоматически, чтобы настроить свою среду, а затем я запускаю остальных по линейной основе, чтобы обеспечить точность и изучить.

В начале каждого файла я загружаю очищенную среду данных и преуспеваю.

load("Cleaned.Rdata")

Номенклатура объекта:

Я не использую списки, но я использую номенклатуру для своих объектов.

df.YYYY # Data for a certain year
demo.describe.YYYY ## Demographic data for a certain year
po.describe ## Plot option
list.describe.YYYY ## lists
f.describe ## Functions

Использование дружественной мнемоники для замены "описать" в приведенном выше.

Комментирование

Я пытался привыкнуть использовать комментарий (x), который я нашел невероятно полезным. Комментарии в коде полезны, но часто недостаточно.

Очистка

Опять же, здесь я всегда стараюсь использовать один и тот же объект для легкой очистки. tmp, tmp1, tmp2, tmp3 и обеспечить их удаление в конце.

Функции

В других сообщениях был комментарий, касающийся только написания функции для чего-то, если вы собираетесь использовать ее более одного раза. Я хотел бы настроить это, чтобы сказать, если вы считаете, что вы можете снова использовать его снова, вы должны бросить его в функцию. Я даже не могу подсчитать количество раз, когда я хотел написать функцию для процесса, который я создал в строке за строкой.

Кроме того, ПЕРЕД тем, как я меняю функцию, я бросаю ее в файл с надписью "Устаревшие функции", опять же, защищая от эффекта "как, черт возьми, я делаю это".

Ответ 5

Я часто разделяю свой код аналогично этому (хотя я обычно добавляю Load и Clean в один файл), но я никогда не просто отправляю все файлы для запуска всего проекта; для меня, который побеждает цель их разделения.

Как и комментарий от Sharpie, я думаю, что ваш рабочий процесс должен сильно зависеть от той работы, которую вы делаете. Я занимаюсь в основном поисковыми работами, и в этом контексте хранение данных (загрузка и очистка) отдельно от анализа (функций и операций) означает, что мне не нужно перезагружать и повторять, когда я вернусь на следующий день; Вместо этого я могу сохранить набор данных после очистки, а затем импортировать его снова.

У меня мало опыта многократного перебора ежедневных наборов данных, но я полагаю, что я нашел бы другой рабочий процесс полезным; как отвечает Хэдли, если вы только что-то делаете (как и я, когда я загружаю/очищаю свои данные), может быть полезно написать функцию. Но если вы делаете это снова и снова (как вам кажется, вы бы это сделали), это может быть гораздо более полезно.

Короче говоря, я нашел, что раздел полезен для поисковых анализов, но, вероятно, сделает что-то другое для повторяющихся анализов, как вы думаете.

Ответ 6

Я некоторое время размышлял о компромиссе с рабочим процессом.

Вот что я делаю для любого проекта, связанного с анализом данных:

  • Загрузка и очистка: Создавайте чистые версии исходных наборов данных для проекта, как если бы я строил локальную реляционную базу данных. Таким образом, я по возможности структурирую таблицы в 3n нормальной форме. Я выполняю базовое манипулирование, но на этом этапе я не объединяю и не фильтрую таблицы; опять же, я просто создаю нормализованную базу данных для данного проекта. Я помещаю этот шаг в свой собственный файл, и я сохраню объекты на диске в конце, используя save.

  • Функции. Я создаю функцию script с функциями для фильтрации, слияния и агрегации данных. Это наиболее интеллектуально сложная часть рабочего процесса, поскольку я вынужден думать о том, как создавать правильные абстракции, чтобы функции были повторно использованы. Функции должны быть обобщены, чтобы я мог гибко объединять и агрегировать данные с нагрузки и чистого шага. Как и в модели LCFD, этот script не имеет побочных эффектов, поскольку он только загружает определения функций.

  • Функциональные тесты. Я создаю отдельный script для тестирования и оптимизации производительности функций, определенных на шаге 2. Я четко определяю, каков должен быть результат от функций, поэтому этот шаг служит своеобразной документацией (аналитическое тестирование).

  • Главная. Я загружаю объекты, сохраненные на шаге 1. Если таблицы слишком велики для размещения в ОЗУ, я могу отфильтровать таблицы с помощью SQL-запроса, поддерживая мышление базы данных, Затем я фильтрую, объединяю и агрегирую таблицы, вызывая функции, определенные на шаге 2. Таблицы передаются в качестве аргументов в функции, определенные мной. Результатом функций являются структуры данных в форме, подходящей для построения, моделирования и анализа. Очевидно, что у меня может быть несколько дополнительных шагов по строке, где нет смысла создавать новую функцию.

Этот рабочий процесс позволяет мне делать молниеносную разведку на шаге Main.R. Это связано с тем, что я создал четкие, обобщаемые и оптимизированные функции. Основное отличие от модели LCFD заключается в том, что я не зачищаю по очереди фильтрацию, слияние или агрегацию; Я предполагаю, что я могу фильтровать, объединять или обобщать данные по-разному в рамках исследования. Кроме того, я не хочу загрязнять свою глобальную среду длинными строк за строкой script; как указывает Spacedman, функции помогают в этом.