Заметки по языку R — это серия статей, в которых я собираю наиболее интересные публикации канала R4marketing из рубрики "#заметки_по_R".
В прошлый раз мы говорили о нетипичных визуализациях, сегодняшняя подборка состоит из описания приёмов, которые свойственны и горячо любимы пользователям Python, но большинство пользователей R о них не знают.
Для пользователей Python эта статья будет полезна тем, что они найдут реализацию своих любимых приёмов в другом языке, для пользователей R статья будет полезна тем, что они откроют для себя изящные приёмы Python, и смогут перенести их в свои R проекты.

Содержание
Если вы интересуетесь анализом данных возможно вам будут полезны мои telegram и youtube каналы. Большая часть контента которых посвящены языку R.
Декораторы в R
На самом деле декораторы широко применяются в Python и горячо любимы пользователям этого языка, а в R они пока не получили широкого распространения. Тем не менее в R тоже можно реализовывать декорирование функций.
Немного теории:
Декораторы — это, по сути, «обёртки», которые дают нам возможность изменить поведение функции, не изменяя её код.
Визуально изображение ниже помогает понять смысл декораторов.

Первоначальная функция — автомобиль. Декоратор добавляет к машине антенну и крыло, но основной функционал машины (перевозка людей) остается неизменным.
Реализация декораторов в R
Базовый скелет декораторов выглядит следующим образом:
deco <- function(f) { wrapper <- function(...) { # <код до выполнения основной функции> res <- f(...) # <код после выполнения основной функции> return(res) } return(wrapper) }
Ниже представлен пример декоратора, который выводит время начала и завершения выполнения задекорированной функции:
timer <- function(f) { wrapper <- function(...) { # Перед выполнением op <- options(digits.secs = 6) # увеличиваем точность выводимого времени print(paste("Ini time:", Sys.time())) # Показываем время начала выполнения res <- f(...) # После выполнения print(paste("End time:", Sys.time())) # Показываем время завершения выполнения return(res) } return(wrapper) }
Теперь задекорируем функцию cos() из базового R и используем её задекорированную версию.
# декорируем cos() cos_timed <- timer(cos) # используем cos_timed(3.1416) # альтернативный укороченный вариант использования timer(cos)(3.1418)
Пакет tinsel
Мы привели пример декоратора в R, но выглядят приведённые примеры в R всё ещё не так привлекательно как в Python:
# Пример декоратора в Python @decorator def f(args): # <function body>
Добавить синтаксического сахара в реализацию декораторов в R поможет пакет tinsel. Он позволяет применять декораторы с помощь специального синтаксиса комментариев. Например, что бы задекорировать функцию написанным ранее декоратором timer, достаточно использовать комментарий #. timer.
#. timer say_hi <- function(name) { return(paste("Hi", name, sep = " ")) }
Эта заметка является неполным передом статьи «Decorators in R».
Множественное присваивание
Множественное присваивание, так же как и декораторы, горячо любимо пользователями Python. Этот приём даёт возможность присвоить одновременно значения сразу нескольким объектам. Множественное присваивание в Python используется например для обмена значений между двумя переменными, не используя при этом третью, временную переменную. Также его удобно использовать в случаях, когда функция возвращает набор значений в виде списка, например summary(). Тогда вы можете распаковать её результат сразу в несколько переменных, поэтому множественное присваивание также иногда называют распаковочным, параллельным или деструктурирующим.
В базовом R аналога этой операции нет, но как мы помним, в R на любой чих есть готовый паке. Для множественного присваивания можно использовать оператор %<-% из пакета zeallot.
Ниже несколько примеров его использования:
# распаковываем список или вектор c(lat, lng) %<-% list(38.061944, -122.643889) c(lat, lng) %<-% c(38.061944, -122.643889) # распаковываем результат выполнения функции c(min_wt, q1_wt, med_wt, mean_wt, q3_wt, max_wt) %<-% summary(mtcars$wt) # ещё один пример распаковки функции coords_list <- function() { list(38.061944, -122.643889) } c(lat, lng) %<-% coords_list() # используем в паре с lapply quartet <- lapply(1:4, function(i) anscombe[, c(i, i + 4)]) c(an1, an2, an3, an4) %<-% lapply(quartet, head, n = 3) # распаковка вложенных списков c(a, c(b, d), e) %<-% list("begin", list("middle1", "middle2"), "end") # распаковка даты c(y, m, d) %<-% Sys.Date() # меняем местами значения # без использования временной переменной c(first, last) %<-% c("Ai", "Genly") c(first, last) %<-% c(last, first)
Ссылка на заметку.
Списковые включения
Списковое включение – это некий синтаксический сахар, позволяющий упростить генерацию последовательностей. Этот приём, аналогично рассмотренным выше, очень распространён в Python, но в R о нём знают не многие, а используют ещё меньше.
Списковые включения, или как их ещё называют — генераторы списков, в Python выглядят следующим образом: a = [i for i in range(1,15)].
В результате вы получите следующий список (не путайте со списками в R, в Python список наиболее похож на вектор из R): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14].
Пример не самый выразительный, но он демонстрирует в простейшем виде синтаксис списковых включений в Python. (Конкретно этот пример в R можно заменить на a <- 1:14).
Аналог списковых включений в R
В базовом R пока нет аналога генераторов списков, но они реализованы в пакете comprehenr.
Пакет включает три основные функции:
-
to_list()— генерация списков; -
to_vec()— генерация векторов; -
alter()— приводит преобразование над объектом, и возвращает объект того же типа, что и входящий, но уже с преобразованными значениями (из приведённых примеров кода, понять смысл этого определения будет проще).
Примеры:
library(comprehenr) to_vec(for(i in 1:10) if(i %% 2==0) i*i) to_list(for (x in 1:20) for (y in x:20) for (z in y:20) if (x^2 + y^2 == z^2) c(x, y, z)) colours = c("red", "green", "yellow", "blue") things = c("house", "car", "tree") to_vec(for(x in colours) for(y in things) paste(x, y)) # преобразование фактора в текстовый тип res = alter(for(i in iris) if(is.factor(i)) as.character(i)) # удаление столбцов - факторов res = alter(for(i in iris) if(is.factor(i)) exclude())
Индексирование с нуля
Значимой разницей в R и Python является индексирование. По умолчанию в Python индексация элементов объектов начинается с нуля, а в R с единицы.

Если вы привыкли к индексации в Python, использовать её в R позволяет пакет index0.
library(index0) letters0 <- as.index0(letters) numbers0 <- as.index0(c(2, 3, 4, 5, 6)) letters0[0] #> [1] "a" #> indexed from 0 numbers0[0] #> [1] 2 #> indexed from 0 letters0[c(1, 2, 4)] #> [1] "b" "c" "e" #> indexed from 0 numbers0[c(1, 3)] <- NA numbers0 #> [1] 2 NA 4 NA 6 #> indexed from 0
Заметка родилась из статьи «Indexing from zero in R».
Обработка исключений (try — except)
В базовом Python обработка исключений зачастую реализуется конструкцией try-except, которая имеет следующий синтаксис:
try: ~ Тут код который будет выполняться ~ except Exception: ~ Код который будет выполняться в случае возникновения ошибки в блоке try ~ finally: ~ Код который будет выполняться в любом случае, не зависимо от того закончилось выражение try ошибкой или нет ~т ~
Аналогом этой операции в R является конструкция tryCatch(), которая имеет следующий синтаксис:
tryCatch(expr = { ~ Тут код который будет выполняться ~ }, error = function(err) { ~ Код который будет выполняться в случае возникновения ошибки в блоке expr ~ }, finally = { ~ Код который будет выполняться в любом случае, не зависимо от того закончилось выражение expr ошибкой или нет ~ })
Более подробно изучить конструкцию tryCatch() можно посмотрев следующее видео:
Классическое объектно ориентированное программирование
Ключевая разница между R и Python заключаются в том, что эти языки используют разные парадигмы программирования:
-
R — функциональный язык программирования;
-
Python — объектно ориентированный язык программирования.
По умолчанию в базовом R ООП реализовано на S3 классах и обобщённых функциях. Подробнее об этом можно узнать из статьи «ООП в языке R (часть 1): S3 классы».
Но, так же в R вам доступно и классическое ООП, которое в этом языке реализовано в отдельном пакете — R6.
Ниже приведён пример кода, построения класса Cat, включающий в себя несколько свойств и методов.
library(R6) # создаём класс Cat Cat <- R6Class(classname = "Cat", public = list( name = "Tom", breed = "Persian", age = 3, rename = function(name = NULL) { self$name <- name invisible(self) }, add_year = function(ages = 1) { self$age <- self$age + ages invisible(self) } ) ) # инициализируем объект класса Cat tom <- Cat$new() # используем метод rename tom$rename('Tommy')
Более подробно про классическое объектно ориентирование программирование в R можно узнать из статьи «ООП в языке R (часть 2): R6 классы».
Логирование (logging)
Модуль logging поставляется с базовой комплектацией Python, в базовом R подобный функционал мне не известен, но он реализован в пакете lgr.
Пример создания простейшего логгера в R, с помощью пакета lgr:
# создаём обычный логгер lg <- get_logger('simple logger') # выводим информационное сообщение lg$info('Is %s', 'test message!')
Подробно узнать о работе с пакетом lgr можно из статьи «Логирование выполнения скриптов на языке R, пакет lgr» или следующего видео:
Работа с табличными данными
В Python вся работа с табличными данными зачастую реализуется средствами библиотеки pandas. Уэс Мак-Кинни начал разработку pandas под вдохновением от работы с данными на языке R.
В R есть несколько средств манипуляции данными:
-
Базовый синтаксис
data.frame -
Пакеты
dplyrиtidyr -
Пакет
data.table
Тема манипуляции табличными данными очень обширная, и не поместиться в раздел одной статьи, поэтому я более подробно описал примеры манипуляции данных на R и Python в статье «Какой язык выбрать для работы с данными — R или Python? Оба! Мигрируем с pandas на tidyverse и data.table и обратно».
Заключение
В этой статье я продемонстрировал несколько приёмов в R, которые довольно популярны среди пользователей Python, но знакомы далеко не всем пользователям R.
На самом деле я искрене надеюсь, что статья будет полезна как пользователям R, так и пользователям Python, которые планируют ознакомится с возможностями R.
Буду рад видеть вас в рядах подписчиков моего telegram и youtube каналов.
Делитесь в комментариях другими интересными приёмами, которые мигрировали из одного языка в другой.
ссылка на оригинал статьи https://habr.com/ru/articles/587480/
Добавить комментарий