Что означает "методы S3" в R?
Поскольку я довольно плохо знаком с R, я не знаю, что такое методы и объекты S3. Я обнаружил, что существуют объектные системы S3 и S4, и некоторые рекомендуют использовать S3 поверх S4, если это возможно (http://google-styleguide.googlecode.com/svn/trunk/google-r-style.html). Однако я не знаю точного определения методов / объектов S3.
5 ответов
Большую часть соответствующей информации можно найти, посмотрев на ?S3
или же ?UseMethod
, но в двух словах:
S3 относится к схеме метода диспетчеризации. Если вы использовали R некоторое время, вы заметите, что есть print
, predict
а также summary
методы для множества различных видов объектов.
В S3 это работает:
- установка класса объектов интереса (например: возвращаемое значение вызова метода
glm
имеет классglm
) - предоставление метода с общим именем (например,
print
), затем точка, а затем имя класса (например:print.glm
) - к этому общему имени должна была быть сделана некоторая подготовка (
print
), чтобы это работало, но если вы просто хотите согласовать себя с существующими именами методов, вам это не нужно (см. справку, на которую я ссылался ранее, если вы это сделаете).
На взгляд смотрящего, и в частности, пользователя вашей недавно созданной прикольной комплектации, гораздо удобнее набирать текст predict(myfit, type="class")
чем predict.mykindoffit(myfit, type="class")
,
Есть еще кое-что, но это должно помочь вам начать. У такого способа диспетчеризации методов есть несколько недостатков, основанных на атрибуте (классе) объектов (и пуристы Си, вероятно, не спят ночью в ужасе от него), но для многих ситуаций он работает прилично. В текущей версии R были реализованы более новые способы (S4 и справочные классы), но большинство людей все еще (только) используют S3.
Чтобы начать работу с S3, посмотрите код median
функция. Typing median
в командной строке показывает, что он имеет одну строку в своем теле, а именно
UseMethod("median")
Это означает, что это метод S3. Другими словами, вы можете иметь другой median
функция для разных классов S3. Чтобы перечислить все возможные срединные методы, введите
methods(median) #actually not that interesting.
В этом случае есть только один метод по умолчанию, который вызывается для чего угодно. Вы можете увидеть код для этого, набрав
median.default
Гораздо более интересным примером является print
функция, которая имеет много разных методов.
methods(print) #very exciting
Обратите внимание, что некоторые из методов имеют *
рядом с их именем. Это означает, что они скрыты внутри пространства имен какого-либо пакета. использование find
чтобы выяснить, в какой упаковке они находятся. Например,
find("acf") #it's in the stats package
stats:::print.acf
С http://adv-r.had.co.nz/OO-essentials.html:
Три ОО-системы R отличаются в том, как определяются классы и методы:
S3 реализует стиль OO-программирования, называемый OO обобщенной функции. Это отличается от большинства языков программирования, таких как Java, C++ и C#, которые реализуют ОО с передачей сообщений. При передаче сообщений сообщения (методы) отправляются объектам, и объект определяет, какую функцию вызывать. Как правило, этот объект имеет особый внешний вид в вызове метода, как правило, появляется перед именем метода / сообщения: например, canvas.drawRect("синий"). S3 отличается. Хотя вычисления по-прежнему выполняются с помощью методов, специальный тип функции, называемый обобщенной функцией, решает, какой метод вызывать, например drawRect(canvas, "blue"). S3 очень случайная система. У него нет формального определения классов.
S4 работает аналогично S3, но более формально. Есть два основных отличия от S3. S4 имеет формальные определения классов, которые описывают представление и наследование для каждого класса, и имеет специальные вспомогательные функции для определения обобщений и методов. S4 также имеет множественную диспетчеризацию, что означает, что универсальные функции могут выбирать методы, основанные на классе любого количества аргументов, а не только одного.
Эталонные классы, для краткости называемые RC, весьма отличаются от S3 и S4. RC реализует ОО с передачей сообщений, поэтому методы принадлежат классам, а не функциям. $ используется для разделения объектов и методов, поэтому вызовы методов выглядят как canvas$drawRect("blue"). Объекты RC также являются изменяемыми: они не используют обычную семантику R при копировании при модификации, но модифицируются на месте. Это затрудняет их рассуждение, но позволяет решать проблемы, которые трудно решить с помощью S3 или S4.
Есть также еще одна система, которая не совсем ОО, но важно упомянуть здесь:
- базовые типы, внутренние типы уровня C, которые лежат в основе других ОО-систем. Базовыми типами в основном манипулируют с использованием кода на C, но о них важно знать, потому что они обеспечивают строительные блоки для других ОО-систем.
Я пришел к этому вопросу, задаваясь вопросом, откуда берутся имена. Из этой статьи википедии следует, что название относится к версии языка программирования S, на котором основан R. Схемы диспетчеризации методов, описанные в других ответах, взяты из S и помечены соответствующим образом в соответствии с версией.
Пытаться
methods(residuals)
который перечисляет, среди прочего, "residuals.lm" и "residuals.glm". Это означает, что когда вы установили линейную модель, m и тип residuals(m)
, residuals.lm будет вызываться. Когда вы укажете обобщенную линейную модель, будет вызван residuals.glm. Это своего рода объектная модель C++, перевернутая с ног на голову. В C++ вы определяете базовый класс, имеющий виртуальные функции, которые переопределяются производным классом. В R вы определяете виртуальную (также называемую универсальной) функцию, а затем решаете, какие классы будут переопределять эту функцию (или определять метод). Обратите внимание, что классы, делающие это, не должны быть производными от одного общего суперкласса. Я бы не согласился вообще предпочесть S3, а не S4. S4 имеет больше формализма (= больше печатания), и это может быть слишком много для некоторых приложений. Классы S4, однако, могут быть определены как класс или структура в C++. Вы можете указать, что объект определенного класса состоит из строки и двух чисел, например:
setClass("myClass", representation(label = "character", x = "numeric", y = "numeric"))
Методы, которые вызываются с объектом этого класса, могут полагаться на объект, имеющий эти члены. Это сильно отличается от классов S3, которые представляют собой просто список элементов.
С S3 и S4 вы вызываете функцию-член fun(object, args)
и не object$fun(args)
, Если вы ищете что-то вроде последнего, посмотрите на пакет proto.
Вот обновленное краткое изложение многочисленных систем объектов R в соответствии с "Advanced R, 2nd edition" (CRC Press, 2019) Хэдли Уикхэм (главный научный сотрудник RStudio), веб-представление которого здесь основано на главе об объектах -Ориентированное программирование.
Первое издание 2015 года представлено здесь в сети, а соответствующая глава по объектно-ориентированному программированию находится здесь.
Подходы к ОО-системам
Хэдли определяет следующее, чтобы различать два различных подхода к объектно-ориентированному программированию:
Функциональное ООП: методы (вызываемые фрагменты кода) относятся к универсальным функциям (не путать с универсальными методами Java/C#). Думайте о методах, как о находящихся в глобальной таблице поиска. Метод для выполнения определяется системой времени выполнения на основе имени функции и типа (или класса объекта) одного или нескольких аргументов, переданных этой функции (это называется "отправкой метода"). С точки зрения синтаксиса вызовы методов могут выглядеть как обычные вызовы функций:myfunc(object, arg1, arg2)
. Этот вызов заставит среду выполнения искать метод, связанный с парой ("myfunc", typeof(объект)) или, возможно, ("myfunc", typeof(объект), typeof(arg1), typeof(arg2)), если язык поддерживает это. В R S3 полное имя универсальной функции дает пару (имя-функция, класс). Например:mean.Date
- это метод вычисления среднего числа дат. Пытатьсяmethods("mean")
чтобы перечислить общие методы с именем функции mean
. Функциональный подход ООП можно найти, например, в Smalltalk, пионере ООП, в объектной системе Common Lisp и в Julia. Хэдли отмечает, что "По сравнению с R, реализация Джулии полностью разработана и чрезвычайно эффективна".
Инкапсулированное ООП: методы принадлежат объектам или классам, и вызовы методов обычно выглядят так:object.method(arg1, arg2)
. Это называется инкапсулированным, потому что объект инкапсулирует как данные (поля), так и поведение (методы). Подумайте о методе, который находится в таблице поиска, прикрепленной к объекту или описанию класса объекта. Среда выполнения ищет метод на основе имени метода и, возможно, типа одного или нескольких аргументов. Это подход, применяемый в "популярных" объектно-ориентированных языках, таких как C++, Java, C#.
В обоих случаях, если поддерживается наследование (возможно, так оно и есть), среда выполнения может перемещаться по иерархии классов вверх, пока не найдет совпадение для ключа поиска вызова.
Как узнать, к какой системе принадлежит объект R
library(sloop) # formerly, "pryr"
otype(mtcars)
#> [1] "S3"
Объектные системы R
S3
- Функциональный подход ООП.
- Самая важная система по Хэдли.
- Самый простой, самый распространенный. Первая объектно-ориентированная система, использованная Р.
- Поставляется с базой R, используется во всей базе R.
- Скорее полагается на условности, чем на принудительные гарантии.
- См. Чемберс, Джона М. и Тревора Дж. Хасти. 1992."Статистические модели в С." Уодсворт и Брукс / Продвинутые книги и программное обеспечение Коула.
- Подробности в "Advanced R, 2nd edition" здесь.
S4
- Функциональный подход ООП.
- Третья по важности система по Хэдли.
- Перепишите S3, следовательно, аналогично S3, но более формально и строго: это заставляет вас тщательно продумать дизайн программы. Подходит для создания больших систем (например, для проекта Bioconductor).
- Реализовано в базовом пакете "методы".
- См.: Чемберс, Джон М. 1998. "Программирование с данными: руководство по S-языку". Springer.
- Подробности в "Advanced R, 2nd edition" здесь.
РЦ он же "Референсные классы"
- Инкапсулированный подход ООП.
- Поставляется с базой R.
- На основе S4.
- Объекты RC - это особый тип объектов S4, которые также "изменяемы". т.е. вместо использования обычной семантики копирования при изменении в R они могут быть изменены на месте. Обратите внимание, что об изменяемом состоянии сложно рассуждать, и он является источником уродливых ошибок, но может привести к более эффективному коду в определенных приложениях.
R6
- Инкапсулированный подход ООП.
- Вторая по важности система по Хэдли.
- Можно найти в пакете R6 (установить с
library(R6)
) - Подобно RC, но легче и намного быстрее: это не зависит от S4 или пакета методов. Создан на основе среды R. Также имеет:
- публичные и частные методы
- активные привязки (поля, которые при доступе фактически вызывают метод)
- наследование классов, которое работает между пакетами
- оба метода класса (код, который принадлежит классу и может получить доступ к экземпляру через
self
,private
,super
) и функции-члены (функции, назначенные полям, но не методы, а просто функции)
- Предоставляет стандартизированный способ избежать семантики R "копирование при изменении"
- См. Сайт пакета: "R6: Инкапсулированное объектно-ориентированное программирование для R".
- Подробности в "Advanced R, 2nd edition" здесь.
Другие
Есть и другие, такие как R.oo (похожий на RC), proto (на основе прототипов, думаю, JavaScript) и Mutatr. Однако "Advanced R" говорит:
Помимо широко применяемого R6, эти системы представляют прежде всего теоретический интерес. У них есть свои сильные стороны, но немногие пользователи R знают и понимают их, поэтому другим трудно читать и вносить свой вклад в ваш код.
Не забудьте также прочитать главу о компромиссах в "Advanced R, 2nd edition".