Как человек, имеющий опыт работы в статистике, я признаю тот факт, что мне постоянно приходится улучшать свои компьютерные науки и инженерные навыки почти каждый день. Хотя для меня естественно думать о распределениях, статистике и других ключевых концепциях при анализе данных, написание эффективного и чистого кода - нет.
К счастью, у меня была возможность поработать со множеством инженеров, которые научили меня и объяснили, почему код должен быть чистым и эффективным - если я могу резюмировать эту потребность в одном предложении, лучшее из них взято из стихотворения Джона Донна ( говорят, что ему почти 400 лет!): «Ни один человек - не остров».
Когда дело доходит до разработки нашего кода и скриптов, мы не остров. А совместная работа - один из важнейших навыков, которыми нужно обладать при работе в качестве специалиста по данным, аналитика (или почти в любой другой профессии) - если вы хотите сделать карьеру на анализе данных, вероятность того, что кому-то придется взглянуть на ваш код. в будущем вероятно 99,99%. Чем лучше организован ваш код, тем проще будет для кого-то искать, отлаживать и улучшать его в будущем. И это касается не только других людей, с которыми вам, возможно, придется работать, это также избавит вас от многих хлопот (кто никогда не смотрел на свой собственный код и не думал: «Что, черт возьми, я делаю в этом функция? ”)
Итак, давайте сразу перейдем к некоторым распространенным передовым методам программирования на R (некоторые оспариваются, другие широко принимаются сообществом)!
Библиотеки идут первыми
Первое, что должно войти в ваш сценарий R, - это ваши библиотеки - зависимости вашего кода должны быть явными в самом начале. Это позволит избежать сюрпризов при запуске кода, потому что один из импортированных файлов скрыт в середине кода, и пользователь не подготовил для этого свою среду.
Большинство руководств по стилю согласны с этой рекомендацией, и вам не следует делать что-то вроде:
my_vector <- c(1,2,3) library(readxl) read_excel(path_file)
Выше создается вектор my_vector перед импортом библиотеки readxl -, как правило, это плохая практика.
Единственный аргумент, когда я считаю приемлемым нарушить это правило, - это во время обучения - например, когда кто-то вводит новую концепцию в середине лекции, которая опирается на библиотеку - эту библиотеку можно загрузить в середине сценария, чтобы студенты сохраняют визуальную ссылку на используемую функцию и библиотеку, содержащую этот фрагмент кода.
На втором месте - жестко запрограммированные переменные
Другое общепринятое правило - жестко запрограммированные переменные, такие как пути или файлы конфигурации для доступа к базам данных (если у вас есть пароли, еще лучше взглянуть на эту статью, чтобы управлять секретами: https://cran.r-project.org /web/packages/httr/vignettes/secrets.html ) в начале скрипта после импорта библиотек.
Многие сценарии используют данные из файлов CSV или XLSX, поэтому рекомендуется выполнять следующие действия:
library(readxl)
path_file <- "data/data.csv"
my_df <- read_excel(path_file)
Таким образом, всякий, кто читает ваш код, получает о нем две важные части информации:
- От того, какие библиотеки вы кодируете, зависит.
- Какие файлы и папки должны содержать исходная структура папок.
Да, и насчет путей к файлам ..
Относительные пути по абсолютным путям
Абсолютный путь никогда не подходит. Это особенно актуально, когда вы работаете с папкой, которая находится внутри пользовательской структуры операционной системы.
Абсолютные пути имеют следующий вид:
"C:\Users\ivopb\My Documents\R Project\data\data.csv"
Если я передам свой код кому-то, кому нужно запустить его на своем компьютере, если у него нет имени пользователя ivopb, он никогда не сможет запустить код там, где мы его используем. этот файл. Даже если они запускают его в одной и той же структуре папок (Мои документы / R Project / и т. Д.).
Да, и даже если случайно они являются пользователем ivopb,, но на их жестком диске отображается другая буква, отличная от C :, удачи в выполнении кода!
Как правило, всегда предпочтительны относительные пути:
"data\data.csv"
Это заставит вас установить рабочий каталог в папку, над которой вы работаете, или открыть скрипт из папки - что на самом деле намного лучше, чем отладка и изменение огромного количества путей, которые могут быть в вашем скрипте!
Соглашения об именах - Имена файлов
Для имен файлов всегда используйте легко интерпретируемые имена файлов и не используйте пробелы в имени файла (на самом деле я совершаю эту ошибку в сценариях своего курса, чтобы попытаться сопоставить имена лекций на Udemy, что-то я могу изменить это в future) - пример хорошего и плохого примера:
# Good example my_file.R # Bad example My File.R
Также старайтесь использовать имена в нижнем регистре в именах скриптов. Если ваш сценарий преследует цель, например, создать агрегацию некоторых конкретных данных в файле csv, используйте имя, привязанное к общей цели сценария:
aggregating_data.R
Соглашения об именах - объекты и функции
Это горячая тема для любого языка программирования, и люди склонны спорить о том, какое соглашение об именах лучше.
Помимо выбранного вами соглашения об именах, просто обязательно следуйте одному и тому же во всем сценарии - для меня это общее золотое правило.
Мне нравится использовать футляр для змей (используя _) для объектов и футляр для верблюда или змейки для функций, но это открыто для обсуждения. Пример:
# Good my_vector <- c(1,2,3) # Bad myvector <- c(1,2,3) # Good ThisFunction() this_function() # Bad thisfunction()
Кроме того, имена ваших объектов и функций должны быть как можно более явными и краткими, представляя функцию, которая принимает элемент и вычисляет степень числа:
ComputePowerOfBaseWithExponent <- function (base, exponent) { return (base**exponent) }
Имя функции очень длинное, поэтому мы можем сократить его, и обычно рекомендуется это сделать:
ComputePower <- function (base, exponent) { return (base**exponent) }
Повторюсь, мое единственное золотое правило - придерживаться единого стиля во всем сценарии.
Возврат
Это, наряду с именами переменных и функций, является одной из самых спорных тем внутри сообщества (взгляните на эту ветку, чтобы проверить обе стороны аргумента - https://stackoverflow.com/questions/11738823/explicitly-calling -Возврат-в-функции-или-нет )
Операторы возврата в R в конце каждой функции добавляют избыточности - это факт. Обратите внимание, что в приведенном выше примере я использовал явный возврат:
ComputePower <- function (base, exponent) { return (base**exponent) }
Оператор return можно удалить из функции, изменив с явного возврата на неявный возврат:
ComputePower <- function (base, exponent) { base**exponent }
Использование явных возвратов имеет незначительную разницу в скорости вашего кода - немного увеличивает ее (как правило, она настолько крошечная, что ею можно пренебречь).
Я склонен думать, что явные возвраты проще для всех уровней кодировщиков R, поскольку явные возвраты облегчают новичку понимание потока кода. Но в основном это выбор программиста - люди склонны сидеть по обе стороны забора, когда доходит до этого, и мое личное мнение таково, что я не считаю справедливым ругать того, кто использует неявные или явные результаты.
Будьте откровенны в циклах
Одна из важных вещей при выполнении циклов для объектов - это явное наименование элементов, для которых выполняется цикл.
Представьте себе следующее упражнение: у вас есть вектор с возрастом определенной группы людей, которую вы хотите классифицировать как «Major» или «Minor», и вы используете для этого цикл for (давайте проигнорируем другие подходы, которые мы могли бы использовать, такие как лучшие реализации ради аргумента):
ages_people = c(10, 20, 20, 30, 40) ClassifyAge <- function (ages) { age_class <- c() for (age in ages) { if (age < 18) { age_class <- c(age_class, 'Minor') } else { age_class <- c(age_class, 'Major') } } age_class }
Следующий код будет работать, если мы вызовем age в цикле for как i или элемент:
ages_people = c(10, 20, 20, 30, 40) ClassifyAge <- function (ages) { age_class <- c() for (i in ages) { if (i < 18) { age_class <- c(age_class, 'Minor') } else { age_class <- c(age_class, 'Major') } } age_class }
Как правило, лучше явно называть элементы цикла - в приведенном выше случае мы делаем что-то на основе возраста, поэтому было бы лучше назвать элемент цикла age, а не i, element или j. Это облегчило бы понимание того, что код делает на функциональном уровне, для тех, кто не знаком с кодом.
Использование ‹- или = при назначении объекта
Это еще одна горячая тема в сообществе - я склонен придерживаться ‹- при создании объектов или функций, хотя в этом контексте = работает точно так же. Большинство гидов по стилю согласны с этим, но нет единого мнения по этому поводу.
Одним из общепринятых правил является то, что когда вы используете оператор ‹для присваивания, вы оставляете пробелы между назначаемым объектом и именем переменной, как показано ниже:
# Good example my_vector <- c(1, 2, 3) # Bad example my_vector<-c(1, 2, 3)
Конечно, поскольку я много переплетаю между скриптами Python и R, иногда непослушный = делается на задании :-)
Длина линии
Избегайте использования более 80 символов в строке, чтобы ваш код мог поместиться в большинстве окон IDE. Это также общая лучшая практика для других языков программирования, таких как Python. Вы хотите, чтобы читатель скрипта не использовал горизонтальную полосу прокрутки вперед и назад (это простой рецепт, чтобы потеряться в коде).
Представьте некоторую функцию, которая вызывается с очень длинными аргументами:
CalculatesMeaningOfLife('This is a really long argument','This is another really long argument','This is a third really long argument!')
При вызове этого кода рекомендуется делать следующее:
CalculatesMeaningOfLife( 'This is a really long argument', 'This is another really long argument', 'This is a third really long argument!' )
В R Studio есть автоматический отступ, когда вы нажимаете Enter после запятых. Это изящная функция, которая упрощает поддержание порядка и чистоты нашего кода.
Интервал
При вызове функций или индексировании объектов рекомендуется всегда ставить пробел после каждого ‘,’. Это делает код более читаемым и позволяет избежать идеи «сжатого кода». Сжатый код - это когда у нас есть следующее:
my_array = array(1:10,c(2,5)) my_array[,c(1,2)]
Код работает, но весь ваш код связан без пробелов. Визуально это затрудняет понимание того, какой бит относится к первому или второму измерению в массиве.
Более чистый способ сделать это - сделать следующее:
my_array = array(1:10, c(2, 5)) my_array[, c(1, 2)]
Обратите внимание, как я добавил пробел после каждой запятой в коде. Это то, что обычно называют «дать коду дышать» - вы упрощаете понимание того, что вы индексируете в каждом измерении и что входит в каждый аргумент вашего вызова функции.
СУХОЙ - Не повторяйся
Одним из важнейших понятий любого языка программирования (по крайней мере, функционального) является концепция DRY. Общее золотое правило: когда вы обнаруживаете, что копируете и вставляете большой объем кода, это хорошее применение для функции.
В качестве действительно простого примера представим, что мы хотим поприветствовать 8 студентов в классе, используя R:
paste('Hello','John') paste('Hello','Susan') paste('Hello','Matt') paste('Hello','Anne') paste('Hello','Joe') paste('Hello','Tyson') paste('Hello','Julia') paste('Hello','Cathy')
Вы повторяете один и тот же код несколько раз, меняя только имя ученика. По вашему мнению, это должно немедленно вызвать необходимость использования функции:
GreetStudent <- function(name) { paste(‘Hello’,name) } class_names <- c(‘John’, ‘Susan’, ‘Matt’ ,’Anne’, ‘Joe’, ‘Tyson’, ‘Julia’, ‘Cathy’) for (student in class_names){ print(GreetStudent(student)) }
Замечательно то, что теперь вы можете добавить больше учеников в наш вектор class_names и избежать повторения команды вставки несколько раз!
Функции действительно являются одной из самых мощных концепций в R. На них следует полагаться несколько раз, поскольку они сделают наш код эффективным и тестируемым.
И это все! Есть что еще добавить?
Есть много передовых методов, которые я здесь не описал, и, вероятно, гораздо больше, о которых я сам не знаю. Что меня восхищает в языках с открытым исходным кодом, так это то, насколько быстро они развиваются и как сообщество поддерживает друг друга в разработке лучших программ и сценариев для достижения более высокой производительности для каждого.
В заключение помните, что изучение нового языка - это навык, требующий времени, и практически невозможно быть всезнайкой. У всех вокруг вас, независимо от того, насколько они старшие в своем языке, всегда есть чему поучиться, и этот образ мышления обучения - лучший вариант для того, чтобы стать лучше профессионалом и человеком в целом.
Не стесняйтесь обращаться, и если вы хотите узнать больше о R, вы можете присоединиться к моему курсу программирования R здесь: Курс программирования R для абсолютных новичков
Спасибо, что нашли время прочитать этот пост! Не стесняйтесь добавлять меня в LinkedIn (https://www.linkedin.com/in/ivobernardo/) и проверять веб-сайт моей компании (https://daredata.engineering/home).
Если вы заинтересованы в обучении по аналитике и науке о данных, вы также можете посетить мою страницу на Udemy (https://www.udemy.com/user/ivo-bernardo/)
Эта лекция взята из моего Курса программирования R, доступного на платформе Udemy - курс подходит для новичков и людей, которые хотят изучить основы программирования на языке R. Курс также содержит более 50 упражнений по программированию, которые позволят вам попрактиковаться в изучении новых концепций.