8 S3
Es posible que haya notado que los resultados de su máquina tragamonedas no se ven como prometí. Sugerí que la máquina tragamonedas mostraría sus resultados así:
play()
## 0 0 DD
## $0
Pero la máquina actual muestra sus resultados en un formato menos bonito:
play()
## "0" "0" "DD"
## 0
Además, la máquina tragamonedas usa un truco para mostrar símbolos (llamamos print
desde dentro de play
). Como resultado, los símbolos no siguen la salida de su premio si lo guarda:
<- play()
a_play ## "B" "0" "B"
a_play## 0
Puede solucionar ambos problemas con el sistema S3 de R.
8.1 El Sistema S3
S3 se refiere a un sistema de clases integrado en R. El sistema rige cómo R maneja objetos de diferentes clases. Ciertas funciones de R buscarán la clase S3 de un objeto y luego se comportarán de manera diferente en respuesta.
La función print
es así. Cuando imprime un vector numérico, print
mostrará un número:
<- 1000000000
num print(num)
## 1000000000
Pero si le da ese número a la clase S3 POSIXct
seguida de POSIXt
, print
mostrará una hora:
class(num) <- c("POSIXct", "POSIXt")
print(num)
## "2001-09-08 19:46:40 CST"
Si usa objetos con clases, y lo hace, se encontrará con el sistema S3 de R. El comportamiento de S3 puede parecer extraño al principio, pero es fácil de predecir una vez que se familiariza con él.
El sistema S3 de R se basa en tres componentes: atributos (especialmente el atributo class
), funciones genéricas y métodos.
8.2 Atributos
En Atributos, aprendió que muchos objetos de R vienen con atributos, piezas de información adicional a las que se les da un nombre y se agregan al objeto. Los atributos no afectan los valores del objeto, pero se adhieren al objeto como un tipo de metadatos que R puede usar para manejar el objeto. Por ejemplo, un data frame almacena sus nombres de fila y columna como atributos. Los data frame también almacenan su clase, "data.frame"
, como un atributo.
Puede ver los atributos de un objeto con attribute
. Si ejecuta attribute
en el data frame mazo
que creó en Proyecto 2: Baraja de Cartas, verá:
attributes(mazo)
## $names
## [1] "cara" "palo" "valor"
##
## $class
## [1] "data.frame"
##
## $row.names
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
## [20] 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
## [37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
R viene con muchas funciones auxiliares que le permiten establecer y acceder a los atributos más comunes utilizados en R. Ya conoce las funciones names
, dim
y class
, cada una de las cuales funciona con un atributo con nombre homónimo. Sin embargo, R también tiene row.names
, levels
y muchas otras funciones auxiliares basadas en atributos. Puede utilizar cualquiera de estas funciones para recuperar el valor de un atributo:
row.names(mazo)
## [1] "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13"
## [14] "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" "25" "26"
## [27] "27" "28" "29" "30" "31" "32" "33" "34" "35" "36" "37" "38" "39"
## [40] "40" "41" "42" "43" "44" "45" "46" "47" "48" "49" "50" "51" "52"
o para cambiar el valor de un atributo:
row.names(mazo) <- 101:152
o para dar a un objeto un atributo completamente nuevo:
levels(mazo) <- c("level 1", "level 2", "level 3")
attributes(mazo)
## $names
## [1] "cara" "palo" "valor"
##
## $class
## [1] "data.frame"
##
## $row.names
## [1] 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
## [18] 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
## [35] 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
## [52] 152
##
## $levels
## [1] "level 1" "level 2" "level 3"
R es muy libre cuando se trata de atributos. Le permitirá agregar cualquier atributo que desee a un objeto (y luego generalmente los ignorará). La única vez que R se quejará es cuando una función necesita encontrar un atributo y no está allí.
Puede agregar cualquier atributo general a un objeto con attr
; también puede usar attr
para buscar el valor de cualquier atributo de un objeto. Veamos cómo funciona esto con a_play
, el resultado de jugar nuestra máquina tragamonedas una vez:
<- play()
a_play
a_play## 0
attributes(a_play)
## NULL
attr
toma dos argumentos: un objeto de R y el nombre de un atributo (como una cadena de caracteres). Para darle al objeto de R un atributo del nombre especificado, guarde un valor en la salida de attr
. Démosle a a_play
un atributo llamado simbolos
que contiene un vector de cadenas de caracteres:
attr(a_play, "simbolos") <- c("B", "0", "B")
attributes(a_play)
## $simbolos
## [1] "B" "0" "B"
Para buscar el valor de cualquier atributo, dale a attr
un objeto R y el nombre del atributo que te gustaría buscar:
attr(a_play, "simbolos")
## "B" "0" "B"
Si asigna un atributo a un vector atómico, como a_play
, R generalmente mostrará el atributo debajo de los valores del vector. Sin embargo, si el atributo cambia la clase del vector, R puede mostrar toda la información en el vector de una nueva forma (como vimos con los objetos POSIXct
):
a_play## [1] 0
## attr(,"simbolos")
## [1] "B" "0" "B"
R generalmente ignorará los atributos de un objeto a menos que le des un nombre que busca una función de R, como names
o class
. Por ejemplo, R ignorará el atributo simbolos
de a_play
mientras manipulas a_play
:
+ 1
a_play ## 1
## attr(,"simbolos")
## "B" "0" "B"
Ejercicio 11.1 (Añade un Atributo) Modifique play
para devolver un premio que contenga los símbolos asociados a él como un atributo denominado simbolos
. Elimine la llamada redundante a print(simbolos)
:
<- function() {
play <- obt_simbolos()
simbolos print(simbolos)
puntuacion(simbolos)
}
Solución. Puede crear una nueva versión de play
capturando la salida de puntuacion(simbolos)
y asignándole un atributo. play
puede devolver la versión mejorada de la salida:
<- function() {
play <- obt_simbolos()
simbolos <- puntuacion(simbolos)
premio attr(premio, "simbolos") <- simbolos
premio }
Ahora play
devuelve tanto el premio como los símbolos asociados con el premio. Puede que los resultados no se vean bonitos, pero los símbolos se quedan con el premio cuando lo copiamos a un nuevo objeto. Podemos trabajar en ordenar la pantalla en un minuto:
play()
## [1] 0
## attr(,"simbolos")
## [1] "B" "BB" "0"
<- play()
b_play
b_play## [1] 0
## attr(,"simbolos")
## [1] "0" "B" "0"
También puede generar un premio y establecer sus atributos en un solo paso con la función structure
. structure
crea un objeto con un conjunto de atributos. El primer argumento de structure
debe ser un objeto de R o un conjunto de valores, y los argumentos restantes deben ser atributos con nombre para que structure
se agregue al objeto. Puede dar a estos argumentos cualquier nombre de argumento que desee. structure
agregará los atributos al objeto bajo los nombres que proporcione como nombres de argumento:
<- function() {
play <- get_simbolos()
simbolos structure(puntuacion(simbolos), simbolos = simbolos)
}
<- play()
c_play
c_play## 0
## attr(,"simbolos")
## "0" "BB" "B"
Ahora que su salida play
contiene un atributo simbolos
, ¿qué puede hacer con él? Puede escribir sus propias funciones que busquen y usen el atributo. Por ejemplo, la siguiente función buscará el atributo simbolos
de a_play
y lo usará para mostrar a_play
de una manera bonita. Usaremos esta función para mostrar los resultados de nuestra tragamonedas, así que tomemos un momento para estudiar lo que hace:
<- function(premio){
mostrat_tragamoneda
# extraer simbolos
<- attr(premio, "simbolos")
simbolos
# colapsar símbolos en una sola cadena de caracteres
<- paste(simbolos, collapse = " ")
simbolos
# combinar símbolo con premio como una cadena de caracteres
# \n es una secuencia de escape especial para una nueva línea (i.e. return or enter)
<- paste(simbolos, premio, sep = "\n$")
texto
# mostrar cadena de caracteres en la consola sin comillas
cat(texto)
}
mostrat_tragamoneda(a_play)
## B 0 B
## $0
La función espera un objeto como a_play
que tiene tanto un valor numérico como un atributo de simbolos
. La primera línea de la función buscará el valor del atributo simbolos
y lo guardará como un objeto llamado simbolos
. Hagamos un objeto simbolos
de ejemplo para que podamos ver lo que hace el resto de la función. Podemos usar el atributo simbolos
de a_play
para hacer el trabajo. simbolos
será un vector de cadenas de tres caracteres:
<- attr(a_play, "simbolos")
simbolos
simbolos## "B" "0" "B"
A continuación, mostrat_tragamoneda
usa paste
para colapsar las tres cadenas en simbolos
en una cadena de un solo carácter. paste
colapsa un vector de cadenas de caracteres en una sola cadena cuando le das el argumento collapse
. paste
usará el valor de collapse
para separar las cadenas anteriormente distintas. Por lo tanto, simbolos
se convierte en B 0 B
las tres cadenas separadas por un espacio:
<- paste(simbolos, collapse = " ")
simbolos
simbolos## "B 0 B"
Nuestra función luego usa paste
de una nueva forma para combinar simbolos
con el valor de premio
. paste
combina objetos separados en una cadena de caracteres cuando le das un argumento sep
. Por ejemplo, aquí paste
combinará la cadena en simbolos
, B 0 B
, con el número en premio
, 0. paste
usará el valor del argumento sep
para separar las entradas en el cadena nueva. Aquí, ese valor es \n$
, por lo que nuestro resultado se verá como "B 0 B\n$0"
:
<- a_play
premio <- paste(simbolos, premio, sep = "\n$")
texto
texto## "B 0 B\n$0"
La última línea de mostrat_tragamoneda
llama a cat
en la nueva cadena. cat
es como print
; muestra su entrada en la línea de comando. Sin embargo, cat
no encierra su salida entre comillas. cat
también reemplaza cada \n
con una nueva línea o salto de línea. El resultado es lo que vemos. Tenga en cuenta que se ve exactamente como sugerí que nuestra salida play
debería verse en Programas:
cat(texto)
## B 0 B
## $0
Puedes usar mostrat_tragamoneda
para limpiar manualmente la salida de play
:
mostrat_tragamoneda(play())
## C B 0
## $2
mostrat_tragamoneda(play())
## 7 0 BB
## $0
Este método de limpieza de la salida requiere que intervengas manualmente en tu sesión de R (para llamar a mostrat_tragamoneda
). Hay una función que puede usar para limpiar automáticamente la salida de play
cada vez que se muestra. Esta función es print
, y es una función genérica.
8.3 Funciones Genéricas
R usa print
con más frecuencia de lo que piensas; R llama a print
cada vez que muestra un resultado en la ventana de su consola. Esta llamada ocurre en segundo plano, por lo que no la nota; pero la llamada explica cómo la salida llega a la ventana de la consola (recuerde que print
siempre imprime su argumento en la ventana de la consola). Esta llamada print
también explica por qué la salida de print
siempre coincide con lo que ve cuando muestra un objeto en la línea de comando:
print(pi)
## 3.141593
pi## 3.141593
print(head(mazo))
## cara palo valor
## rey picas 13
## reina picas 12
## jota picas 11
## diez picas 10
## nueve picas 9
## ocho picas 8
head(mazo)
## cara palo valor
## rey picas 13
## reina picas 12
## jota picas 11
## diez picas 10
## nueve picas 9
## ocho picas 8
print(play())
## 5
## attr(,"simbolos")
## "B" "BB" "B"
play()
## 5
## attr(,"simbolos")
## "B" "BB" "B"
Puede cambiar la forma en que R muestra la salida de su maquina tragamonedas reescribiendo print
para que se vea como mostrat_tragamoneda
. Entonces R mostraría la salida en el formato que hemos creado. Sin embargo, este método tendría efectos secundarios negativos. No desea que R llame a mostrat_tragamoneda
cuando muestre un data frame, un vector numérico o cualquier otro objeto.
Afortunadamente, print
no es una función normal; es una función genérica. Esto significa que print
está escrito de una manera que le permite hacer cosas diferentes en casos diferentes. Ya has visto este comportamiento en acción (aunque es posible que no te hayas dado cuenta). print
hizo una cosa cuando miramos la versión sin clase de num
:
<- 1000000000
num print(num)
## 1000000000
y una cosa diferente cuando le dimos a num
una clase:
class(num) <- c("POSIXct", "POSIXt")
print(num)
## "2001-09-08 19:46:40 CST"
Eche un vistazo al código dentro de print
para ver cómo lo hace. Puede imaginar que print busca el atributo de clase de su entrada y luego usa un árbol +if+ para elegir qué salida mostrar. Si esto te ocurrió, ¡buen trabajo! print
hace algo muy similar, pero mucho más simple.
8.4 Métodos
Cuando llamas a print
, print
llama a una función especial, UseMethod
:
print## function (x, ...)
## UseMethod("print")
## <bytecode: 0x7ffee4c62f80>
## <environment: namespace:base>
UseMethod
examina la clase de la entrada que proporcionas para el primer argumento de print
y luego pasa todos tus argumentos a una nueva función diseñada para manejar esa clase de entrada. Por ejemplo, cuando le das a print
un objeto POSIXct, UseMethod
pasará todos los argumentos de print
a print.POSIXct
. R luego ejecutará print.POSIXct
y devolverá los resultados:
print.POSIXct## function (x, ...)
## {
## max.print <- getOption("max.print", 9999L)
## if (max.print < length(x)) {
## print(format(x[seq_len(max.print)], usetz = TRUE), ...)
## cat(" [ reached getOption(\"max.print\") -- omitted",
## length(x) - max.print, "entries ]\n")
## }
## else print(format(x, usetz = TRUE), ...)
## invisible(x)
## }
## <bytecode: 0x7fa948f3d008>
## <environment: namespace:base>
Si le das a print
un objeto de factor, UseMethod
pasará todos los argumentos de print
a print.factor
. R luego ejecutará print.factor
y devolverá los resultados:
print.factor## function (x, quote = FALSE, max.levels = NULL, width = getOption("width"),
## ...)
## {
## ord <- is.ordered(x)
## if (length(x) == 0L)
## cat(if (ord)
## "ordered"
## ...
## drop <- n > maxl
## cat(if (drop)
## paste(format(n), ""), T0, paste(if (drop)
## c(lev[1L:max(1, maxl - 1)], "...", if (maxl > 1) lev[n])
## else lev, collapse = colsep), "\n", sep = "")
## }
## invisible(x)
## }
## <bytecode: 0x7fa94a64d470>
## <environment: namespace:base>
print.POSIXct
y print.factor
se denominan métodos de print
. Por sí mismos, print.POSIXct
y print.factor
funcionan como funciones regulares de R. Sin embargo, cada uno fue escrito específicamente para que ‘UseMethod’ pudiera llamarlo para manejar una clase específica de entrada de print
.
Tenga en cuenta que print.POSIXct
y print.factor
hacen dos cosas diferentes (también tenga en cuenta que compendié la mitad de print.factor
: es una función larga). Así es como print
se las arregla para hacer diferentes cosas en diferentes casos. print
llama a UseMethod
, que llama a un método especializado basado en la clase del primer argumento de print
.
Puede ver qué métodos existen para una función genérica llamando a methods
en la función. Por ejemplo, print
tiene casi 200 métodos (lo que le da una idea de cuántas clases existen en R):
methods(print)
## [1] print.acf*
## [2] print.anova
## [3] print.aov*
## ...
## [176] print.xgettext*
## [177] print.xngettext*
## [178] print.xtabs*
##
## Nonvisible functions are asterisked
Este sistema de funciones genéricas, métodos y despacho basado en clases se conoce como S3 porque se originó en la tercera versión de S, el lenguaje de programación que se convertiría en S-PLUS y R. Muchas funciones comunes de R son genéricas de S3 que funcionan con un conjunto de métodos de clase. Por ejemplo, summary
y head
también llaman a UseMethod
. Las funciones más básicas, como c
, +
, -
, <
y otras también se comportan como funciones genéricas, aunque llaman a .primitive
en lugar de UseMethod
.
El sistema S3 permite que las funciones de R se comporten de diferentes maneras para diferentes clases. Puede usar S3 para formatear la salida de su tragamonedas. Primero, dé a su salida su propia clase. Luego escriba un método de impresión para esa clase. Para hacer esto de manera eficiente, necesitará saber un poco acerca de cómo UseMethod
selecciona una función de método para usar.
8.4.1 Selección de Método
UseMethod
utiliza un sistema muy simple para emparejar métodos con funciones.
Cada método S3 tiene un nombre de dos partes. La primera parte del nombre se referirá a la función con la que trabaja el método. La segunda parte se referirá a la clase. Estas dos partes estarán separadas por un punto. Entonces, por ejemplo, el método de print
que funciona con funciones se llamará print.function
. El método de summary
que trabaja con matrices se llamará summary.matrix
. Y así sucesivamente.
Cuando UseMethod
necesita llamar a un método, busca una función de R con el nombre de estilo S3 correcto. La función no tiene que ser especial de ninguna manera; solo necesita tener el nombre correcto.
Puede participar en este sistema escribiendo su propia función y dándole un nombre de estilo S3 válido. Por ejemplo, demos a a_play
una clase propia. No importa cómo llames a la clase; R almacenará cualquier cadena de caracteres en el atributo de clase:
class(a_play) <- "tragamonedas"
Ahora escribamos un método de impresión S3 para la clase +tragamonedas+. El método no necesita hacer nada especial, ni siquiera necesita imprimir a_play
. Pero sí necesita llamarse print.tragamonedas
; de lo contrario, UseMethod
no lo encontrará. El método también debería tomar los mismos argumentos que print
; de lo contrario, R dará un error cuando intente pasar los argumentos a print.tragamonedas
:
args(print)
## function (x, ...)
## NULL
<- function(x, ...) {
print.tragamonedas cat("Estoy usando el método print.tragamonedas")
}
¿Funciona nuestro método? Sí, y no solo eso; R usa el método de impresión para mostrar el contenido de a_play
. Este método no es muy útil, así que voy a eliminarlo. Tendrás la oportunidad de escribir uno mejor en un minuto:
print(a_play)
## Estoy usando el método print.tragamonedas
a_play## Estoy usando el método print.tragamonedas
rm(print.tragamonedas)
Algunos objetos de R tienen múltiples clases. Por ejemplo, la salida de Sys.time
tiene dos clases. ¿Qué clase usará UseMethod
para encontrar un método de impresión?
<- Sys.time()
ahora attributes(ahora)
## $class
## [1] "POSIXct" "POSIXt"
UseMethod
primero buscará un método que coincida con la primera clase listada en el vector de clase del objeto. Si UseMethod
no puede encontrar uno, buscará el método que coincida con la segunda clase (y así sucesivamente si hay más clases en el vector de clase de un objeto).
Si le das a print
un objeto cuya clase o clases no tienen un método de impresión, UseMethod
llamará a print.default
, un método especial escrito para manejar casos generales.
Usemos este sistema para escribir un mejor método de impresión para la salida de la máquina tragamonedas.
Ejercicio 11.2 (Hacer un Método de print) Escriba un nuevo método de print para la clase de tragamonedas. El método debería llamar a mostrat_tragamoneda
para devolver una salida de máquina tragamonedas bien formateada.
¿Qué nombre debe usar para este método?
Solución. Es sorprendentemente fácil escribir un buen método print.tragamonedas
porque ya hicimos todo el trabajo duro cuando escribimos mostrat_tragamoneda
. Por ejemplo, el siguiente método funcionará. Solo asegúrese de que el método se llame print.tragamonedas
para que UseMethod
pueda encontrarlo, y asegúrese de que toma los mismos argumentos que print
para que UseMethod
pueda pasar esos argumentos a print.tragamonedas
sin ningún problema:
<- function(x, ...) {
print.tragamonedas mostrat_tragamoneda(x)
}
Ahora R usará automáticamente mostrat_tragamoneda
para mostrar objetos de clase +tragamonedas+ (y solo objetos de clase “tragamonedas”):
a_play## B 0 B
## $0
Asegurémonos de que cada salida de la máquina tragamonedas tenga la clase tragamonedas
.
Ejercicio 11.3 (Añadir una Clase) Modifique la función play
para que asigne tragamonedas
al atributo class
de su salida:
<- function() {
play <- get_simbolos()
simbolos structure(puntuacion(simbolos), simbolos = simbolos)
}
Solución. Puede establecer el atributo class
de la salida al mismo tiempo que establece el atributo +simbolos+. Simplemente agregue class = "tragamonedas"
a la llamada structure
:
<- function() {
play <- get_simbolos()
simbolos structure(puntuacion(simbolos), simbolos = simbolos, class = "tragamonedas")
}
Ahora cada uno de nuestras salidas de play
tendrá la clase tragamonedas
:
class(play())
## "tragamonedas"
Como resultado, R los mostrará en el formato de máquina tragamonedas correcto:
play()
## BB BB BBB
## $5
play()
## BB 0 0
## $0
8.5 Clases
Puede usar el sistema S3 para crear una nueva clase sólida de objetos en R. Luego, R tratará los objetos de su clase de manera consistente y sensata. Para hacer una clase:
- Elija un nombre para su clase.
- Asigne a cada instancia de su clase un atributo +class+.
- Escriba métodos de clase para cualquier función genérica que pueda usar objetos de su clase.
Muchos paquetes de R se basan en clases que se han creado de manera similar. Si bien este trabajo es simple, puede que no sea fácil. Por ejemplo, considere cuántos métodos existen para clases predefinidas.
Puede llamar a methods
en una clase con el argumento class
, que toma una cadena de caracteres. methods
devolverá todos los métodos escritos para la clase. Tenga en cuenta que methods
no podrá mostrarle los métodos que vienen en un paquete R descargado:
methods(class = "factor")
## [1] [.factor [[.factor
## [3] [[<-.factor [<-.factor
## [5] all.equal.factor as.character.factor
## [7] as.data.frame.factor as.Date.factor
## [9] as.list.factor as.logical.factor
## [11] as.POSIXlt.factor as.vector.factor
## [13] droplevels.factor format.factor
## [15] is.na<-.factor length<-.factor
## [17] levels<-.factor Math.factor
## [19] Ops.factor plot.factor*
## [21] print.factor relevel.factor*
## [23] relist.factor* rep.factor
## [25] summary.factor Summary.factor
## [27] xtfrm.factor
##
## Nonvisible functions are asterisked
Esta salida indica cuánto trabajo se requiere para crear una clase robusta y de buen comportamiento. Por lo general, necesitará escribir un método de class
para cada operación básica de R.
Considere dos desafíos que enfrentará de inmediato. Primero, R descarta atributos (como class
) cuando combina objetos en un vector:
<- play()
play1
play1## B BBB BBB
## $5
<- play()
play2
play2## 0 B 0
## $0
c(play1, play2)
## [1] 5 0
Aquí, R deja de usar print.tragamonedas
para mostrar el vector porque el vector c(play1, play2)
ya no tiene un atributo +class+ “tragamonedas”.
A continuación, R eliminará los atributos de un objeto (como class
) cuando subjunte el objeto:
1]
play1[## [1] 5
Puede evitar este comportamiento escribiendo un método c.tragamonedas
y un método [.tragamonedas
, pero luego se acumularán dificultades rápidamente. ¿Cómo combinaría los atributos de simbolos
de múltiples jugadas en un vector de atributos de símbolos? ¿Cómo cambiarías print.tragamonedas
para manejar vectores de salidas? Estos desafíos están abiertos para que los explores. Sin embargo, normalmente no tendrá que intentar este tipo de programación a gran escala como científico de datos.
En nuestro caso, es muy útil dejar que los objetos tragamonedas
vuelvan a tener valores de premios únicos cuando combinamos grupos de ellos en un vector.
8.6 S3 y Depuración
S3 puede ser molesto si está tratando de comprender las funciones de R. Es difícil saber qué hace una función si su cuerpo de código contiene una llamada a UseMethod
. Ahora que sabe que UseMethod
llama a un método específico de clase, puede buscar y examinar el método directamente. Será una función cuyo nombre siga la sintaxis <function.class>
, o posiblemente <function.default>
. También puede usar la función methods
para ver qué métodos están asociados con una función o una clase.
8.7 S4 y R5
R también contiene otros dos sistemas que crean un comportamiento específico de clase. Estos se conocen como S4 y R5 (o clases de referencia). Cada uno de estos sistemas es mucho más difícil de usar que S3 y quizás, como consecuencia, más raro. Sin embargo, ofrecen garantías que S3 no ofrece. Si desea obtener más información sobre estos sistemas, incluido cómo escribir y usar sus propias funciones genéricas, le recomiendo el libro Advanced R Programming de Hadley Wickham.
8.8 Resumen
Los valores no son el único lugar para almacenar información en R, y las funciones no son la única forma de crear un comportamiento único. También puede hacer ambas cosas con el sistema S3 de R. El sistema S3 proporciona una forma sencilla de crear comportamientos específicos de objetos en R. En otras palabras, es la versión de programación orientada a objetos (OOP) de R. El sistema se implementa mediante funciones genéricas. Estas funciones examinan el atributo de clase de su entrada y llaman a un método específico de clase para generar salida. Muchos métodos de S3 buscarán y utilizarán información adicional que se almacena en los atributos de un objeto. Muchas funciones comunes de R son genéricas de S3.
El sistema S3 de R es más útil para las tareas de informática que para las tareas de ciencia de datos, pero comprender S3 puede ayudarlo a solucionar problemas en su trabajo en R como científico de datos
Ahora sabe bastante sobre cómo escribir código de R que realiza tareas personalizadas, pero ¿cómo podría repetir estas tareas? Como científico de datos, a menudo repetirá tareas, a veces miles o incluso millones de veces. ¿Por qué? Porque la repetición te permite simular resultados y estimar probabilidades. Bucles te mostrará cómo automatizar la repetición con las funciones for
y while
de R. Usará for
para simular varios juegos de máquinas tragamonedas y para calcular la tasa de pago de su máquina tragamonedas.