Як організувати великі програми R?


161

Коли я виконую проект R будь-якої складності, мої сценарії швидко стають довгими і заплутаними.

Які деякі практики я можу застосувати, щоб з моїм кодом завжди було приємно працювати? Я думаю про такі речі

  • Розміщення функцій у вихідних файлах
  • Коли щось вийти з іншого вихідного файлу
  • Що має бути в головному файлі
  • Використання функцій як організаційних підрозділів (чи варто це враховувати, що R ускладнює доступ до глобального стану)
  • Практика відступу / розриву рядків.
    • Пригощати (як {?
    • Поставте такі речі, як)} на 1 або 2 рядки?

В основному, які ваші правила щодо організації великих R-скриптів?


12
повинні бути вікі спільноти
SilentGhost

Ви також можете подивитися ProjectTemplateпакет.
ctbrown

Відповіді:


71

Стандартною відповіддю є використання пакетів - див. Посібник з написання розширень R , а також різні підручники в Інтернеті.

Це дає тобі

  • квазіавтоматичний спосіб організації коду за темами
  • наполегливо рекомендує написати файл довідки, змусивши задуматися про інтерфейс
  • багато перевірок здорового стану через R CMD check
  • можливість додати тести регресії
  • а також засіб для просторів імен.

Просто біжить source() коду працює для дійсно коротких фрагментів. Все інше має бути в пакеті - навіть якщо ви не плануєте його публікувати, оскільки ви можете написати внутрішні пакети для внутрішніх сховищ.

Що стосується частини "як редагувати", керівництво R Internals має відмінні стандарти кодування R у Розділі 6. В іншому випадку я схильний використовувати стандартні параметри в ESS-режимі Emacs .

Оновлення 2008 Август-13: Девід Сміт просто блог про R Style Guide Google .


8
Якщо ви вирощуєте своє початкове дерево / аналіз "органічно", вам не важко це зробити / громіздко? Якщо ви помітили помилку у своєму коді (поширену під час вивчення нового проблемного простору), ви повинні (i) виправити джерело; (ii) перевстановити пакет; (iii) перезавантажити його у робочу область? Чи є спосіб викликати бібліотеку (...), щоб перезавантажити вже завантажений пакет (етап III вище)? Чи не потрібно вбивати робочу область, перезавантажте R, а потім перезавантажте свою бібліотеку / пакет, щоб переконатися, що це правильно?
Стіва Ліаноглу

1
Спроба googling для стилю кодування R.
хадлі

3
@SteveLianoglou Я знаю, що це досить старий, але пакет devtools від Хедлі дуже просто перезавантажує весь ваш код.
Десон

1
Цей блог дає (моя думка) дуже хороший швидкий підручник , щоб побудувати скелет першого пакет: hilaryparker.com/2014/04/29/writing-an-r-package-from-scratch
panterasBox

1
Тут працює посилання на посібник зі стилів Google R
Денис Расулев

51

Мені подобається вкладати різні функції у власні файли.

Але мені не подобається пакетна система R. Це досить важко використовувати.

Я вважаю за краще легку альтернативу - розміщувати функції файлу всередині середовища (те, що кожна інша мова називає "простором імен") і додавати його. Наприклад, я створив "util" групу функцій на зразок:

util = new.env()

util$bgrep = function [...]

util$timeit = function [...]

while("util" %in% search())
  detach("util")
attach(util)

Це все в файлі util.R . Коли ви його джерело, ви отримуєте середовище 'util', щоб ви могли дзвонити util$bgrep()і таке; але, крім того, attach()дзвінок робить його таким справедливим bgrep()і таким, що працює безпосередньо. Якщо ви не помістили всі ці функції у своє власне оточення, вони забруднили б найвищий простір імен інтерпретатора (той, що ls()показує).

Я намагався імітувати систему Python, де кожен файл є модулем. Це було б краще, але це здається нормальним.


Спасибі, Брендане. Це дуже корисно. Що відбувається з циклом while? Що не так, якщо (! ("Util"% in% search ())) attach (util)
Dan Goldstein,

2
тому ви можете робити джерело ("util.R") знову і знову, якщо ви хочете налаштувати його і таке інше.
Брендан Оконнор

вам не потрібна певна цикл часу - все, що вам потрібно, від'єднається (util). я не можу пригадати, чи дає вона помилку чи ні, якщо вона ще не завантажена, але це найбезпечніше і працює. пропозиції вітаються.
Брендан Оконнор

1
Створення специфічних для функцій середовищ та приєднання її до мене - це шлях. Інший спосіб домогтися того ж по-іншому (з більшою модульности) полягає у використанні sys.source: MyEnv <- attach(NULL, name=s_env); sys.source(file, MyEnv). Я навіть декларую (у своєму власному середовищі!) При запуску функцію, sys.source2яка буде шукати, якщо середовище з такою ж назвою вже є і подає це замість того, щоб створювати нове. Це робить додавання особистих функцій швидким, легким та своєрідним :-)
Antoine Lizée

5
Щойно я побачив це сьогодні, і це стосується альтернативи пакету: github.com/klmr/modules
ctbrown

34

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

Я не знаю, чи це у вашому випадку, але коли я працюю в R, я рідко починаю з великої складної програми на увазі. Зазвичай я починаю в одному сценарії і розділяю код на логічно відокремлювані одиниці, часто використовуючи функції. Контроль даних та код візуалізації розміщуються у власних функціях тощо. І такі функції об’єднуються в один розділ файлу (маніпулювання даними зверху, потім візуалізація тощо). Зрештою, ви хочете подумати про те, як полегшити вам підтримку сценарію та знизити кількість дефектів.

Від того, наскільки дрібно / крупнозернистим ви зробите свої функції, варіюватимуться різні правила: наприклад, 15 рядків коду або "функція повинна відповідати за виконання однієї задачі, ідентифікованої її назвою" і т. Д. Ваш пробіг буде змінюватися . Оскільки R не підтримує поклик за посиланням, я зазвичай відрізняюсь тим, щоб зробити свої функції занадто дрібними, коли це передбачає передачу кадрів даних або подібні структури навколо. Але це може бути надмірною компенсацією за деякі нерозумні помилки у виконанні, коли я вперше розпочав роботу з Р.

Коли витягнути логічні одиниці у власні фізичні одиниці (наприклад, вихідні файли та більші угруповання на зразок пакунків)? У мене є два випадки. По-перше, якщо файл стає занадто великим і прокручується серед логічно непов'язаних одиниць, це прикро. По-друге, якщо у мене є функції, які можна використовувати повторно іншими програмами. Я зазвичай починаю, розміщуючи якийсь згрупований блок, скажімо, функції маніпулювання даними, в окремий файл. Потім я можу отримати джерело цього файлу з будь-якого іншого сценарію.

Якщо ви збираєтесь розгорнути свої функції, то вам потрібно почати думати про пакети. Я не розгортаю R-код у виробництві або для повторного використання іншими з різних причин (коротко: організація культури віддає перевагу іншим мовам, занепокоєння щодо продуктивності, GPL тощо). Крім того, я прагну постійно вдосконалювати та додавати до своїх колекцій джерел файли, і я краще не торкаюся пакунків, коли вношу зміни. Тож вам слід ознайомитись з іншими відповідями на пакет, як, наприклад, з Дірком, для отримання більш детальної інформації на цьому фронті.

Нарешті, я думаю, що ваше запитання не обов'язково стосується Р. Я б дуже рекомендував прочитати Code Complete від Steve McConnell, який містить багато мудрості щодо таких питань та практики кодування взагалі.


3
Дуже корисний коментар, ар, дякую. Я програміст, але добре поговорити з іншими. Коли ви говорите "Оскільки R не підтримує поклик за телефоном, я зазвичай остерігаюся робити свої функції занадто дрібними", я чую вас. Я звик писати такі функції, як ReadData (); CleanData (); AnalyzeData (); GraphData (); і R робить це громіздким. Мені прокидається думка, що мені потрібно використовувати "джерело" так, як я використовую функції іншими мовами.
Дан Голдштейн

2
Ти маєш рацію, Ден. Я вважаю, що таким чином використовую "джерело" для виконання завдань підготовки набору даних, тому я можу просто використовувати підготовлений data.frame для інших сценаріїв, де робиться реальний аналіз. Я ніколи не був впевнений, чи це була хороша практика, тому що це просто дивно по відношенню до інших мов - більше схоже на сценарій оболонки. Добре порівнювати нотатки. :)
АРС

Приємна відповідь та коментарі. Мені здається, що це особливо дратує R, тому що ви часто працюєте з даними, що перебувають у певному форматі, для яких справді важко записати повторно використовувані функції. Отже, ви пишете приємний функціональний код, хоча ви знаєте, що він ніколи не буде повторно використаний, або ви просто пишете швидкий і неприємний процедурний код, щоб отримати трохи додаткову ефективність з великими об'єктами? Трохи дилеми .. R буде абсолютно приголомшливим з посиланням на дзвінок ..
naught101

Що ж, це можна зробити, начебто , але підвищення ефективності немає ...
naught101

19

Я згоден з порадою Дірка! IMHO, організація ваших програм від простих скриптів до документованих пакетів, для програмування в R, як перехід з Word на TeX / LaTeX для запису. Рекомендую ознайомитись з дуже корисними Створення пакетів R: Навчальний посібник Фрідріха Лейша.


6
Пакети виглядають переконливо. Однак я побоювався, що вони можуть бути зайвими. Я не пишу код загального призначення. Більшість з того, що я роблю, - це перевірити цю гіпотезу, перевірити цю гіпотезу, побудувати цю схему, відрегулювати параметри сюжету, побудувати графік, змінити дані, побудувати це. Я роблю речі, які після закінчення, ймовірно, ніколи не будуть повторно запущені.
Ден Гольдштейн

1
У такому випадку вам слід поглянути на Sweave. Він поєднує R-код з LaTeX. Таким чином, у вас є аналіз та джерело звіту разом.
Тьєррі

15

Моя лаконічна відповідь:

  1. Ретельно пишіть свої функції, визначаючи достатньо загальних виходів та входів;
  2. Обмежити використання глобальних змінних;
  3. Використовуйте об'єкти S3 та, де це доречно, об'єкти S4;
  4. Розміщуйте функції в пакети, особливо коли ваші функції викликають C / Fortran.

Я вважаю, що R все більше використовується у виробництві, тому потреба в коді для багаторазового використання більша, ніж раніше. Я вважаю перекладача набагато надійнішим, ніж раніше. Немає сумнівів, що R на 100-300 разів повільніше, ніж C, але зазвичай вузьке місце сконцентровано навколо кількох рядків коду, які можна делегувати на C / C ++. Я думаю, було б помилкою делегувати сильні сторони R в маніпулюванні даними та статистичному аналізі на іншій мові. У цих випадках покарання за ефективність є низьким, і в будь-якому випадку добре варто заощадити на розробці. Якби тільки час виконання було вирішенням, ми б усі писали асемблер.


11

Я мав намір розібратися, як писати пакунки, але не вкладав часу. Для кожного з моїх міні-проектів я зберігаю всі свої низькорівневі функції у папці під назвою "функції /" та надсилаю їх в окрему область імен, яку я явно створюю.

Наступні рядки коду створять середовище з назвою "myfuncs" на шляху пошуку, якщо він ще не існує (використовуючи вкладення), і заповнюють його функціями, що містяться у файлах .r у моєму каталозі "function /" (використовуючи sys.source). Зазвичай я розміщую ці рядки у верхній частині мого основного сценарію, призначеного для "інтерфейсу користувача", з якого викликаються функції високого рівня (викликаючи функції низького рівня).

if( length(grep("^myfuncs$",search()))==0 )
  attach("myfuncs",pos=2)
for( f in list.files("functions","\\.r$",full=TRUE) )
  sys.source(f,pos.to.env(grep("^myfuncs$",search())))

Коли ви вносите зміни, ви завжди можете їх повторно використовувати з тими ж рядками або використовувати щось подібне

evalq(f <- function(x) x * 2, pos.to.env(grep("^myfuncs$",search())))

оцінити доповнення / модифікації в створеному вами середовищі.

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

Що стосується умов кодування, то це єдине, що я бачив щодо естетики (мені це подобається і я дуже дотримуюся, але я не використовую занадто багато фігурних дужок в R):

http://www1.maths.lth.se/help/R/RCC/

Існують і інші "умови" щодо використання [, drop = FALSE] та <- як оператор присвоєння пропонується в різних презентаціях (як правило, основний запис) на useR! конференцій, але я не думаю, що будь-яке з них є суворим (хоча [, drop = ЛІЖНЕ] корисно для програм, у яких ви не впевнені у вкладеному вами вкладі).


6

Порахуйте мене як іншу людину на користь пакунків. Я визнаю, що я дуже бідний при написанні чоловічих сторінок і віньєток до тих пір, поки / коли мені доведеться (тобто звільнятимуться), але це робить справжній корисний спосіб зв'язати джерело лань. Плюс, якщо ви серйозно ставитеся до збереження свого коду, всі пункти, які викликає Дірк, стають такими.


4

Я також згоден. Для початку скористайтеся функцією package.skeleton (). Навіть якщо ви думаєте, що ваш код ніколи не буде запущений, він може допомогти мотивувати вас створити більш загальний код, який може заощадити ваш час пізніше.

Що стосується доступу до глобального середовища, то з оператором << це легко, хоч це і не заважає.


3

Ще не навчившись писати пакунки, я завжди організовував пошук джерел сценаріїв. Це схоже на заняття з письма, але не настільки задіяне. Це не програмно елегантно, але я вважаю, що я збираю аналізи з часом. Як тільки у мене є великий розділ, який працює, я часто переміщую його до іншого сценарію і просто надходжу його, оскільки він буде використовувати об’єкти робочої області. Можливо, мені потрібно імпортувати дані з декількох джерел, сортувати їх і знайти перехрестя. Я міг би помістити цей розділ у додатковий сценарій. Однак, якщо ви хочете розповсюдити свою "програму" для інших людей, або вона використовує інтерактивне введення, пакет, ймовірно, є хорошим маршрутом. Як дослідник мені рідко потрібно поширювати свій код аналізу, але мені часто потрібно розширювати чи змінювати його.


Я використовував цей метод, але з тих пір зрозумів, що функції та пакети кращі, ніж вихідні ("next_script.R"). Я писав про це тут: stackoverflow.com/questions/25273166/…
Артур Іп

1

Я також шукав святий грааль правильного робочого процесу для складання великого проекту R. Торік я знайшов цей пакет під назвою rsuite , і, звичайно, це було те, що я шукав. Цей пакет R був явно розроблений для розгортання великих проектів R, але я виявив, що він може бути використаний для проектів R менших, середніх і великих розмірів. Я дам посилання на приклади реального світу через хвилину (нижче), але спочатку я хочу пояснити нову парадигму побудови проектів Rrsuite .

Примітка. Я не творець і не розробник rsuite.

  1. Ми працювали з проектами RStudio, які не так; мета повинна бути не створенням проекту чи пакетом, а більшою сферою застосування. У rsuite ви створюєте надпроектний або головний проект, який містить стандартні R-проекти та R-пакети, у всіх можливих комбінаціях.

  2. Маючи суперпроект R, вам більше не потрібен Unix make для управління нижчими рівнями R-проектів під ними; ви використовуєте R-сценарії вгорі. Дозвольте мені показати вам. Створюючи головний проект rsuite, ви отримуєте цю структуру папок:

введіть тут опис зображення

  1. У папку Rрозміщені сценарії управління проектами, ті, які замінять make.

  2. Папка packages- це папка, де rsuiteзберігаються всі пакети, що складають суперпроект. Ви також можете скопіювати вставити пакет, недоступний з Інтернету, і rsuite також створить його.

  3. папку deployment - це те, де rsuiteбудуть записуватися всі пакунки, які були вказані у DESCRIPTIONфайлах пакунків . Отже, це означає, що ви самі проектуєте повністю відтворюваний час.

  4. rsuiteпоставляється з клієнтом для всіх операційних систем. Я перевірив їх усіх. Але ви також можете встановити його як addinдля RStudio.

  5. rsuiteтакож дозволяє створити ізольовану condaустановку у власній папціconda . Це не середовище, а фізична установка Python, отримана від Anaconda у вашій машині. Це працює разом з R SystemRequirements, з яких ви можете встановити всі необхідні вам пакети Python з будь-якого каналу conda, який ви хочете.

  6. Ви також можете створити локальні сховища, щоб витягувати R-пакети, коли ви перебуваєте в режимі офлайн, або хочете створити все це швидше.

  7. Якщо хочете, ви також можете створити проект R у вигляді поштового файлу та поділитися ним з колегами. Він запуститься, якщо ваші колеги встановлять ту ж версію R.

  8. Інший варіант - це створення контейнера всього проекту в Ubuntu, Debian або CentOS. Отже, замість того, щоб ділитися поштовим файлом зі збіркою вашого проекту, ви ділитесь цілимDocker контейнером з вашим проектом, готовим до запуску.

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

Перше, що я почав експериментувати - це bookdownелектронні книги. Мені ніколи не пощастило мати відлік, щоб пережити тест часу довше шести місяців. Отже, те, що я зробив, - це перетворення оригінального проекту з відстеження книг, щоб слідувати rsuiteрамкам. Тепер мені не потрібно турбуватися про оновлення мого глобального R середовища, оскільки проект має власний набір пакунків у deploymentпапці.

Наступне, що я зробив - це створити проекти машинного навчання, але в rsuiteдорозі. Головний, оркестровий проект у верхній частині, і всі підпроекти та пакети, які мають контролюватися майстром. Це дійсно змінює спосіб кодування з R, роблячи вас більш продуктивними.

Після цього я почав працювати в новій шахті під назвою rTorch. Це було можливо здебільшого через rsuite: це дозволяє думати і йти великим.

Одна порада, хоча. Навчитися rsuiteнепросто. Оскільки він представляє новий спосіб створення R-проектів, він відчуває важкість. Не лякайтеся при перших спробах, продовжуйте підніматися по схилу, поки не зробите це. Це вимагає передових знань про вашу операційну систему та про вашу файлову систему.

Я думаю, що один день RStudioдозволяє нам генерувати оркестрові проекти, як rsuiteце робиться в меню. Це було б приголомшливо.

Посилання:

RSuite GitHUb repo

r4ds облік

кери і блискучий підручник

модерн-книга-rsuite

interpretable_ml-rsuite

IntroMachineLearningWithR-rsuite

clark-intro_ml-rsuite

hyndman-bookdown-rsuite

statisti_rethinking-rsuite

fread-орієнтири-rsuite

dataviz-rsuite

роздріб-сегментація-h2o-навчальний посібник

telco-customer-churn-tutorial

sclerotinia_rsuite


-7

R добре для інтерактивного використання та невеликих сценаріїв, але я не використовував би його для великої програми. Я б використовував основну мову для більшості програмування і загорнув його в інтерфейс R.


1
Там є серйозно великі пакети (тобто програми). Ви серйозно пропонуєте їх переписати якоюсь іншою мовою? Чому ???
Едуардо Леоні

4
Одне врахування - ефективність. Я часто переписував R-код як C ++ і робив його на 100 разів швидше. Інша - підтримка інструментів. R не має нічого подібного до IDE, як Eclipse або Visual Studio. Нарешті, якщо програма дуже велика, ймовірно, вона виконує нестатистичні завдання, до яких R не дуже підходить.
Джон Д. Кук

2
Існує плагін (Stat-ET), який дозволяє Eclipse взаємодіяти з R. Я погоджуюся, що C ++ може працювати набагато швидше, ніж Р. Але скільки часу потрібно, щоб перекодувати R-речі в C ++? Якщо ви не можете часто використовувати код, користь більш швидкого коду не варто багато в порівнянні з зусиллями з перекодування його в C ++.
Тьєррі

2
Так, є торгівля (продуктивність проти продуктивності). А для чисто аналізу даних / статистичної роботи R часто виграє. Але для написання інших завдань, наприклад, GUI, Інтернету тощо, я не впевнений, що це так. Ми часто прототипуємо і працюємо в R, але розгортаємо виробничий код у Python / C ++. З останнім ви отримуєте продуктивність і дуже зрілі та багаторазові бібліотеки / рамки для різних завдань. Але це текуча ситуація, і екосистема Р постійно розвивається.
АРС

Використання Rcppпакету, включаючи код C ++ у програмах R, стає досить простим. Тому перезапис певних частин коду R може бути інтегрований у R досить легко. Крім того, поява RStudio представила IDE для R, хоча, можливо, ще не настільки потужна, як Visual Studio.
Пол Хіемстра
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.