написание функций и построчная интерпретация в рабочем процессе R - PullRequest
10 голосов
/ 20 марта 2011

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

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

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

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

Сейчас я не могу найти ссылку, но я где-то читал на SO, что при программировании на R нужно преодолевать их желание писать все в терминах вызовов функций - что R ЗАМЕТИЛСЯ, чтобы написать это построчная интерпретирующая форма.

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

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

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

Ответы [ 6 ]

15 голосов
/ 20 марта 2011

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

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)
}

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

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

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

13 голосов
/ 20 марта 2011

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

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

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

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

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

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

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

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

7 голосов
/ 21 марта 2011

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

6 голосов
/ 22 марта 2011

Workflow:

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

  1. Base.r: извлекает первичные данные, вызывает другие файлы (пункты со 2 по 5)
  2. Functions.r: загружает функции
  3. Plot Options.r: загружает ряд общих опций печати, которые я часто использую
  4. Lists.r: загружает списки, у меня их много, потому что названия компаний, заявления и тому подобное со временем меняются
  5. 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

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

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

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

Функции

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

Кроме того, ДО того, как я изменю функцию, я добавлю ее в файл с именем Deprecated Functions.r, опять же, для защиты от эффекта «как, черт возьми, я это сделал».

3 голосов
/ 21 марта 2011

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

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

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

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

1 голос
/ 07 марта 2014

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

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...