apropos("as")
10 CLASIFICACIÓN DE OBJETOS
En R los objetos pueden clasificarse con base en tres criterios:
Clase (
class
)Tipo (
typeof
)Modo (
mode
)
10.1 Clase
La clase indica, en sentido amplio, la naturaleza del objeto. En R, todos los objetos son de una clase determinada (en ocasiones pueden pertenecer a dos o más clases).
Para averiguar la clase de un objeto, se usa la función class
. Las clases más comunes de los objetos contenedores de datos que se presentan en el capítulo 8 son:
- entera (
integer
) - numérica (
numeric
) - compleja (
complex
) - lógica (
logical
) - carácter (
character
) - matriz (
matrix
) - arreglo (
array
) - data frame (
data.frame
) - lista (
list
)
Los nombres de las clases coinciden con los de los contendedores de información para las matrices, los arreglos, los data frames y las listas. Sin embargo, no hay coincidencia para el caso de los vectores, pues no existe una una clase denominada vector
.
Los vectores pueden ser de alguna de las cinco primeras clases, según la naturaleza de sus elementos.
Para establecer la relación entre clases y contenedores, puede pensarse cada una de las primeras cinco clases enumeradas anteriormente como si llevaran antepuesta la palabra vector, así: vector numérico, vector complejo, vector lógico, etc.
Como parte de la programación orientada a objetos, R maneja funciones genéricas, que derivan a funciones particulares, tomando en consideración la clase del argumento principal de la función.
Es posible —con ciertas restricciones— modificar la clase de un objeto, mediante el uso de funciones tales como as.matrix
, as.data.frame
, as.list
, as.numeric
y as.character
, que permiten guardar objetos como matrices, data frames, listas, vectores numéricos y vectores de caracteres, respectivamente.
La siguiente instrucción genera una lista completa de tales funciones:
La clase de un objeto es un aspecto de particular relevancia, pues cada función exige que sus argumentos sean de una clase particular.
Así, por ejemplo, las operaciones matriciales exigen objetos de la clase matriz (eventualmente, también vectores; cf. sección 8.2.1).
10.2 Tipo
Aunque la clase define la naturaleza de los elementos que conforman un vector, no informa sobre los elementos que conforman los demás objetos atómicos. Para conocer la naturaleza de tales elementos en matrices y arreglos, debe evaluarse su tipo, mediante la función typeof
.
Los tipos son cuasicoincidentes con las clases de vectores:
- entero (
integer
) - doble (
double
) - complejo (
complex
) - lógico (
logical
) - carácter (
character
)
Se habrá notado que con excepción de double
, los tipos coinciden con las clases de los vectores.
El nombre double es herencia de la computación de bajo nivel, donde surgió de la necesidad de representar números reales con mayor precisión que la de los flotantes de precisión simple (single-precision), que usaban 32 bits para el almacenamiento y permitían almacenar cada número con aproximadamente 7 u 8 dígitos de precisión.
En contraste, el almacenamiento de doble precisión (double-precision) usaba 64 bits y permitía entre 15 y 16 dígitos.
Al evaluar el tipo de datos que conforman un objeto atómico se obtiene información inequívoca (entero, lógico, carácter, etc.), puesto que todos sus elementos son del mismo tipo.
Sin embargo, cuando se pretende evaluar el tipo de datos que conforman un objeto recursivo, esto es, un data frame o una lista (cf. nota 8.1), el resultado obtenido es list
, como un recordatorio de que los elementos alojados en dichos contenedores pueden ser de diferentes tipos. Este resultado es siempre el mismo, aun si se evalúan data frames o listas conformados por elementos del mismo tipo.
No obstante, de ser necesario, puede evaluarse el tipo de cada uno de los objetos que conforman un contenedor recursivo, mediante el uso de los descriptores de acceso apropiados (sección 13.1.3.1).
A nivel de usuario, la naturaleza de los elementos constituyentes de un objeto atómico (vector, matriz o arreglo) se evalúa a través de su tipo (typeof
).
10.3 Modo
El modo, que se verifica con la función mode
, tiene que ver con la manera en la que los objetos son almacenados en memoria, siendo cuasicoincidente con el tipo.
El concepto de modo es una herencia de las versiones antiguas de R. En la actualidad es poco usado, prefiriéndose el tipo.
No obstante, el modo cobraría relevancia si se importara o exportara código desde o hacia otros lenguajes tales como S, C, C++ o Fortran. Asimismo, si se requiriera compatibilidad con funciones antiguas.
10.4 Clase factor
En adición a las clases que se presentan en la sección 10.1 como las más populares para los vectores atómicos (integer
, numeric
, logical
, character
y complex
), está la clase factor
.
Los vectores de la clase factor
están conformados por los diferentes niveles de una variable categórica.
Considérese el siguiente vector:
<- c("j", "m", "f", "m", "m", "f") a
Aunque el vector a
aparentemente está conformado por una serie de niveles de una variable categórica, esto no lo convierte automáticamente en un miembro de la clase factor
. El vector a
es de la clase character
1. Para que el vector a
sea de la clase factor
, es necesario definirlo explícitamente como tal, usando la función factor
(o también as.factor
), así:
<- factor(a) a2
Aunque el contenido de los vectores a
y a2
es en esencia el mismo, la definición de a2
como un vector de la clase factor
, le agrega un atributo de niveles (levels
) que lo hace apto como insumo de ciertos procesos.
La función levels
permite recuperar los niveles de un vector de la clase factor
:
levels(a2)
[1] "f" "j" "m"
Nótese que el anterior resultado no enumera todos los elementos del vector a2
, sino únicamente los que son diferentes. Estos son los niveles del factor a2
.
El resultado de la función levels
es un vector con cada una de las categorías o niveles ordenados del factor. El orden por defecto es alfabético; no el orden de aparición en el factor.
Por otra parte, la función nlevels
da como resultado el número de niveles de un vector de la clase factor
. En este caso, no se enumeran los niveles; simplemente se obtiene su número .
nlevels(a2)
[1] 3
Si al evaluar el número de niveles de un factor aparece un número mayor de niveles que el esperado, puede deberse a un uso descuidado de las mayúsculas y minúsculas.
Recuerde que R es case-sensitive. Consecuentemente, “enero” y “Enero” se registrarían como dos niveles diferentes.
No solamente los vectores de la clase character
pueden convertirse a la clase factor
. Cualquier vector, sin importar su clase original, puede convertirse en un factor, usando la función factor
.
Considérense los siguientes vectores:
<- c(9, 5, 3, 6, 10, 5, 5, 3)
b <- factor(b) b2
b
es un vector de la clase numeric
, mientras que b2
es un vector de la clase factor
. Estos son su niveles:
levels(b2)
[1] "3" "5" "6" "9" "10"
Aunque siguen usándose los mismos símbolos para identificar los niveles del vector b2
, estos pierden su concepto como valores numéricos, no siendo posible usarlos, por ejemplo, en una operación aritmética. En un vector de la clase factor
, “3”, “5”, “6”, “9” y “10” son símbolos de la misma naturaleza que “f”, “j” y “m”.
Nótese que cuando el factor proviene de un vector numérico, el orden de los niveles respeta el orden numérico original.
Puesto que la definición de un vector como miembro de la clase factor
únicamente conlleva un cambio en sus atributos, sin que se altere el contenido del vector, lo que usualmente se hace es sobreescribir el vector original, en lugar de generar un nuevo vector. Con esto se evita la acumulación innecesaria de objetos en el entorno de trabajo.
Acorde con esto, en lugar de los vectores a
y a2
del ejemplo anterior2 se sobreescribiría el vector a
—usándolo como argumento de la función factor
y como resultado— así:
<- c("j", "m", "f", "m", "m", "f")
a <- factor(a)
a class(a)
[1] "factor"
Al final se tiene un único vector a
de la clase factor
.
10.4.1 Redefinición del orden de los niveles de un factor
En ocasiones, puede requerirse cambiar el orden que por defecto se les asigna a los niveles de un factor.
Considérese el siguiente vector.
<- c("mar", "feb", "ene", "abr")
mes <- factor(mes)
mes levels(mes)
[1] "abr" "ene" "feb" "mar"
El orden alfabético que se obtiene por defecto para los niveles del factor mes
podría no ser el más conveniente si se quisiera, por ejemplo, construir un gráfico con los meses en la abscisa.
Para generar un orden personalizado, acorde con su secuencia temporal de aparición durante el año, se incorpora un vector con los niveles en el orden deseado, a través del argumento levels
, así:
<- c("mar", "feb", "ene", "abr")
mes <- factor(mes, levels = c("ene", "feb", "mar", "abr"))
mes levels(mes)
[1] "ene" "feb" "mar" "abr"
Igualmente, podría obtenerse un orden personalizado, usando la función levels
en una línea aparte, en lugar de hacerlo como argumento de la función factor
, así:
mes <- c("mar", "feb", "ene", "abr")
mes <- factor(mes)
levels(mes) <- c("ene", "feb", "mar", "abr")
levels(mes)
[1] "ene" "feb" "mar" "abr"
La línea 1 genera el vector mes
, de la clase character
.
En la línea 2 se sobreescribe el vector mes
con otro vector del mismo nombre, pero de la clase factor
. El orden de los niveles del factor mes
es el alfabético.
Mediante la instrucción de la línea 3 se redefine el orden de los niveles del factor mes
.
Las estrategias anteriores permiten reordenar los niveles del factor, pero no permiten modificar sus nombres. Consecuentemente, el siguiente fragmento de código genera un resultado inesperado:
<- c("mar", "feb", "ene", "abr")
mes <- factor(mes, levels = c("enero", "febrero", "marzo", "abril"))
mes levels(mes)
[1] "enero" "febrero" "marzo" "abril"
Hasta aquí todo pareciera ir bien. El factor mes
reconoció los nuevos nombres para las etiquetas de sus niveles.
Obsérvese, sin embargo, lo que sucede con el vector mes
.
print(mes)
[1] <NA> <NA> <NA> <NA>
Levels: enero febrero marzo abril
En la sección 11.3 se detalla el significado de la etiqueta NA.
De manera breve podemos decir que cuando se auscultan los elementos del vector mes
y no se encuentra correspondencia entre estos y los niveles del factor, se interpretan como información faltante.
10.4.2 Redefinición del primer nivel
Un caso particular de reordenamiento de los niveles de un factor surge cuando se necesita definir un nivel determinado como nivel de referencia.
Teniendo en cuenta que algunas funciones toman el primer nivel del factor como nivel de referencia, bastaría con ubicar el nivel deseado en la primera posición antes de aplicar tales funciones.
Para tal efecto se usa la función relevel
(reference level).
Considérese nuevamente el factor a
definido anteriormente y supóngase que se usará como argumento de una función, mediante la cual se pretende comparar los niveles de "j"
contra los demás niveles.
Para tal efecto, se define “j” como el nivel de referencia, ubicándolo en la primera posición.
<- factor(c("j", "m", "f", "m", "m", "f"))
a levels(a)
[1] "f" "j" "m"
Hasta aquí todo lo que se ha hecho es definir el vector a
como factor (¡en una sola instrucción!). Tal y como era de esperarse el orden de los niveles queda definido por el orden alfabético.
La siguiente instrucción redefine el orden, ubicando el nivel “j” en la primera posición:
<- relevel(a, "j")
a levels(a)
[1] "j" "f" "m"
Tal y como se observa, “j” queda definido como el nivel de referencia (primer nivel). Los demás niveles se reacomodan a partir de este, manteniendo el orden alfabético o cualquier otro orden personalizado que se hubiera definido.
Cuando se importan datos, mediante cualquiera de las estrategias presentadas en el capítulo 6, el objeto resultante es un data frame, en el que la clase de cada uno de sus vectores queda definida automáticamente por su correspondiente contenido.
Las columnas que solo contienen información numérica se importan como vectores de la clase numeric
, mientras que las que contienen caracteres o una combinación de números y caracteres se importan como objetos de la clase character
.
Hay un aspecto particular de los vectores de la clase factor
que podría generar desconcierto: su tipo.
<- factor(c(9, 5, 3, 6, 10, 5, 5, 3))
b typeof(b)
[1] "integer"
¡No parece tan desconcertante!
Pero veamos ahora el tipo del vector a
:
<- factor(c("j", "m", "f", "m", "m", "f"))
a typeof(a)
[1] "integer"
Esto sí resulta bastante desconcertante. ¿Cómo puede ser que un vector cuyos elementos son “j”, “m” y “f” sea de tipo integer
?
Aunque parezca extraño, así es: el tipo de todos los vectores de la clase factor
—sin importar su tipo original— es integer
.
Si no quiere quedarse con la intriga, puede averiguar el porqué de este comportamiento.
factor
son del tipo integer
?
A continuación se discute el proceso interno involucrado en la definición de factores.
Aunque se trata de un tecnicismo, este permite resolver un par de aspectos desconcertantes relativos a los objetos de la clase factor
.
En primera instancia, que los factores no son vectores, y en segunda instancia, que, sin importar cuál sea su contenido, siempre son de tipo entero.
La transformación de un vector a la clase factor
se realiza en cinco pasos, tal y como se ilustra en la figura 10.1:

El sistema determina los niveles, evaluando el conjunto de elementos únicos, mediante la función
unique
, o tomándolos del argumentolevels
, en caso de que este haya sido suministrado por el usuario.Mediante la función
match
, se genera un vector de índices enteros que guardan correspondencia con los niveles ordenados del vector.Se le asigna el atributo
levels
, al objeto que contiene los índices.Se clasifica dicho objeto como
factor
.Se remplaza el vector original con el objeto creado.
El tercer paso, es decir, la asignación del atributo levels
al vector de índices enteros hace que este deje de ser reconocido como vector mediante la función is.vector
. Esta función —más allá de lo que su nombre pueda sugerir— solo reconoce como vector a una estructura en la que todos sus elementos sean de un modo específico y que no tenga ningún atributo adicional al nombre de los elementos. Luego, aunque, en realidad, el objeto en cuestión sí sigue siendo un vector, no es reconocido como tal mediante la función is.vector
, por el hecho de habérsele agregado el atributo levels
.
Cuando, mediante el paso 4, a este “vector” de enteros se le asigna la clase factor
, se establece una asociación entre su contenido y los correspondientes niveles, siendo estos últimos los que se muestran, pareciendo que el objeto original no se hubiera modificado. No obstante, lo que realmente queda almacenado internamente es el vector de índices enteros.
Esto explica por qué el tipo de cualquier objeto de la clase factor es integer
.
Para recuperar el contenido del vector de índices enteros, basta con desclasificarlo o retirarle el atributo de clase, mediante la función unclass
.
<- factor(c("j", "m", "f", "m", "m", "f"))
a unclass(a)
[1] 2 3 1 3 3 1
attr(,"levels")
[1] "f" "j" "m"
10.5 Tipo lógico
En programación, los booleanos son variables que solo pueden tomar dos posibles valores: falso y verdadero.
En R, los booleanos son objetos de tipo lógico (logical
), en los que TRUE
o T
representa el valor verdadero, mientras que FALSE
o F
representa el valor falso. Estas constantes se escriben siempre en mayúscula sostenida y no van entrecomilladas.
Las constantes lógicas aparecen frecuentemente como argumentos de funciones, para discernir entre dos líneas de acción. También es común que se generen como resultado de alguna función.
Cuando se realizan operaciones aritméticas propias de variables numéricas, TRUE
toma el valor de 1 y FALSE
, de 0. Esto puede ser de utilidad para contabilizar el número de elementos que satisfacen una condición.
Considérese el siguiente vector.
<- c(7, 23, 11, 8, 45, 90, 16, 21, 34, 57, 69) x
Si se quisiera averiguar, por ejemplo, cuáles elementos son mayores que 20, se escribiría:
> 20 x
[1] FALSE TRUE FALSE FALSE TRUE TRUE FALSE TRUE TRUE TRUE TRUE
Para contabilizar el número de elementos que satisfacen esa condición, basta con sumar las respuestas verdaderas, escribiendo sum(x > 20)
.
Internamente, esto equivale a la siguiente suma: sum(c(0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1))
.
sum(x > 20)
[1] 7
Debe tenerse presente que la relación entre los valores lógicos y las constante numéricas 0 y 1 solamente aplica en una vía; es decir que, cuando sea requerido, las constantes lógicas toman valores numéricos.
No obstante, no puede usarse 1 en lugar de TRUE
ni 0 en lugar de FALSE
.
Las funciones isTRUE
e isFALSE
permiten verificar si sus argumentos son verdaderos o falsos, correspondientemente.
10.6 Resumen de objetos contendores de información
Cuando se habla de contenedores de información en R, se hace referencia a los objetos detallados en el capítulo 8, sin considerar objetos de otra índole que cumplen diferentes roles en R, tales como las funciones, los entornos, las expresiones y las fórmulas.
En el ámbito de los contenedores de información, no existe en R el concepto de escalares, como elementos aislados por fuera de una estructura contenedora; todos los elementos —aun siendo unitarios— están contenidos en un vector. Los vectores son las estructuras contenedoras básicas. Todas las estructuras contenedoras complejas están conformadas en última instancia por vectores.
Todos los elementos de un vector tienen que ser de la misma naturaleza. Esto define el tipo de vector (typeof
), siendo los más comunes integer
, double
, logical
, character
y complex
.
Aunque eventualmente los vectores pueden hacerse corresponder con el concepto de los vectores del álgebra lineal (cf. sección 8.2.1), en principio son independientes de tal concepto, por lo que no se habla ni de vectores fila ni de vectores columna; simplemente, de vectores.
Los vectores son unidimensionales. No obstante, son susceptibles de conformar arreglos rectangulares o hiperrectangulares.
La matriz es el más básico de los arreglos dimensionales conformados por vectores. La matriz tiene dos dimensiones: filas y columnas. Para la conformación de tales estructuras basta con ligar un atributo de dimensionalidad al vector. Tales arreglos seguirán conteniendo elementos de la misma naturaleza, por lo cual siguen siendo del mismo tipo del vector base.
A estos objetos que solamente permiten alojar elementos de naturaleza común se les denomina atómicos.
La figura 10.2 se representan una serie de objetos atómicos. El panel de la izquierda representa una serie de vectores de diferentes tipos y de diferentes tamaños. No obstante, cada vector contiene elementos de un tipo común.
El panel de la derecha representa un arreglo rectangular en dos dimensiones (una matriz), cuyos elementos son todos del mismo tipo.
Cada uno de los vectores del panel izquierdo es un objeto atómico. La matriz que aparece representada en el panel derecho también es un objeto atómico.
Cualquier estructura contenedora que permita alojar elementos de diversa naturaleza se denomina recursiva.
La forma más general de las estructuras recursivas es la lista. Esta estructura permite alojar objetos de diferente tipo, sin importar el tamaño ni la dimensionalidad de los mismos, ni que estos tengan o no tengan nombres (Ver figura 10.3 (a)).
Un caso particular de lista es el data frame. Esta estructura recursiva está diseñada para alojar vectores de diferentes tipos. Los vectores son los elementos básicos de esta lista. Adicionalmente debe satisfacerse que todos los vectores tengan nombre y que tengan el mismo tamaño (Ver figura 10.3 (b)).


La figura 10.3 (a) ilustra una lista con 6 elementos: dos matrices, un data frame y tres vectores, uno de los cuales es de tamaño 1.
Nótese que las dos matrices contenidas en esta lista son de diferente tipo y de diferente tamaño, no obstante, cada matriz, al ser un objeto atómico, está conformada por elementos del mismo tipo.
Asimismo, los vectores pueden ser de diferente tipo y de diferente tamaño, pero, al tratarse también de objetos atómicos, cada vector está conformado por elementos del mismo tipo. Vale la pena llamar la atención sobre el tercer elemento de la lista: un vector de tamaño 1.
El cuarto elemento de esta lista es un data frame, el cual tiene las mismas restricciones del que se presenta en la figura 10.3 (b): está conformado por vectores del mismo tamaño, cada uno de los cuales tiene un nombre.