org - ¿Qué significa "métodos S3" en R?
r studiodio (5)
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 (http://google-styleguide.googlecode.com/svn/trunk/google-r-style.html). Sin embargo, no conozco la definición exacta de los métodos / objetos S3.
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 OO de función genérica. Esto es diferente de la mayoría de los lenguajes de programación, como Java, C ++ y C #, que implementa OO de paso de mensajes. Con el paso de mensajes, los mensajes (métodos) se envían a 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. Mientras que los cálculos se siguen realizando a través de métodos, un tipo especial de función llamada función genérica decide qué método llamar, por ejemplo, drawRect (canvas, "blue"). 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 para 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 cantidad 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 las clases, no a las funciones. $ se usa para separar objetos y métodos, por lo que las llamadas a métodos se ven como canvas $ drawRect ("blue"). Los objetos RC también son mutables: no usan la semántica habitual de copiar-en-modificar de R, sino que 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 completamente OO, pero es importante mencionar aquí:
- tipos base, los tipos internos de nivel C que subyacen en los otros sistemas OO. Los tipos base se manipulan principalmente con el código C, pero es importante conocerlos porque proporcionan los componentes básicos para los otros sistemas OO.
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 que se basa R. Los esquemas de despacho de métodos descritos en las otras respuestas provienen de S y están etiquetados apropiadamente según la versión.
Para comenzar con S3, mire el código para la función median
. Escribir la median
en el símbolo del sistema revela que tiene una línea en su cuerpo, es decir
UseMethod("median")
Eso significa que es un método S3. En otras palabras, puede tener una función median
diferente para diferentes clases S3. Para enumerar todos los métodos medianos 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 función de print
, que tiene muchos métodos diferentes.
methods(print) #very exciting
Observe 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. Use find
para descubrir en qué paquete se encuentran. Por ejemplo
find("acf") #it''s in the stats package
stats:::print.acf
Tratar
methods(residuals)
que enumera, entre otros, "residuals.lm" y "residuals.glm". Esto significa que cuando haya ajustado un modelo lineal, m, y escriba residuals(m)
, se invocará residuals.lm. Cuando haya ajustado un modelo lineal generalizado, se invocará residuals.glm. Es una especie de modelo de objetos C ++ invertido. En C ++, usted define una clase base que tiene funciones virtuales, que son anuladas por derivadas clasificadas. En R, usted define una función virtual (también conocida como genérica) y luego decide qué clases anularán esta función (es decir, definir un método). Tenga en cuenta que las clases que hacen esto no necesitan derivarse de una superclase común. No estoy de acuerdo con que generalmente prefiera S3 a S4. S4 tiene más formalismo (= más tipeo) y esto puede ser demasiado para algunas aplicaciones. Sin embargo, las clases de S4 se pueden definir como una clase o estructura en C ++. Puede especificar que un objeto de una cierta clase se compone de 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 el objeto que tiene esos miembros. Eso es muy diferente de las clases S3, que son solo una lista de varios 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.
La mayor parte de la información relevante se puede encontrar mirando ?S3
o ?UseMethod
, pero en pocas palabras:
S3 se refiere a un esquema de envío de métodos. Si ha usado R por un tiempo, notará que hay métodos de print
, predict
y summary
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
glm
tiene claseglm
) - proporcionando un método con el nombre general (por ejemplo,
print
), luego un punto, y luego el nombre de clase (por ejemplo:print.glm
) - se debe haber hecho algo de preparación con este nombre general (
print
) para que esto funcione, pero si simplemente buscas conformarte a los nombres de métodos existentes, no es necesario (mira la ayuda que mencioné anteriormente si hacer).
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 predict(myfit, type="class")
que predict.mykindoffit(myfit, type="class")
.
Hay bastante más para eso, pero esto debería ayudarte a empezar. Hay muchas desventajas en esta forma de distribuir métodos basados en un atributo (clase) de objetos (y los puristas de C probablemente estén despiertos por la noche con horror), 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 (solo) usan S3.