Capítol 3 Objetos de R

3.1 Colecciones de objetos

3.1.1 Tipo básicos

Numeric

Los números, en R, en general se guardan en coma flotante y doble precisión ("double").

a <- 3.7
class(a)
## [1] "numeric"
typeof(a)
## [1] "double"

Todo objeto tiene una clase que se puede consultar con la función class(). Adicionalmente se puede saber el tipo de datos interno con typeof().

La precisión doble es exacta hasta los 16 dígitos. La siguiente expresión debería dar 0, pero no es así.

sqrt(2)^2 - 2
## [1] 4.440892e-16

Integer

Para indicar que es un entero, hay que finalizar el número con L mayúscula. Ahorran memoria pero pierden precisión. No es muy habitual su uso en Data Science.

a <- 4L
class(a)
## [1] "integer"
typeof(a)
## [1] "integer"

Logical

Los tipos lógicos TRUE (o T) y FALSE (o F), son de uso común para filtrar vectores.

a <- 3 > 4
a
## [1] FALSE
class(a)
## [1] "logical"
typeof(a)
## [1] "logical"

Se pueden convertir a 1 y 0 (respectivamente) con as.numeric().

b <- as.numeric(a)
b
## [1] 0

Character

Texto entre comas simple o dobles.

a <- "hola"  # o con comas simples: 'hola' 
class(a)
## [1] "character"
typeof(a)
## [1] "character"

Factor

Información categórica, por ejemplo, el color de los ojos. Por su naturaleza de conjunto, se explican dentro de la sección de vectores.

Fechas y horarios

Las fechas y horarios, son una clase compleja. Internamente son de tipo "double" con dos clases: "POSIXct" "POSIXt".

a <- Sys.time()
a
## [1] "2021-01-13 01:24:34 CET"
class(a)
## [1] "POSIXct" "POSIXt"
typeof(a)
## [1] "double"

La clase "POSIXct" internamente almacena el número de segundos transcurridos entre la fecha y las 12:00 AM del 1 de enero de 1970 (en la zona del Tiempo Universal Coordinado (UTC)). Se puede obtener este valor con unclass().

unclass(a)  # muestra el valor interno de a
## [1] 1610497474

La clase Date, almacena sólo la fecha.

b <- as.Date(a)
b
## [1] "2021-01-13"
class(a)
## [1] "POSIXct" "POSIXt"
typeof(a)
## [1] "double"

La clase Date contiene el número de días transcurridos des de 1 de enero de 1970.

unclass(b)
## [1] 18640

Se ampliará esta clase en el capítulo dedicado al package lubridate.

3.1.2 Vectores

Se define mediante la función c(). Adopta el mismo tipo básico que los datos que lo componen.

class(c(3.1,9.7))
## [1] "numeric"
class(c(4L, 8L))
## [1] "integer"
class(c(TRUE, FALSE))
## [1] "logical"
class(c("es", "un", "vector"))
## [1] "character"
class(c(Sys.Date(), Sys.Date() + 1, Sys.Date()+2))
## [1] "Date"

Longitud

Con length() se obtiene el número de elementos.

a <- c(2,4,6)
length(a)
## [1] 3

Nombres

Los vectores pueden tener atributos. Es de uso común el atributo names.

names(a) <- c("dos","cuatro", "seis")
a
##    dos cuatro   seis 
##      2      4      6

Operaciones aritméticas

Operaciones aritméticas con vectores.

c(1,2,3) * 2  # multiplicación por escalar
## [1] 2 4 6
c(1,2,3) + c(4,5,6) # suma vectores
## [1] 5 7 9
c(1,2,3) * c(4,5,6) # producto elemento a elemento
## [1]  4 10 18

Operaciones con texto

paste(1:3,c("uno","dos", "tres"), sep="-") # junta vectores
## [1] "1-uno"  "2-dos"  "3-tres"
paste(c("Hola,","Mundo!"), collapse = " ") # junta elementos de un vector
## [1] "Hola, Mundo!"
substr("abcdefgh", 3, 4)   # subcadenas
## [1] "cd"

Secuencias

3:5
## [1] 3 4 5
seq(from = 2, to = 6, by = 2)
## [1] 2 4 6
rep(0, times = 3)
## [1] 0 0 0
rep(1:3, each = 2)
## [1] 1 1 2 2 3 3

Factor

Son vectores de enteros, donde cada entero tiene asignado una etiqueta.

color_ojos <- factor(c("marron", "azul",  "azul", "verde"))
color_ojos
## [1] marron azul   azul   verde 
## Levels: azul marron verde

El atributo levels contiene las etiquetas. Se puede consultar con levels(). Por defecto, los levels se crean en orden alfanumérico a partir de los valores del vector. También se pueden definir por parámetro.

color_ojos <- factor(c("marron", "azul",  "azul", "verde"),
                     levels = c("marron", "azul", "verde"))
levels(color_ojos)
## [1] "marron" "azul"   "verde"

Los factores, se codifican internamente como ‘integer.’ Cada entero, contiene la posición en el vector de levels. Esta forma de codificar, ahorra memoria y acelera los cálculos. Se puede recuperar los valores integer con unclass().

class(color_ojos)
## [1] "factor"
typeof(color_ojos)
## [1] "integer"
unclass(color_ojos)
## [1] 1 2 2 3
## attr(,"levels")
## [1] "marron" "azul"   "verde"

También se pueden transformar a character con as.character().

as.character(color_ojos)
## [1] "marron" "azul"   "azul"   "verde"

3.1.3 Matrices

Las matrices añaden otra dimensión (fila) a los vectores (columna).

a <- matrix(1:6, ncol = 2)
a
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6

Por defecto se rellenan por columna, pero se puede modificar a rellenado por filas.

a <- matrix(1:6, ncol = 2, byrow = TRUE)
a
##      [,1] [,2]
## [1,]    1    2
## [2,]    3    4
## [3,]    5    6

Dimensión

Se puede consultar el número de filas y columnas con dim(), ncol() y nrow().

dim(a)
## [1] 3 2
nrow(a)
## [1] 3
ncol(a)
## [1] 2

Nombres

Se puede asignar nombres a las filas y a las columnas.

colnames(a) <- paste0("V",1:ncol(a))
rownames(a) <- LETTERS[1:(nrow(a))]
a
##   V1 V2
## A  1  2
## B  3  4
## C  5  6

3.1.3.1 Arrays

Se puede generalizar las matrices a más de 2 dimensiones con array().

a <- array(11:18, dim=c(2,2,2))
a
## , , 1
## 
##      [,1] [,2]
## [1,]   11   13
## [2,]   12   14
## 
## , , 2
## 
##      [,1] [,2]
## [1,]   15   17
## [2,]   16   18

3.1.4 Listas

Las listas permiten agrupar objetos R con distintos tipos de datos.

a <- list(11:13, "R", matrix(1:4,2,2))
a
## [[1]]
## [1] 11 12 13
## 
## [[2]]
## [1] "R"
## 
## [[3]]
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4

Nombres

Se les puede asignar un nombre a cada elemento.

names(a) <- c("es_num", "es_char", "es_matriz")

3.1.5 Data frames

Formalmente son una lista de vectores de la misma longitud. Tienen forma de matriz.

a <- data.frame(V1=c(1,2,3), V2=c("R","S","T"), V3=c(TRUE, FALSE,TRUE))
class(a)
## [1] "data.frame"
typeof(a)
## [1] "list"
kable(a)
V1 V2 V3
1 R TRUE
2 S FALSE
3 T TRUE

Para conocer la estructura del objeto es útil la función str().

str(a)
## 'data.frame':    3 obs. of  3 variables:
##  $ V1: num  1 2 3
##  $ V2: chr  "R" "S" "T"
##  $ V3: logi  TRUE FALSE TRUE

Se utilizan las mismas reglas que en las matrices para saber la dimensión, nombres de filas y columnas.

3.2 Filtrado de objetos

Para filtrar matrices y data frames se utiliza corchetes separados por coma [,]. En el caso de vectores, corchetes simples [].

Los datos de paises07 servirán de ejemplo.

suppressPackageStartupMessages(library(tidyverse))
library(datos)
library(knitr)

paises07 <- as.data.frame(paises %>% filter(anio==2007))

class(paises07)
## [1] "data.frame"
dim(paises07)
## [1] 142   6
colnames(paises07)
## [1] "pais"              "continente"        "anio"              "esperanza_de_vida"
## [5] "poblacion"         "pib_per_capita"

Con head() (respec. tail()), se obtiene las primeras (resp. últimas) 6 filas.

kable(head(paises07))
pais continente anio esperanza_de_vida poblacion pib_per_capita
Afganistán Asia 2007 43.828 31889923 974.5803
Albania Europa 2007 76.423 3600523 5937.0295
Argelia África 2007 72.301 33333216 6223.3675
Angola África 2007 42.731 12420476 4797.2313
Argentina Américas 2007 75.320 40301927 12779.3796
Australia Oceanía 2007 81.235 20434176 34435.3674

Enteros positivos

Se puede indicar las posiciones fila y columna a seleccionar. Por ejemplo, la esperanza de vida de Angola y Australia.

paises07[c(4,6),4]
## [1] 42.731 81.235

Para evitar que el resultado pase de data frame a vector, se utiliza el parámetro drop.

kable(paises07[c(4,6), 4, drop=FALSE])
esperanza_de_vida
4 42.731
6 81.235

Si no se informa la columna (alternativamente fila), se seleccionan todos sus valores.

kable(paises07[c(4,6),])
pais continente anio esperanza_de_vida poblacion pib_per_capita
4 Angola África 2007 42.731 12420476 4797.231
6 Australia Oceanía 2007 81.235 20434176 34435.367

En el caso de vectores, se utiliza un solo corchete.

a <- c(5,2,4,7,9)
a[c(2,2,1,5)]
## [1] 2 2 5 9

Observa que se pueden repetir posiciones o índices. Tampoco es necesario mantener un orden monótono en los índices.

Enteros negativos

Selecciona todas las columnas (alternativamente las filas) excepto las posiciones indicadas con valor negativo.

kable(head(paises07[,-c(3,5)]))
pais continente esperanza_de_vida pib_per_capita
Afganistán Asia 43.828 974.5803
Albania Europa 76.423 5937.0295
Argelia África 72.301 6223.3675
Angola África 42.731 4797.2313
Argentina Américas 75.320 12779.3796
Australia Oceanía 81.235 34435.3674

Nombres

Se utiliza habitualmente para seleccionar las columnas por su nombre.

kable(head(paises07[, c("pais","esperanza_de_vida")]))
pais esperanza_de_vida
Afganistán 43.828
Albania 76.423
Argelia 72.301
Angola 42.731
Argentina 75.320
Australia 81.235

Dolares y dobles corchetes

En listas y data frames se puede obtener un elemento con $nombre , o bien, con corchetes dobles

head(paises07$pib_per_capita)
## [1]   974.5803  5937.0295  6223.3675  4797.2313 12779.3796 34435.3674
head(paises07[["esperanza_de_vida"]])
## [1] 43.828 76.423 72.301 42.731 75.320 81.235

Una fuente habitual de error es intentar seleccionar las columnas de un objeto matrix con $nombre o dobles corchetes. Esto produce un error.

Valores lógicos

Se seleccionan las posiciones con valores TRUE o T y se descartan las posiciones FALSE o F.

kable(head(paises07[,c(F, F, F, T, F, T)]))
esperanza_de_vida pib_per_capita
43.828 974.5803
76.423 5937.0295
72.301 6223.3675
42.731 4797.2313
75.320 12779.3796
81.235 34435.3674

La forma habitual de seleccionar elementos de una matriz es mediante expresiones lógicas.

kable(paises07[paises07$continente=="Oceanía",])
pais continente anio esperanza_de_vida poblacion pib_per_capita
6 Australia Oceanía 2007 81.235 20434176 34435.37
92 Nueva Zelanda Oceanía 2007 80.204 4115771 25185.01

Para construir estas expresiones, puedes utilizar los siguientes operadores.

Operador Ejemplo
a > b ¿a mayor que b?
a >= b ¿a mayor o igual que b?
a < b ¿a menor que b?
a <= b ¿a menor o igual que b?
a == b ¿a igual a b?
a != b ¿a distinto b?
a %in% c(b,c,d) ¿a esta en el vector b, c o d?

Operadores lógicos: (fuente: elaboración propia)

Estos operadores resultan extremadamente útiles en vectores.

1 > c(0, 1, 2)
## [1]  TRUE FALSE FALSE
c(1, 2, 3) != c(3, 2, 1)
## [1]  TRUE FALSE  TRUE

El operador %in% tiene un funcionamiento un poco distinto. Evalúa cada elemento del objeto situado a su izquierda respecto a todos los elementos del objeto situado a su derecha.

c(1, 2, 3, 4) %in% c(3, 4, 5)
## [1] FALSE FALSE  TRUE  TRUE

En operadores booleanos utiliza == en vez del operador ‘=.’ Este último, hace la misma operación que <- de asignación de valores a objetos.

Operaciones booleanas

Puedes construir expresiones lógicas complejas utilizando los operadores booleanos habituales:

Operador Significado
cond1 & cond2 ¿Son las dos condiciones ciertas?
cond1 | cond1 ¿Es cierta alguna de las dos condiciones?
cond1 xor cond1 ¿Es cierta sólo una de las condiciones?
!cond1 ¿Es falsa la condición?
any(cond1,cond2,…) ¿Es cierta alguna de las condiciones?
all(cond1,cond2,…) ¿Son ciertas todas las condiciones?

Operaciones booleanas (fuente: elaboración propia).

Para seleccionar los países asiáticos con esperanza de vida media en 2007 superior o igual a 80 años.

consulta <- paises07[paises07$continente=="Asia" & paises07$esperanza_de_vida >= 80 ,]
kable(consulta)
pais continente anio esperanza_de_vida poblacion pib_per_capita
56 Hong Kong, China Asia 2007 82.208 6980412 39724.98
64 Israel Asia 2007 80.745 6426679 25523.28
67 Japón Asia 2007 82.603 127467972 31656.07

3.3 Modificacion objetos

R ofrece algunas facilidades para modificar los valores de sus objetos.

Filtro y asignación “]<-

Para modificar uno elemento de un vector, R te ofrece la posibilidad de aplicar un filtro con corchetes seguido de una asignación.

a <- 1:6
a[1] <- 10
a
## [1] 10  2  3  4  5  6

También puedes modificar varios elementos a la vez asignando un vector de la misma longitud.

a[c(3,5)] <- c(300,500)
a
## [1]  10   2 300   4 500   6
a[4:6] <- a[4:6] + 1
a
## [1]  10   2 300   5 501   7

Puedes añadir elementos nuevos a un vector.

a[7] <- 7
a
## [1]  10   2 300   5 501   7   7

También puedes modificar varios elementos asignando un único valor.

a[c(3,5,7)] <- 0
a
## [1] 10  2  0  5  0  7  0

En data frames (y listas) se pueden añadir columnas (resp. elementos).

suppressPackageStartupMessages(library(tidyverse))
library(datos)
library(knitr)

paises07$id <- 1:nrow(paises07)
kable(head(paises07))
pais continente anio esperanza_de_vida poblacion pib_per_capita id
Afganistán Asia 2007 43.828 31889923 974.5803 1
Albania Europa 2007 76.423 3600523 5937.0295 2
Argelia África 2007 72.301 33333216 6223.3675 3
Angola África 2007 42.731 12420476 4797.2313 4
Argentina Américas 2007 75.320 40301927 12779.3796 5
Australia Oceanía 2007 81.235 20434176 34435.3674 6

Modificar el nombre de una columna.

colnames(paises07)[colnames(paises07)=="id"] <- "identificador"
colnames(paises07)
## [1] "pais"              "continente"        "anio"              "esperanza_de_vida"
## [5] "poblacion"         "pib_per_capita"    "identificador"

Eliminar las columnas (resp. elmentos) con el objeto NULL.

paises07$identificador <- NULL
colnames(paises07)
## [1] "pais"              "continente"        "anio"              "esperanza_de_vida"
## [5] "poblacion"         "pib_per_capita"

3.4 Información faltante

Para marcar los valores faltantes en R se utiliza la combinación NA (acrónimo de Not Available). Este valor especial tiene su propia aritmética.

a <- 3 + c(NA, 4)
a
## [1] NA  7

Es decir, cuando un valor es desconocido, la mejor opción es no evaluar la suma con otros valores. Las expresiones lógicas se comportan de un modo similar.

c(8, NA) > 0
## [1] TRUE   NA

Seleccion filas missings

Para seleccionar las filas con valores faltantes, entre otros usos, puedes utilizar la función is.na().

# Introducimos algunos NA para el ejemplo
paises07NA <- paises07
paises07NA$pib_per_capita[c(34,70,108)] <- NA
kable(summary(paises07NA))
pais continente anio esperanza_de_vida poblacion pib_per_capita
Afganistán: 1 África :52 Min. :2007 Min. :39.61 Min. :1.996e+05 Min. : 277.6
Albania : 1 Américas:25 1st Qu.:2007 1st Qu.:57.16 1st Qu.:4.508e+06 1st Qu.: 1708.3
Argelia : 1 Asia :33 Median :2007 Median :71.94 Median :1.052e+07 Median : 6223.4
Angola : 1 Europa :30 Mean :2007 Mean :67.01 Mean :4.402e+07 Mean :11750.2
Argentina : 1 Oceanía : 2 3rd Qu.:2007 3rd Qu.:76.41 3rd Qu.:3.121e+07 3rd Qu.:18008.7
Australia : 1 NA Max. :2007 Max. :82.60 Max. :1.319e+09 Max. :49357.2
(Other) :136 NA NA NA NA NA’s :3

Para seleccionar los registros con missing en una columna.

kable(paises07NA[is.na(paises07NA$pib_per_capita),])
pais continente anio esperanza_de_vida poblacion pib_per_capita
34 República Checa Europa 2007 76.486 10228744 NA
70 Corea, Rep. Dem. Asia 2007 67.297 23301725 NA
108 Ruanda África 2007 46.242 8860588 NA

Filtros missings

La presencia de NA en una variable dificulta la definición de condiciones lógicas. Por ejemplo, si seleccionamos países con PIB per cápita inferior a 500 dólares se obtiene el siguiente resultado incorrecto:

kable(paises07NA[paises07NA$pib_per_capita<500,])
pais continente anio esperanza_de_vida poblacion pib_per_capita
18 Burundi África 2007 49.580 8390505 430.0707
28 República Democrática del Congo África 2007 46.462 64606759 277.5519
NA NA NA NA NA NA NA
NA.1 NA NA NA NA NA NA
75 Liberia África 2007 45.678 3193942 414.5073
NA.2 NA NA NA NA NA NA
142 Zimbabue África 2007 43.487 12311143 469.7093

Esta problemática se puede resolver mediante la función which().

kable(paises07NA[which(paises07NA$pib_per_capita<500),])
pais continente anio esperanza_de_vida poblacion pib_per_capita
18 Burundi África 2007 49.580 8390505 430.0707
28 República Democrática del Congo África 2007 46.462 64606759 277.5519
75 Liberia África 2007 45.678 3193942 414.5073
142 Zimbabue África 2007 43.487 12311143 469.7093

La función which() devuelve la posición de los valores TRUE dentro de un vector.

a <- c(NA, FALSE, NA, TRUE, FALSE, TRUE, NA )
which(a)
## [1] 4 6

Utiliza which para “protegerte” de la presencia de valores faltantes en la definición de filtros.