¿Qué significa "métodos S3" en R?

124

Como soy bastante nuevo en R, no sé cuáles son los métodos y objetos S3. Descubrí que hay sistemas de objetos S3 y S4, y algunos recomiendan usar S3 sobre S4 si es posible (consulte la Guía de estilo R de Google en http://google-styleguide.googlecode.com/svn/trunk/google-r-style. html ) *. Sin embargo, no sé la definición exacta de los métodos / objetos S3.

Actualización: a partir de 2019, el hipervínculo de la Guía de estilo R de Google ya está aquí .

jiggysoo
fuente

Respuestas:

85

La mayor parte de la información relevante se puede encontrar mirando ?S3o ?UseMethod, pero en pocas palabras:

S3 se refiere a un esquema de envío de métodos. Si ha utilizado R por un tiempo, se dará cuenta de que hay print, predicty summarymétodos para una gran cantidad de diferentes tipos de objetos.

En S3, esto funciona por:

  • establecer la clase de objetos de interés (por ejemplo: el valor de retorno de una llamada al método glmtiene clase glm)
  • proporcionando un método con el nombre general (por ejemplo print), entonces un punto, y después el nombre de clase (por ejemplo: print.glm)
  • Se debe haber hecho alguna preparación para este nombre general ( print) para que esto funcione, pero si simplemente está buscando ajustarse a los nombres de métodos existentes, no necesita esto (consulte la ayuda que mencioné anteriormente si lo hace )

Para el observador, y particularmente, para el usuario de su paquete de ajuste de modelo funky recién creado, es mucho más conveniente poder escribir predict(myfit, type="class")que predict.mykindoffit(myfit, type="class").

Hay bastante más, pero esto debería ayudarlo a comenzar. Existen bastantes desventajas en esta forma de enviar métodos basados ​​en un atributo (clase) de objetos (y los puristas de C probablemente permanecen despiertos por la noche horrorizados), pero para muchas situaciones, funciona decentemente. Con la versión actual de R, se han implementado formas más nuevas (S4 y clases de referencia), pero la mayoría de las personas todavía (solo) usan S3.

Nick Sabbe
fuente
54

Para comenzar con S3, mire el código de la medianfunción. Escribir medianen el símbolo del sistema revela que tiene una línea en su cuerpo, a saber

UseMethod("median")

Eso significa que es un método S3. En otras palabras, puede tener una medianfunción diferente para diferentes clases de S3. Para enumerar todos los métodos de mediana posibles, escriba

methods(median) #actually not that interesting.  

En este caso, solo hay un método, el predeterminado, que se llama para cualquier cosa. Puede ver el código para eso escribiendo

median.default

Un ejemplo mucho más interesante es la printfunción, que tiene muchos métodos diferentes.

methods(print)  #very exciting

Tenga en cuenta que algunos de los métodos tienen *s junto a su nombre. Eso significa que están ocultos dentro del espacio de nombres de algunos paquetes. Úselo findpara averiguar en qué paquete están. Por ejemplo

find("acf")  #it's in the stats package
stats:::print.acf
Algodón Richie
fuente
39

De http://adv-r.had.co.nz/OO-essentials.html :

Los tres sistemas OO de R difieren en cómo se definen las clases y los métodos:

  • S3 implementa un estilo de programación OO llamado función genérica OO. Esto es diferente de la mayoría de los lenguajes de programación, como Java, C ++ y C #, que implementan OO de paso de mensajes. Con el paso de mensajes, los mensajes (métodos) se envían a los objetos y el objeto determina a qué función llamar. Normalmente, este objeto tiene una apariencia especial en la llamada al método, que generalmente aparece antes del nombre del método / mensaje: por ejemplo, canvas.drawRect ("azul"). S3 es diferente. Si bien los cálculos aún se realizan a través de métodos, un tipo especial de función llamada función genérica decide a qué método llamar, por ejemplo, drawRect (canvas, "azul"). S3 es un sistema muy informal. No tiene una definición formal de clases.

  • S4 funciona de manera similar a S3, pero es más formal. Hay dos diferencias principales con S3. S4 tiene definiciones de clase formales, que describen la representación y la herencia de cada clase, y tiene funciones auxiliares especiales para definir genéricos y métodos. S4 también tiene despacho múltiple, lo que significa que las funciones genéricas pueden elegir métodos basados ​​en la clase de cualquier número de argumentos, no solo uno.

  • Las clases de referencia, llamadas RC para abreviar, son bastante diferentes de S3 y S4. RC implementa OO de paso de mensajes, por lo que los métodos pertenecen a clases, no a funciones. $ se usa para separar objetos y métodos, por lo que las llamadas a métodos se parecen al lienzo $ drawRect ("azul"). Los objetos RC también son mutables: no usan la semántica habitual de copiar para modificar de R, pero se modifican en su lugar. Esto los hace más difíciles de razonar, pero les permite resolver problemas que son difíciles de resolver con S3 o S4.

También hay otro sistema que no es OO, pero es importante mencionarlo aquí:

  • tipos base, los tipos internos de nivel C que subyacen a los otros sistemas OO. Los tipos base se manipulan principalmente utilizando el código C, pero es importante conocerlos porque proporcionan los componentes básicos para los otros sistemas OO.
Amit K Thakur
fuente
11

Llegué a esta pregunta principalmente preguntándome de dónde venían los nombres. Parece de este artículo de Wikipedia que el nombre se refiere a la versión del lenguaje de programación S en el que se basa R. Los esquemas de envío de métodos descritos en las otras respuestas provienen de S y están etiquetados apropiadamente según la versión.

Jonathan Adelson
fuente
10

Tratar

methods(residuals)

que enumera, entre otros, "residuals.lm" y "residuals.glm". Esto significa que cuando ha ajustado un modelo lineal, my tiporesiduals(m), se llamará residuals.lm. Cuando haya ajustado un modelo lineal generalizado, se llamará residuals.glm. Es una especie de modelo de objetos C ++ al revés. En C ++, usted define una clase base que tiene funciones virtuales, que son anuladas por derivadas clasificadas. En R define una función virtual (también conocida como genérica) y luego decide qué clases anularán esta función (también conocida como definir un método). Tenga en cuenta que las clases que hacen esto no necesitan derivarse de una superclase común. No estaría de acuerdo en preferir generalmente S3 sobre S4. S4 tiene más formalismo (= más tipeo) y esto puede ser demasiado para algunas aplicaciones. Sin embargo, las clases S4 se pueden definir como una clase o estructura en C ++. Puede especificar que un objeto de una determinada clase esté formado por una cadena y dos números, por ejemplo:

setClass("myClass", representation(label = "character", x = "numeric", y = "numeric"))

Los métodos que se llaman con un objeto de esa clase pueden confiar en que el objeto tenga esos miembros. Eso es muy diferente de las clases S3, que son solo una lista de un montón de elementos.

Con S3 y S4, llama a una función miembro por fun(object, args)y no por object$fun(args). Si está buscando algo como esto último, eche un vistazo al paquete proto.

Harald Brendel
fuente
Estoy bastante seguro de que la idea de funciones miembro y métodos que pertenecen a objetos no tiene mucho sentido en R. Los métodos no pertenecen a objetos (también las funciones también son objetos) sino que pertenecen a la función.
petermeissner
3

Aquí hay un resumen rápido actualizado de los numerosos sistemas de objetos R de acuerdo con "Advanced R, 2nd edition" (CRC Press, 2019) de Hadley Wickham (Chief Scientist en RStudio), que tiene una representación web aquí , basada en el capítulo sobre Object -Programación orientada .

Portada de libro avanzada R

La primera edición de 2015 tiene una representación web aquí , con el capítulo correspondiente sobre OO aquí .

Enfoques de los sistemas OO

Hadley define lo siguiente para distinguir dos enfoques distintos para la programación OO:

OOP funcional : los métodos (piezas de código invocables) pertenecen a funciones genéricas (no deben confundirse con los métodos genéricos Java / C # ). Piense en los métodos como ubicados en una tabla de búsqueda global. El sistema de tiempo de ejecución encuentra el método a ejecutar en función del nombre de la función y el tipo (o clase de objeto) de uno o más argumentos pasados ​​a esa función (esto se denomina "envío de método"). Sintaxis-sabia, las llamadas de método puede parecer como llamadas a funciones comunes: myfunc(object, arg1, arg2). Esta llamada llevaría al tiempo de ejecución a buscar el método asociado al par ("myfunc", typeof (objeto)) o posiblemente ("myfunc", typeof (objeto), typeof (arg1), typeof (arg2))si el idioma lo admite. En el S3 de R, el nombre completo de la función genérica proporciona el par (nombre-función, clase) . Por ejemplo:mean.Datees el método para calcular la media de las fechas. Intente methods("mean")enumerar los métodos genéricos con el nombre de la función mean. El enfoque de OOP funcional se encuentra, por ejemplo, en el pionero de OO Smalltalk , Common Lisp Object System y Julia . Hadley señala que "en comparación con R, la implementación de Julia está completamente desarrollada y es extremadamente eficiente".

OOP encapsulada : los métodos pertenecen a objetos o clases, y las llamadas a métodos suelen ser similares object.method(arg1, arg2). Esto se denomina encapsulado porque el objeto encapsula tanto los datos (campos) como el comportamiento. (métodos). Piense en el método como ubicado en una tabla de búsqueda adjunta al objeto o la descripción de clase del objeto. El tiempo de ejecución busca el método en función del nombre del método y posiblemente del tipo de uno o más argumentos. Este es el enfoque que se encuentra en los lenguajes OO "populares" como C ++, Java, C #.

En ambos casos, si se admite la herencia (probablemente lo sea), el tiempo de ejecución puede atravesar la jerarquía de clases hacia arriba hasta que encuentre una coincidencia para la clave de búsqueda de llamadas.

Cómo averiguar a qué sistema pertenece un objeto R

library(sloop) # formerly, "pryr"
otype(mtcars)
#> [1] "S3"

Los sistemas de objetos R

S3

  • Enfoque funcional de OOP.
  • El sistema más importante según Hadley.
  • Más simple, más común. Primer sistema OO utilizado por R.
  • Viene con la base R, utilizada en toda la base R.
  • Se basa en convenciones en lugar de garantías forzadas.
  • Ver Chambers, John M y Trevor J Hastie. 1992. "Modelos estadísticos en S." Wadsworth & Brooks / Cole Advanced Books & Software.
  • Detalles en "Advanced R, 2nd edition" aquí .

S4

  • Enfoque funcional de OOP.
  • Tercer sistema más importante según Hadley.
  • Reescribe S3, por lo tanto similar a S3, pero más formal y más estricto: te obliga a pensar cuidadosamente sobre el diseño del programa. Adecuado para la construcción de grandes sistemas (por ejemplo, el proyecto Bioconductor ).
  • Implementado en el paquete base de "métodos".
  • Ver: Chambers, John M. 1998. "Programación con datos: una guía para el lenguaje S". Saltador.
  • Detalles en "Advanced R, 2nd edition" aquí .

RC también conocido como "Clases de referencia"

  • Enfoque OOP encapsulado.
  • Viene con base R.
  • Basado en S4.
  • Los objetos RC son un tipo especial de objetos S4 que también son "mutables". es decir, en lugar de utilizar la semántica habitual de copiar y modificar de R, se pueden modificar en el lugar. Tenga en cuenta que el estado mutable es difícil de razonar y una fuente de errores feos, pero puede conducir a un código más eficiente en ciertas aplicaciones.

R6

  • Enfoque OOP encapsulado.
  • Segundo sistema más importante según Hadley.
  • Se puede encontrar en el paquete R6 (instalar con library(R6))
  • Similar a RC, pero más ligero y mucho más rápido: no depende de S4 o los métodos paquete de . Construido en la parte superior de los entornos R. También tiene:
    • métodos públicos y privados
    • enlaces activos (campos, que, cuando se accede, en realidad llaman a un método)
    • clase de herencia que funciona en paquetes
    • ambos métodos de clase (de código que pertenece a la clase y pueden acceder a una instancia a través de self, private, super) y funciones miembro (funciones asignadas a los campos, pero que no son métodos, funciones sólo)
  • Proporciona una forma estandarizada de escapar de la semántica de "copiar en modificar" de R
  • Consulte el sitio del paquete: "R6: Programación encapsulada orientada a objetos para R" .
  • Detalles en "Advanced R, 2nd edition" aquí .

Otros

Hay otros, como R.oo (similar a RC), proto (basado en prototipos, piense en JavaScript) y Mutatr . Sin embargo, "Advanced R" dice:

Además de R6, que es ampliamente utilizado, estos sistemas son principalmente de interés teórico. Tienen sus puntos fuertes, pero pocos usuarios de R los conocen y los entienden, por lo que es difícil para otros leer y contribuir a su código.

Asegúrese de leer también el capítulo sobre compensaciones en "Advanced R, 2nd edition" .

David Tonhofer
fuente