Francisco Guijarro

Universidad Politécnica de Valencia

Creative Commons Attribution 4.0 International License (CC BY 4.0)

1 Tipos de datos

1.1 Números, cadenas de texto, valores lógicos y factores

La mayor parte de la información puede representarse mediantes dos tipos básicos: números y texto. Por ejemplo, la siguiente línea de código suma dos números, cuyo resultado es, obviamente, otro número:

3+5
## [1] 8

Los números pueden ser cantidades enteras o pueden contener decimales

3+5.5
## [1] 8.5

Pero igualmente el resultado de la suma sigue siendo un número. Lo que no podemos hacer es sumar un número con una cadena de texto:

3+"casa"

La última línea de código deberá generar un error con el siguiene mensaje:

Error in 3 + "casa" : argumento no-numérico para operador binario

que traducido del austro-húngaro viene a decir que estamos intentando sumar cosas que no son compatibles. Esto es, que el operador suma + no está definido para el caso de que alguno de los argumentos no sea numérico. Cuestión diferente hubiera sido hacer lo siguiente:

casa <- 10
3+casa
## [1] 13

Observa la diferencia entre "casa" y casa. En el primer caso, el término "casa" se refiere a una simple cadena de texto. Al quitar las comillas, nos estamos refiriendo a la variable recién creada casa, a la que hemos asignado el valor numérico 10. Es decir, que es un número y no una cadena de texto.

Otro tipo de datos con los que habitualmente vamos a trabajar son los valores lógicos, de tipo logical al que se asocian los valores TRUE y FALSE:

casa == 10
## [1] TRUE
casa != 10
## [1] FALSE
is.logical(casa)
## [1] FALSE
is.logical(casa == 10)
## [1] TRUE

Para borrar del Environment una variable que no vamos a utilizar más, podemos emplear la función rm. De esta manera mantendremos limpio nuestro entorno de variables.

rm(casa)

Los factores son variables que tienen acotado el número de valores que pueden tomar. Los factores suelen estar referidos a variables categóricas. Un ejemplo es la variable passengerClass en el dataframe TitanicSurvival:

class(TitanicSurvival$passengerClass)
## [1] "factor"

Los diferenes valores que puede tomar un factor se denominan niveles, y puedes ser accesibles a través de la función levels:

levels(TitanicSurvival$passengerClass)
## [1] "1st" "2nd" "3rd"
levels(TitanicSurvival$sex)
## [1] "female" "male"

En este caso los valores representan cadenas de texto, como también ocurre con la variable survived:

levels(TitanicSurvival$survived)
## [1] "no"  "yes"

Puedes observar como en todos los casos los niveles aparecen ordenados alfabéticamente, pudiendo acceder individualmente a cada uno de ellos de la siguiente forma:

levels(TitanicSurvival$passengerClass)[1]
## [1] "1st"
levels(TitanicSurvival$sex)[2]
## [1] "male"

Podemos utilizar la siguiente expresión para conocer qué niveles de la variable passengerClass se corresponde con la cadena de texto "2nd":

levels(TitanicSurvival$passengerClass) == "2nd"
## [1] FALSE  TRUE FALSE

Fíjate como la respuesta es que de los 3 niveles del factor, únicamente el segundo se corresponde con la segunda clase. Si escribes lo siguiente, entonces obtendrás la respuesta a qué pasajeros de la base de datos viajaron en segunda clase:

TitanicSurvival$passengerClass == "2nd"
##    [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##   [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##   [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##   [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##   [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##   [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##   [73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##   [85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##   [97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [109] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [157] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [169] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [193] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [205] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [217] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [229] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [241] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [253] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [265] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [277] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [289] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [301] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [313] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
##  [325]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [337]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [349]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [361]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [373]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [385]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [397]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [409]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [421]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [433]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [445]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [457]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [469]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [481]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [493]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [505]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [517]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [529]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [541]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [553]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [565]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [577]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [589]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [601] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [613] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [625] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [637] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [649] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [661] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [673] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [685] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [697] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [709] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [721] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [733] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [745] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [757] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [769] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [781] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [793] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [805] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [817] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [829] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [841] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [853] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [865] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [877] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [889] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [901] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [913] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [925] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [937] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [949] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [961] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [973] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [985] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [997] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1009] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1021] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1033] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1045] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1057] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1069] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1081] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1093] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1105] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1117] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1129] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1141] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1153] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1165] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1177] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1189] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1201] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1213] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1225] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1237] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1249] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1261] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1273] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1285] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1297] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1309] FALSE

En los dos últimos casos, observa que la respuesta obtenida es de tipo logical.

Ejercicio 1

A partir de la última expresión y la función sum, escribe el código que permita calcular el número de pasajeros que viajaron en primera clase. El resultado debería coincidir con el siguiente valor:

## [1] 323

Otra función interesante es which, que permite identificar aquellas observaciones que cumplen determinada condición:

which(TitanicSurvival$passengerClass == "1st")
##   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
##  [19]  19  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  53  54
##  [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
##  [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
##  [91]  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108
## [109] 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
## [127] 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
## [145] 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
## [163] 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
## [181] 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
## [199] 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
## [217] 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
## [235] 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
## [253] 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
## [271] 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
## [289] 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
## [307] 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323

Como ves, la función which devuelve las posiciones (filas) que ocupan los pasajeros que cumplen la condición: viajar en primera clase.

Ejercicio 2

Calcula el número de pasajeros que cumplen la siguiente doble condición: viajaban en primera clase y eran mujeres. Identifica qué filas ocupan en la base de datos. Para configurar diferentes condiciones emplea el símbolo &, que permite concatenar cuantas condiciones necesitemos.

Una vez analizados los tipos básicos de datos que podemos manejar en R, vamos a ver cómo se pueden estructurar en elementos algo más complejos.

Apoyándonos en la siguiente figura, vamos a explicar las principales estructuras de datos que pueden manejarse en R:

Resumen de estructuras de datos en R.

1.2 Escalares

Un escalar representa el elemento más básico en la estructura de datos diseñada en R. Podemos crear una variable y asignarle un escalar de la siguiente forma:

a <- 3.7

En este caso la variable a es un escalar que toma el valor 3.7. Los escalares pueden ser número enteros o fraccionarios. La variable a es numérica, representa un número fraccionario (double), pero no es un número entero (integer)

is.numeric(a)
is.double(a)
is.integer(a)

Tip

R es case-sensitive. Es decir, no es lo mismo la variable a que la variable A. Prueba a escribir is.numeric(A).

También podemos crear elementos básicos que no sean numéricos:

b <- "Hola"

Y comprobar qué tipo de dato estamos almacenando en b:

is.numeric(b)
is.character(b)

Las anteriores funciones, así como cualquier otra de R, siempre van a tener la siguiente estructura:

nombre.función(parámetro/s)

Por ejemplo, en el comando is.character(b), is.character es el nombre de la función, mientras que b es el único parámetro. Algunas funciones admitirán más de un parámetro.

Para conocer el detalle de los parámetros se puede acudir a la ayuda de R:

?is.character

1.3 Vectores

Un vector se define como un conjunto ordenado de elementos, todos del mismo tipo, que en R se pueden concatenar con la función c:

dias <- c("lunes", "martes", "miércoles", "jueves", "viernes", "sábado", "domingo")
temperaturas <- c(24, 22, 23, 15, 17, 22, 21)

Puede accederse a un elemento concreto o a varios de ellos:

dias[3]
dias[3:5]
dias[c(3,5)]

También puedes aplicar operaciones accediendo a los diferentes elementos de estas variables. Aquí algunos ejemplos:

mean(temperaturas)
## [1] 20.57143
summary(temperaturas)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   15.00   19.00   22.00   20.57   22.50   24.00
2*temperaturas[3]
## [1] 46
temperaturas[1]+temperaturas[2]+temperaturas[3]
## [1] 69
plot(temperaturas)

Ejercicio 3

Observa como 3:5 genera la secuencia 3 4 5. Escribe print(0:10) y comprueba qué resultado se obtiene ¿Cómo crearías una secuencia de 10 a 0? ¿Y una secuencia de 10 a 0 pero de 2 en 2? Para la última pregunta ayúdate de la función seq.

Ejercicio 4

Obtén con una sólo línea de código qué elementos del vector temperaturas están por encima del valor 20. El resultado debería ser el siguiente:

## [1]  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE

1.4 Matrices

Las matrices son estructuras de datos con dos dimensiones: filas y columnas. Se definen a través de la función matrix:

matrix(c(1:10, 10:1), ncol = 10, nrow = 2)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,]    1    3    5    7    9   10    8    6    4     2
## [2,]    2    4    6    8   10    9    7    5    3     1

Observa cómo los parámetros ncoly nrow permiten definir completamente la dimensión de la matriz. Es más, en realidad podemos definir esta dimensión asignando valor a uno de los parámetros, y dejando el otro vacío para que lo infiera R:

secuencia <- matrix(c(1:10, 10:1), ncol = 2)
secuencia
##       [,1] [,2]
##  [1,]    1   10
##  [2,]    2    9
##  [3,]    3    8
##  [4,]    4    7
##  [5,]    5    6
##  [6,]    6    5
##  [7,]    7    4
##  [8,]    8    3
##  [9,]    9    2
## [10,]   10    1

Para referirse a un elemento concreto o una fila/columna:

secuencia[4, 2]
secuencia[3, ]
secuencia[, 1]

1.5 Data frames

El data frame es una matriz donde las columnas tienen nombre:

temp_semana <- data.frame(dias, temperaturas)
temp_semana
##        dias temperaturas
## 1     lunes           24
## 2    martes           22
## 3 miércoles           23
## 4    jueves           15
## 5   viernes           17
## 6    sábado           22
## 7   domingo           21

Podemos referirnos a las columas bien a través del nombre de las mismas, o bien a través del número de columna que ocupan:

temp_semana$dias
temp_semana[, 1]

Al ejecutar el código anterior, se puede comprobar cómo la variable original dias ha pasado de ser de tipo character a Factor. Como se comentó en un punto anterior, el tipo factor está diseñado para representar variables categóricas.

Además de seleccionar columnas mediante el número de las mimas o mediante el símbolo $, también podemos seleccionar subgrupos de observaciones que, por ejemplo, cumplan determinada condición. Por ejemplo, el siguiente código mostrará los días donde la temperatura fue mayor que 22 grados:

temp_semana$temperaturas > 22
## [1]  TRUE FALSE  TRUE FALSE FALSE FALSE FALSE
temp_semana$dias[temp_semana$temperaturas > 22]
## [1] "lunes"     "miércoles"

Si queremos conocer los días en los que la temperatura fue exactamente de 22 grados:

temp_semana$dias[temp_semana$temperaturas == 22]
## [1] "martes" "sábado"

Añadir columnas a un data frame es sencillo. Por ejemplo, la siguiente línea de código añade una columna qué indica qué días se superaron los 20 grados:

temp_semana$temp_mayor_20 <- temp_semana$temperatura > 20
temp_semana
##        dias temperaturas temp_mayor_20
## 1     lunes           24          TRUE
## 2    martes           22          TRUE
## 3 miércoles           23          TRUE
## 4    jueves           15         FALSE
## 5   viernes           17         FALSE
## 6    sábado           22          TRUE
## 7   domingo           21          TRUE

También se puede eliminar fácilmente una columna asignándole el valor NULL:

temp_semana$temp_mayor_20 <- NULL
temp_semana
##        dias temperaturas
## 1     lunes           24
## 2    martes           22
## 3 miércoles           23
## 4    jueves           15
## 5   viernes           17
## 6    sábado           22
## 7   domingo           21

1.6 Listas

Una lista es un conjunto ordenado de objetos o variables. Por lo general, se utilizan para combinar elementos de origen y formato diferente bajo una misma denominación. Por ejemplo, y aunque en este caso los elementos sí guardan relación, podríamos combinar las temperaturas y los días de la semana en una lista:

lista <- list(dias, temperaturas)
lista
## [[1]]
## [1] "lunes"     "martes"    "miércoles" "jueves"    "viernes"   "sábado"   
## [7] "domingo"  
## 
## [[2]]
## [1] 24 22 23 15 17 22 21

Podemos acceder a sus elementos de diferentes formas:

lista[1]
## [[1]]
## [1] "lunes"     "martes"    "miércoles" "jueves"    "viernes"   "sábado"   
## [7] "domingo"
lista[2]
## [[1]]
## [1] 24 22 23 15 17 22 21
class(lista[2])
## [1] "list"
lista[[2]]
## [1] 24 22 23 15 17 22 21
class(lista[[2]])
## [1] "numeric"
lista[[2]][4]
## [1] 15

Observa como se ha mantenido el orden de los elementos que integran la lista. En primer lugar los días de la semana, en segundo las temperaturas. Observa como lista[2] es un objeto tipo lista, mientras que lista[[2]] es un vector de números. Como indicábamos anteriormente, una lista puede incluir elementos que nada tengan que ver entre sí:

lista <- list(dias = dias, temperaturas = temperaturas, nombres = c("Federico", "María", "Mikel", "Andrea"))
lista
## $dias
## [1] "lunes"     "martes"    "miércoles" "jueves"    "viernes"   "sábado"   
## [7] "domingo"  
## 
## $temperaturas
## [1] 24 22 23 15 17 22 21
## 
## $nombres
## [1] "Federico" "María"    "Mikel"    "Andrea"

A diferencia de la primera definición, ahora estamos asignando un nombre a cada una de las 3 listas que componen la variable lista. Esto permite poder acceder a sus elementos de formas alternativas:

lista[[3]]
## [1] "Federico" "María"    "Mikel"    "Andrea"
lista$nombres
## [1] "Federico" "María"    "Mikel"    "Andrea"

Las listas definidas en R pueden tener la complejidad que necesitemos en nuestros cálculos, pudiendo combinar vectores de diferente tamaño como en el caso anterior, o incluso escalares, vectores, matrices, etc:

lista <- list(dias = dias, numero = runif(1), nombres = c("Federico", "María", "Mikel", "Andrea"), matriz = secuencia)
lista
## $dias
## [1] "lunes"     "martes"    "miércoles" "jueves"    "viernes"   "sábado"   
## [7] "domingo"  
## 
## $numero
## [1] 0.598173
## 
## $nombres
## [1] "Federico" "María"    "Mikel"    "Andrea"  
## 
## $matriz
##       [,1] [,2]
##  [1,]    1   10
##  [2,]    2    9
##  [3,]    3    8
##  [4,]    4    7
##  [5,]    5    6
##  [6,]    6    5
##  [7,]    7    4
##  [8,]    8    3
##  [9,]    9    2
## [10,]   10    1

2 La librería dplyr

La librería dplyr es una de las librerías de R más potentes para el manejo y transformación de datos. La siguiente cheatsheet de RStudio muestra alguna de sus funcionalidades más relevantes, algunas de las cuales iremos introduciendo poco a poco:

Cheat sheet de la librería dplyr. Cheat sheet de la librería dplyr (Cont.).

De momento, vamos a hacer uso de los denominados pipes %>% que sirven para encadenar funciones y pasar dataframes a dichas funciones, así como las funciones filter y select (recuerda instalar la librería dplyr antes de correr el siguiente código:

library(dplyr)
temp_semana %>%
  filter(temperaturas == 22) %>%
  select(dias)
##     dias
## 1 martes
## 2 sábado

En el siguiente bloque se introducirá otra función de dplyr muy socorrida: group_by.

3 Ejercicios

En este ejercicio vamos a repasar algunas de las funciones vistas hasta ahora, así como aprender algunas nuevas. Para ello, utilizaremos el dataframe Salaries de la librería carData, que incluye información sobre los salarios de diferentes categorías de profesores en universidades de EEUU durante el periodo 2008-09:

data(Salaries)
head(Salaries)
##        rank discipline yrs.since.phd yrs.service  sex salary
## 1      Prof          B            19          18 Male 139750
## 2      Prof          B            20          16 Male 173200
## 3  AsstProf          B             4           3 Male  79750
## 4      Prof          B            45          39 Male 115000
## 5      Prof          B            40          41 Male 141500
## 6 AssocProf          B             6           6 Male  97000
str(Salaries)
## 'data.frame':    397 obs. of  6 variables:
##  $ rank         : Factor w/ 3 levels "AsstProf","AssocProf",..: 3 3 1 3 3 2 3 3 3 3 ...
##  $ discipline   : Factor w/ 2 levels "A","B": 2 2 2 2 2 2 2 2 2 2 ...
##  $ yrs.since.phd: int  19 20 4 45 40 6 30 45 21 18 ...
##  $ yrs.service  : int  18 16 3 39 41 6 23 45 20 18 ...
##  $ sex          : Factor w/ 2 levels "Female","Male": 2 2 2 2 2 2 2 2 2 1 ...
##  $ salary       : int  139750 173200 79750 115000 141500 97000 175000 147765 119250 129000 ...

La columna rank se refiere a 3 categorías distintas de profesores:

  • AsstProf, o profesor asistente. Según el siguiente enlace de Wikipedia, “el rango de profesor asistente en general se mantiene durante un período de prueba de cinco a siete años, después de lo cual o bien se promovió el individuo a profesor asociado y concedió la tenencia (es decir, no puede ser despedido sin causa y un proceso de audiencia formal) o se dará por terminado de empleo”. Es decir, sería el equivalente a nuestros profesores contratados, como los perfiles de Profesor Ayudante o Profesor Colaborador.

  • AssocProf, o profesor asociado, cuya definición es muy diferente al del caso español: “Después de varios años en la categoría de profesor asistente, los individuos son considerados para un ascenso y la tenencia . La tenencia constituye generalmente un acuerdo de empleo de por vida”. El equivalente español sería Profesor Titular de Universidad

  • Prof, equivalente a Catedrático de Universidad.

La columna discipline hace referencia al tipo de departamento al que está adscrito el profesor:

  • A: teórico.

  • B: aplicado.

Además, tenemos el género de los profesores (sex), los años desde que obtuvieron el título de Doctor (yrs.since.phd), los años de servicio (yrs.service), y el salario en dólares (salary).

Ejercicio 5

Obtén los estadísticos descriptivos básicos (mínimo, percentil del 25%, media, etc) de la variable salary:

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   57800   91000  107300  113706  134185  231545

Lo anterior también puede realizarse para cada una de las categorías de profesor. La función group_by de la librería dplyr permite agrupar las observaciones que cumplen con un determinado criterio. Por ejemplo, podemos querer calcular algunos estadísticos descriptivos de salary para los 3 grupos de profesores que tenemos en el dataframe:

Salaries %>%
  group_by(rank) %>%
  summarise(media = mean(salary), sd = sd(salary))
## # A tibble: 3 x 3
##   rank        media     sd
##   <fct>       <dbl>  <dbl>
## 1 AsstProf   80776.  8174.
## 2 AssocProf  93876. 13832.
## 3 Prof      126772. 27719.

Observa que el resultado en una nueva estructura de datos denominada tibble, una combinación de las palabras table y bible; esto es, una tabla de proporciones (a priori) bíblicas.

También podemos incluir en el anterior resultado el número de profesores en cada categoría a través de la función n():

Salaries %>%
  group_by(rank) %>%
  summarise(media = mean(salary), sd = sd(salary), n_profesores = n())
## # A tibble: 3 x 4
##   rank        media     sd n_profesores
##   <fct>       <dbl>  <dbl>        <int>
## 1 AsstProf   80776.  8174.           67
## 2 AssocProf  93876. 13832.           64
## 3 Prof      126772. 27719.          266

O que el resultado se ordene en función de una varible de interés. Por ejemplo, que la tabla aparezca ordenada en función del número de profesores por categoría. Para ellos podemos utilizar la función arrange:

Salaries %>%
  group_by(rank) %>%
  summarise(media = mean(salary), sd = sd(salary), n_profesores = n()) %>%
  arrange(n_profesores)
## # A tibble: 3 x 4
##   rank        media     sd n_profesores
##   <fct>       <dbl>  <dbl>        <int>
## 1 AssocProf  93876. 13832.           64
## 2 AsstProf   80776.  8174.           67
## 3 Prof      126772. 27719.          266

Si quisiéramos representarlo en orden inverso:

Salaries %>%
  group_by(rank) %>%
  summarise(media = mean(salary), sd = sd(salary), n_profesores = n()) %>%
  arrange(-n_profesores)
## # A tibble: 3 x 4
##   rank        media     sd n_profesores
##   <fct>       <dbl>  <dbl>        <int>
## 1 Prof      126772. 27719.          266
## 2 AsstProf   80776.  8174.           67
## 3 AssocProf  93876. 13832.           64

Si, además, quieres que el resultado no sea de tipo tibble sino el clásico dataframe:

Salaries %>%
  group_by(rank) %>%
  summarise(media = mean(salary), sd = sd(salary), n_profesores = n()) %>%
  arrange(-n_profesores) %>%
  as.data.frame()
##        rank     media        sd n_profesores
## 1      Prof 126772.11 27718.675          266
## 2  AsstProf  80775.99  8174.113           67
## 3 AssocProf  93876.44 13831.700           64

También podemos querer visualizar a través de un histograma:

Ejercicio 6

Obtén un histograma de los salarios utilizando el parámetro breaks para configurar el número de barras; por ejemplo breaks = 50. Los parámetros xlab e ylab te servirán para colocar las leyendas en los ejes, mientras que con main podrás indicar el nombre del gráfico:

Ejercicio 7

Calcula los salarios medios de cada categoría de profesorado pero diferenciando por género. Deberías obtener algo similar a:

Mujeres:

## # A tibble: 3 x 3
##   rank        media     sd
##   <fct>       <dbl>  <dbl>
## 1 AsstProf   78050.  9372.
## 2 AssocProf  88513. 17965.
## 3 Prof      121968. 19620.

Hombres:

## # A tibble: 3 x 3
##   rank        media     sd
##   <fct>       <dbl>  <dbl>
## 1 AsstProf   81311.  7901.
## 2 AssocProf  94870. 12891.
## 3 Prof      127121. 28214.

Ejercicio 8

Habrás observado diferencias en cuanto a medias y dispersión en los salarios según el género. ¿Podría haber otra variable que explicara estas diferencias?

Ejercicio 9

Calcula la matriz de correlaciones entre las siguientes variables numéricas: salary, yrs.since.phd, yrs.service:

##                  salary yrs.since.phd yrs.service
## salary        1.0000000     0.4192311   0.3347447
## yrs.since.phd 0.4192311     1.0000000   0.9096491
## yrs.service   0.3347447     0.9096491   1.0000000

A continuación tienes una imagen que puede recordarte cómo interpretar los coeficientes de correlación:

Imagen de correlación (tomada de https://commons.wikimedia.org/wiki/File:Correlation_examples2.svg) Imagen del entorno RStudio con diferentes paneles.

Ejercicio 10

Realiza un análisis de regresión múltiple que explique el precio en función del resto de variables. Emplea la función lm, cuyo formato tienes que encontrar a partir de la ayuda. Una vez realizada la regresión, cuyos resultados aparecen a continuaión, responde a estas cuestiones. ¿Te parece adecuado el valor del \(R^2\) ajustado? ¿Cuál es la variables menos significativa (o no significativa en este caso)? Observa los coeficientes de yrs.service y yrs.since.phd. ¿Te parecen coherentes respecto del signo que tenían en la matriz de correlaciones? Cuando un coeficiente cambia su signo respecto del inicialmente pautado por el análisis de correlación, podemos estar ante un problema de multicolinealidad. El problema de la multicolinealidad puede afectar a los resultados de la regresión. El modelo de regresión asume que las variables independientes no están correlacionadas entre sí; es decir, que pueden explicar partes diferentes del salario. Cuando esta hipótesis no se cumple, podemos encontrarnos problemas al aplicar el modelo de regresión sobre datos fuera de la muestra considerada.

help('lm')
## 
## Call:
## lm(formula = salary ~ ., data = Salaries)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -65248 -13211  -1775  10384  99592 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    65955.2     4588.6  14.374  < 2e-16 ***
## rankAssocProf  12907.6     4145.3   3.114  0.00198 ** 
## rankProf       45066.0     4237.5  10.635  < 2e-16 ***
## disciplineB    14417.6     2342.9   6.154 1.88e-09 ***
## yrs.since.phd    535.1      241.0   2.220  0.02698 *  
## yrs.service     -489.5      211.9  -2.310  0.02143 *  
## sexMale         4783.5     3858.7   1.240  0.21584    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 22540 on 390 degrees of freedom
## Multiple R-squared:  0.4547, Adjusted R-squared:  0.4463 
## F-statistic:  54.2 on 6 and 390 DF,  p-value: < 2.2e-16

Ejercicio 11

Según el anterior modelo, ¿cuál es la diferencia media en el salario entre un catedrático (professor) y un contratado (assistant professor), suponiendo que el resto de variables se mantienen constantes?

Ejercicio 12

En cualquier caso, parece que el género no influye en el salario. Repite la regresión múltiple pero excluyendo la variable sex. ¿Ha habido cambios en el valor del \(R^2\) ajustado? ¿Realmente perdemos algo por eliminar una variable cuyo coeficiente no ha resultado significativo? ¿Seguimos teniendo problemas con el signo de algún coeficiente?

## 
## Call:
## lm(formula = salary ~ discipline + yrs.since.phd + yrs.service + 
##     rank, data = Salaries)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -65244 -13498  -1455   9638  99682 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    69869.0     3332.1  20.968  < 2e-16 ***
## disciplineB    14505.2     2343.4   6.190 1.52e-09 ***
## yrs.since.phd    534.6      241.2   2.217  0.02720 *  
## yrs.service     -476.7      211.8  -2.250  0.02497 *  
## rankAssocProf  12831.5     4147.7   3.094  0.00212 ** 
## rankProf       45287.7     4236.7  10.689  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 22550 on 391 degrees of freedom
## Multiple R-squared:  0.4525, Adjusted R-squared:  0.4455 
## F-statistic: 64.64 on 5 and 391 DF,  p-value: < 2.2e-16

Los problemas de multicolinealidad se pueden investigar a través del factor de inflado de la varianza (VIF):

library(car)
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
vif(regresion)
##                   GVIF Df GVIF^(1/(2*Df))
## discipline    1.063139  1        1.031086
## yrs.since.phd 7.518920  1        2.742065
## yrs.service   5.908984  1        2.430840
## rank          2.003562  2        1.189736

Un VIF entre 5 y 10 puede suponer problemas leves de multicolinealidad, mientras que si el VIF es superior a 10 tendríamos problemas graves de multicolinealidad.

Ejercicio 13

A raíz de los valores obtenidos del VIF, repite el modelo de regresión eliminando alguna de las variables yrs.service o yrs.since.phd, hasta obtener un modelo de regresión sin problemas de multicolinealidad. ¿Ha afectado severamente la eliminación de alguna de estas variables al valor del \(R^2\) ajustado? ¿Qué otras variables no presentes en este estudio podrían explicar las diferencias salariales?

4 Resumen de funciones empleadas en el capítulo

  • &
  • arrange
  • class
  • data.frame
  • group_by
  • is.character
  • is.double
  • is.integer
  • is.logical
  • is.numeric
  • levels
  • list
  • lm
  • matrix
  • n()
  • runif
  • seq
  • summarise
  • vif
  • which