R-Conomics

Uno de los tópicos probablemente más importantes cuando se trabaja con estadística, econometría y programación en R es trabajar con bases de datos, pero ciertamente no siempre van a estar ordenados cómo uno lo necesita, con los cálculos necesarios para nuestro objetivo ni con los parámetros necesarios para nuestro análisis, es por ello que ésta entrada tendrá como objetivo ver las diferentes formas y opciones que tenemos dentro de R/RStudio para manejar bases de datos, así como crearlas desde el programa, importarlas, hacer cálculos con ellas, entre otros tópicos.

Vectores y matrices en R.

Como bien sabemos, R es un lenguaje de programación (estadística) orientada a objetos, la cual trabaja principalmente con matrices, por lo que vamos a partir de ésto para comenzar a entender la sintaxis que iremos trabajando. Primero que nada, ¿qué es una matriz? Bueno, las podemos definir según diversos autores como vectores multidimensionales, las cuales deben tener necesariamente caracteres de una misma clase, ya sean letras, números o vectores lógicos, pero éstos no pueden ir combinados (al menos no para hacer cálculos con ellas). Las principales propiedades de los vectores son las siguientes:

  1. Tipo: Ésto se refiere al tipo de datos que contiene, ya que por ejemplo si tenemos un vector con datos de tipo numérico entonces tendremos un vector numérico, mientras que si tenemos un vector con datos de tipo carácter entonces tendremos un vector de éste tipo.

  2. Largo: Esto se refiere simplemente a la cantidad de elementos que tiene nuestro vector.

  3. Atributos: Esto se refiere a la caracteristica de los datos que tenemos en nuestro vector, es decir, metadatos.

Llevando los vectores a la consola de R

Si quisieramos saber si un determinado objeto, ya sea numérico o de caracter es un vector, le podemos preguntar a R ésto de la siguiente manera:

is.vector(1)
## [1] TRUE
is.vector("Cualquier cosa")
## [1] TRUE
is.vector(TRUE)
## [1] TRUE

Ahora, comencemos a trabajar con matrices en R. Supongamos que queremos crear un vector con, por ejemplo, 5 números. Ésto lo podemos hacer de la siguiente manera:

c(1,2,3,4,5)
## [1] 1 2 3 4 5

La consola nos devuelve el vector numérico, aunque podemos simplificar ésta tarea simplemente escribiendo lo siguiente:

c(1:5)
## [1] 1 2 3 4 5

Lo que hicimos fue escribir una secuencia del 1 al 5 con el operador “:”. Ahora no parece esencialmente práctico, pero imaginemos que tenemos que crear un vector con números del 1 al 1000, ésto nos simplificaría mucho el trabajo.

Cuando queremos trabajar con un vector en específico es recomendable convertirlo en un objeto, ya que así podemos llamarlo para la función que queramos usar. Para convertir a un vector en un objeto simplemente tenemos que usar el operador <- (también podemos utilizar =, pero es recomendable no hacerlo, ya que no estamos haciendo uso de igualdades) y asignarle el nombre que nosotros queramos a nuestro objeto, sea cual sea éste (un vector, en este caso). Por ejemplo:

#Creamos el objeto

Vector_ejemplo <- c(1:5)

# Llamamos al objeto
Vector_ejemplo
## [1] 1 2 3 4 5

De igual forma podemos crear vectores que contengan caracteres en lugar de números, simplemente debemos escribir el caracter entre comillas de la siguiente manera:

c("Perro", "Gato", "Loro")
## [1] "Perro" "Gato"  "Loro"

Replicando valores

Ahora, imaginemos que queremos crear un vector de caracteres que contenta 10 observaciones de Perro, 20 observaciones de Gato y 15 de Loro, tenemos la opción de escribir manualmente todas las observaciones, pero ésto es poco práctico y nos llevaría mucho tiempo, ¿qué podríamos hacer en este caso para agilizar la tarea? Sencillamente podemos utilizar la función rep(), en la cual debemos crear 2 vectores: Primero uno en el que especifiquemos los caracteres que queremos que tenga nuestro vector principal y luego otro en el que especifiquemos cuantas veces queremos que se repita cada caracter (escribiendolo en el mismo orden). Hagamos el ejemplo anterior:

#Creamos el vector con datos repetidos

Vectorlargo <- rep(c("Perro", "Gato", "Loro"), times = c(10, 20, 15))

# Llamamos al objeto
Vectorlargo
##  [1] "Perro" "Perro" "Perro" "Perro" "Perro" "Perro" "Perro" "Perro" "Perro"
## [10] "Perro" "Gato"  "Gato"  "Gato"  "Gato"  "Gato"  "Gato"  "Gato"  "Gato" 
## [19] "Gato"  "Gato"  "Gato"  "Gato"  "Gato"  "Gato"  "Gato"  "Gato"  "Gato" 
## [28] "Gato"  "Gato"  "Gato"  "Loro"  "Loro"  "Loro"  "Loro"  "Loro"  "Loro" 
## [37] "Loro"  "Loro"  "Loro"  "Loro"  "Loro"  "Loro"  "Loro"  "Loro"  "Loro"

Y si quisieramos saber el total de observaciones que tenemos simplemente tendríamos que usar la siguiente función:

length(Vectorlargo)
## [1] 45

La cual nos dice que en total tenemos 45 observaciones.

Operaciones básicas

Otra cosa que podemos hacer es usar operaciones aritméticas en distintos vectores, por ejemplo, sumar dos objetos de éste estilo, restarlos, dividirlos, etc. Veamos un ejemplo de ello:

#Creamos los vectores

Vector1 <- c(1:5)
Vector2 <- c(6:10)

# Aplicamos operaciones básicas con ellos

# Suma
Vector3 <- Vector1 + Vector2
Vector3
## [1]  7  9 11 13 15
# Resta 
Vector4 <- Vector1 - Vector2
Vector4 
## [1] -5 -5 -5 -5 -5
# División 
Vector5 <- Vector1 / Vector2
Vector5 
## [1] 0.1666667 0.2857143 0.3750000 0.4444444 0.5000000
# Multiplicación
Vector5 <- Vector1 * Vector2
Vector5
## [1]  6 14 24 36 50
# Juntar ambos vectores en uno que incluya todos los caracteres
Vector6 <- c(Vector1, Vector2)
Vector6
##  [1]  1  2  3  4  5  6  7  8  9 10

De igual forma, si simplemente queremos multiplicar, sumar, restar o dividir un valor en específico a nuestro vector solo debemos usar los caracteres del ejemplo anterior, como por ejemplo:

Vector1*2
## [1]  2  4  6  8 10
Vector1+2
## [1] 3 4 5 6 7
Vector1/2
## [1] 0.5 1.0 1.5 2.0 2.5
Vector1-2
## [1] -1  0  1  2  3

Otro operador útil es el operador racional, ya sea < o >, para saber qué valores son mayores o menores a un cierto valor, por ejemplo:

Vector1 > 5
## [1] FALSE FALSE FALSE FALSE FALSE
Vector1 < 5
## [1]  TRUE  TRUE  TRUE  TRUE FALSE

Puede parecer que vamos un poco lento hasta ahora, pero entender cómo funcionan los vectores en R nos servirá más adelante para comprender la forma de trabajo de bases de datos más largas.

Vectores de fechas

Uno de los vectores que probablemente más frecuentemente usemos al trabajar con bases de datos (y sobre todo con series de tiempo) serán los vectores de fechas, pero ¿por qué? A veces descargar una base de datos de internet la cual tiene un formato de fechas que R no reconoce como tal, por lo que tendremos que modificarlas para poder crear gráficos de series de tiempo, por ejemplo, pero modificarlas desde el mismo archivo de Excel, texto, etc, puede ser bastante molesto, por lo que ahora vamos a crear un vector de fechas con la frecuencia necesaria según sea el caso (más adelante veremos como unir esos datos a los que estemos usando en nuestra base de datos, ya sea un archivo de Excel o cualquier otro tipo). Para ello imaginemos lo siguiente: Supongamos que tenemos una base de datos con observaciones mensuales, para crear el vector de fechas utilizaremos un paquete llamado Lubridate, el cual nos ayudará a crear las fechas necesarias. Simplemente necesitamos saber la fecha de origen, la fecha final (por ejemplo, en este caso supondremos que inician en el 1 de enero de 2018 y terminan en el 31 de mayo de 2020) y la frecuencia de nuestra base de datos, en este caso mensual y haremos lo siguiente:

# Cargamos el paquete necesario
library(lubridate)

# Creamos el vector de fechas
Vectorfechas <- seq(as.Date("2018-01-01"), as.Date("2020-05-31"), by = "month")

# Vemos las fechas que hemos creado
Vectorfechas
##  [1] "2018-01-01" "2018-02-01" "2018-03-01" "2018-04-01" "2018-05-01"
##  [6] "2018-06-01" "2018-07-01" "2018-08-01" "2018-09-01" "2018-10-01"
## [11] "2018-11-01" "2018-12-01" "2019-01-01" "2019-02-01" "2019-03-01"
## [16] "2019-04-01" "2019-05-01" "2019-06-01" "2019-07-01" "2019-08-01"
## [21] "2019-09-01" "2019-10-01" "2019-11-01" "2019-12-01" "2020-01-01"
## [26] "2020-02-01" "2020-03-01" "2020-04-01" "2020-05-01"

Como podemos observar, nos arroja un vector que incluye las fechas mensuales desde 2018 hasta 2020 del parámetro que nosotros le indicamos. Podemos cambiar la frecuencia a por ejemplo trimestral, tal que:

Vectorfechas1 <- seq(as.Date("2018-01-01"), as.Date("2020-05-31"), by = "quarter")
Vectorfechas1
##  [1] "2018-01-01" "2018-04-01" "2018-07-01" "2018-10-01" "2019-01-01"
##  [6] "2019-04-01" "2019-07-01" "2019-10-01" "2020-01-01" "2020-04-01"

Es importante mencionar que para que R reconozca como fechas a los caracteres éstos tienen que tener la secuencia “dd/mm/aaaa” (día, mes y año) o bien “aaaa/mm/dd”, siempre con el mes en el centro.

Matrices

Las matrices tienen tanto columnas como renglones, siendo un ejemplo de ello la siguiente matriz numérica:

\[ \overset{\downarrow \;Columna \; \downarrow \qquad \qquad \quad \; \;}{\begin{pmatrix} 1 &5 & 3 & 5 & 2\\ 1 & 2 & 5 & 13 & 8 \end{pmatrix} \left.\begin{matrix} \leftarrow \\\leftarrow \end{matrix}\right\} \text{Renglon} } \]

O bien, una matriz de caracteres:

\[ \overset{\downarrow \;Columna \; \downarrow \qquad \qquad \quad \; \;}{\begin{pmatrix} \alpha_1 & \alpha_2 & \alpha_3 & \alpha_4 & \alpha_5\\ \alpha_6 & \alpha_7 & \alpha_8 & \alpha_9 & \alpha_{10} \end{pmatrix} \left.\begin{matrix} \leftarrow \\\leftarrow \end{matrix}\right\} \text{Renglon} } \]

Como mencionamos al principio, una matriz es en esencia un vector de varias dimensiones (dos, largo y ancho, o bien, renglones y columnas). Los vectores en su forma matricial son sumamente útiles en R, ya que en ésto se basan las bases de datos que solemos utilizar, aunque también existen los arrays, que son objetos vectoriales de más dimensiones, pero éstos no son tan comunes ni tan utilizados, por lo que no los tocaremos por ahora.

Para crear una matriz en R simplemente tenemos que usar la función matrix(), la cual nos devolverá una matriz de una columna, por ejemplo:

matrix(1:6)
##      [,1]
## [1,]    1
## [2,]    2
## [3,]    3
## [4,]    4
## [5,]    5
## [6,]    6

Pero ¿y si quisieramos tener una matriz con dos columnas? Simplemente tenemos que especificarlo en la función con el comando ncol, tal que:

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

También podemos modificar el número de renglones, por ejemplo:

matrix(1:6, nrow = 2)
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6

O combinar ambas opciones:

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

En éste último ejemplo podemos observar que como le dijimos a R que nuestra matriz únicamente podía contener datos del 1 al 6 y creamos una matriz con 3 renglones y 3 columnas, la cual tiene 9 espacios en total, entonces el programa repite los valores.

Otra cosa que podemos hacer es crear una serie de vectores y unirlos en una matriz, ya sea como renglones o como columnas, de la siguiente manera:

# Creamos los vectores

vectormat1 <- c(1:5)
vectormat2 <- c(24:29)
vectormat3 <- c(39:43)

# Creamos la matriz con columnas

matrizcol <- rbind(vectormat1, vectormat2, vectormat3)
matrizcol
##            [,1] [,2] [,3] [,4] [,5] [,6]
## vectormat1    1    2    3    4    5    1
## vectormat2   24   25   26   27   28   29
## vectormat3   39   40   41   42   43   39
# Creamos la matriz con renglones
matrizren <- cbind(vectormat1, vectormat2, vectormat3)
matrizren
##      vectormat1 vectormat2 vectormat3
## [1,]          1         24         39
## [2,]          2         25         40
## [3,]          3         26         41
## [4,]          4         27         42
## [5,]          5         28         43
## [6,]          1         29         39

Al igual que con los vectores, podemos aplicar operaciones aritméticas a las matrices, como por ejemplo:

# Creamos una matriz nueva

Matrizej <- matrix(1:12, nrow = 3)
Matrizej
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
# Suma
Matrizej + 10
##      [,1] [,2] [,3] [,4]
## [1,]   11   14   17   20
## [2,]   12   15   18   21
## [3,]   13   16   19   22
# Resta

Matrizej - 10
##      [,1] [,2] [,3] [,4]
## [1,]   -9   -6   -3    0
## [2,]   -8   -5   -2    1
## [3,]   -7   -4   -1    2
# Multiplicación

Matrizej * 4
##      [,1] [,2] [,3] [,4]
## [1,]    4   16   28   40
## [2,]    8   20   32   44
## [3,]   12   24   36   48
# Matriz inversa

Matrizej^-1
##           [,1]      [,2]      [,3]       [,4]
## [1,] 1.0000000 0.2500000 0.1428571 0.10000000
## [2,] 0.5000000 0.2000000 0.1250000 0.09090909
## [3,] 0.3333333 0.1666667 0.1111111 0.08333333
# Matriz transpuesta

t(Matrizej)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9
## [4,]   10   11   12

También podemos crear matrices de identidad de la siguiente manera:

Matid <- diag(5)
Matid
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    0    0    0    0
## [2,]    0    1    0    0    0
## [3,]    0    0    1    0    0
## [4,]    0    0    0    1    0
## [5,]    0    0    0    0    1

Vectores atómicos

Esta clase de vectores son un subconjunto de los vectores en general que no se puede simpliflicar más, es importante tener esto presente ya que existen funciones que no funcionan con vectores de éste estilo, por ejemplo: el operador $ no se puede usar con éste tipo de vectores.

Data Frames

Los Data Frames son probablemente las matrices que más vamos a utilizar cuando trabajemos con R, estadística o análisis de bases de datos, ya que éstas estructuras que aceptan diferentes tipos de caracteres, ya sean numéricos, nombres, booleanos, etc. Existen paquetes que ya tienen precargados algunos Data Frames para usarlos de ejemplos pero en este caso veremos cómo crear uno desde cero. Debemos partir de la creación de vectores individuales (con cantidades similares de datos), por ejemplo:

# Creamos vectores de diferentes clases

Vec1 <- rep(c(1,4,1,5,2), c(21,40,20,29,17))

Vec2 <- rep(c("Caso 1", "Caso 2", "Caso 3"), c(50,45,32))

Vec3 <- rep(c(TRUE, FALSE), c(80, 47))

Fecha <- seq(as.Date("2020-01-01"), as.Date("2020-05-06"), by = "day")

Ahora, utilizando la función data.frame() creamos nuestra base de datos de la siguiente manera:

# Objeto de clase Data Frame

Base_ejemplo <- data.frame(Fecha, Vec1, Vec2, Vec3)

# Veamos las primeras observaciones de nuestra base de datos

head(Base_ejemplo)
##        Fecha Vec1   Vec2 Vec3
## 1 2020-01-01    1 Caso 1 TRUE
## 2 2020-01-02    1 Caso 1 TRUE
## 3 2020-01-03    1 Caso 1 TRUE
## 4 2020-01-04    1 Caso 1 TRUE
## 5 2020-01-05    1 Caso 1 TRUE
## 6 2020-01-06    1 Caso 1 TRUE

Otra forma de obtener una serie de valores es mediante números aleatorios. La forma de hacerlo es la siguiente:

# Números aleatorios con repetición

aleat <- sample(1:127, replace = TRUE)

# Agregamos la variable al data frame

Base_ejemplo1 <- data.frame(Fecha, Vec1, Vec2, Vec3, aleat)
head(Base_ejemplo1)
##        Fecha Vec1   Vec2 Vec3 aleat
## 1 2020-01-01    1 Caso 1 TRUE    75
## 2 2020-01-02    1 Caso 1 TRUE    34
## 3 2020-01-03    1 Caso 1 TRUE   112
## 4 2020-01-04    1 Caso 1 TRUE    39
## 5 2020-01-05    1 Caso 1 TRUE   111
## 6 2020-01-06    1 Caso 1 TRUE   115

Veamos un poco de las posibilidades que tenemos con los Data Frames, sobre todo aquellos que tienen fechas, por lo que para ello vamos a crear un par de gráficos sencillos, usando los que vienen por default en R y con el paquete Ggplot2. Lo haremos de la siguiente manera:

plot(Fecha, aleat, main = "Gráfico de números aleatorios")

Como vemos es un gráfico bastante sencillo, pero podemos hacer uno mucho más especializado de la siguiente manera:

library(ggplot2)

ggplot(Base_ejemplo1, aes( x = Fecha, y = aleat) ) + # Graficamos los ejes
  geom_point(size = 1.0, color = "darkblue") + # Damos color a los puntos
  theme_bw() + # Cambiamos el fondo
  theme(legend.position = "none") + # Posición del título
  theme(legend.title = element_blank()) + 
  guides(col = guide_legend(nrow = 1, byrow = TRUE)) +  
  xlab("Fecha") + 
  ylab("Número aleatorio")+ 
  theme(plot.title = element_text(size = 11, face = "bold", hjust = 0)) + 
  theme(plot.subtitle = element_text(size = 10, hjust = 0)) + 
  theme(plot.caption = element_text(size = 10, hjust = 0)) +
  theme(plot.margin = unit(c(1,1,1,1), "cm")) + # Márgenes
  labs(
    title = "Gráfico de números aleatorios.",
    subtitle = "Ejemplo sencillo.",
    caption = "Fuente: Elaboración propia. \nNotas: Este ejemplo puede serte útil."
  ) # Títulos, subtitulos y notas al pie

Aquí podemos abrir un paréntesis para preguntarnos ¿cuál es el punto de hacer éstos gráficos con los datos creados? El punto aquí es ver la potencia que tienen los Data Frames en cuanto al análisis de datos, tanto visual como estadístico, ya que de igual manera podemos obtener estadísticos importantes de nuestras bases de datos como la media, mediana, moda, cuartiles, etc. Ahora, vamos a crear un Data Frame a partir de una matriz simple, ésto lo haremos de la siguiente manera:

# Matriz

Matriz_df <- matrix(1:12, nrow = 4)

# Data Frame

DF_mat <- as.data.frame(Matriz_df)
DF_mat
##   V1 V2 V3
## 1  1  5  9
## 2  2  6 10
## 3  3  7 11
## 4  4  8 12

¿Por qué hicimos esto? Aquí hay que denotar que al crear un Data Frame a partir de una matriz, la función lo que hace es devolvernos la misma matriz, sin embargo, en lugar de tener columnas sin título, ahora nos devuelve columnas con títulos por default como V1, V2, V3, por lo que podemos trabajar individualmente con cada una de ellas si así lo requerimos, siendo ésta otra de las ventajas de tener Data Frames en R.

Extranyendo datos específicos de un Data Frame

Cuando trabajamos con bases de datos largas a veces vamos a querer saber, por ejemplo, que valor tenemos en el renglón número \(n\), y hacerlo de manera manual podría ser bastante molesto, por lo que para hacerlo de manera automática en R simplemente tendríamos que hacer lo siguiente, usando la base Base_ejemplo1 creada anteriormente:

# Extrayendo valores de Base_ejemplo1 

Base_ejemplo1[5,]
##        Fecha Vec1   Vec2 Vec3 aleat
## 5 2020-01-05    1 Caso 1 TRUE   111

Es importante no olvidar escribir la coma al final del número, ya que si solo escribimos [5] la función solo nos devolvería toda la columna 5. Si quisieramos saber cuales son los valores de, por ejemplo, 3 renglones concretos, ésto lo podemos hacer de la siguiente manera:

Base_ejemplo1[c(5,8,53),]
##         Fecha Vec1   Vec2 Vec3 aleat
## 5  2020-01-05    1 Caso 1 TRUE   111
## 8  2020-01-08    1 Caso 1 TRUE    82
## 53 2020-02-22    4 Caso 2 TRUE   117

Al igual que en el caso anterior, si no escribieramos la coma nos devolvería columnas enteras.

Ahora, supongamos que queremos extraer los datos 5, 80 y 95 de la columna Fecha únicamente, ésto lo podemos hacer de la siguiente manera:

Base_ejemplo1[c(5,80,95), 1]
## [1] "2020-01-05" "2020-03-20" "2020-04-04"

De igual forma, si quisieramos esos mismos datos pero para otra columna, solo cambiamos el número después de la coma de la siguiente manera:

Base_ejemplo1[c(5,80,95), 3]
## [1] Caso 1 Caso 2 Caso 2
## Levels: Caso 1 Caso 2 Caso 3
Base_ejemplo1[c(5,80,95), 4]
## [1]  TRUE  TRUE FALSE

Importando y depurando bases desde un archivo externo

En ésta sección veremos un par de funciones útiles respecto a bases de datos externas. Primero que nada, ¿cómmo las importamos desde archivos externos? Ésto depende del archivo que queramos leer, por ejemplo, si tenemos un archivo de texto utilizaremos la función read.table(), si necesitamos leer un archivo csv entonces utilizaremos la función read.csv() y si queremos leer un archivo de excel entonces podremos usar las funciones read_excel(), read_xls() o read_xlsx() del paquete readxl. Vamos a utilizar una base de datos de Banxico sobre tasas de interés para mostrar un ejemplo de ello a continuación:

# Cargamos el paquete
library(readxl)

# Leemos la base
tasas_inter <- read_excel("/Users/jorge/Downloads/tasasinter.xlsx")
head(tasas_inter)
## # A tibble: 6 x 8
##   Fecha               `TIIE a 182 día… `TIIE a un día` `Tasa de fondeo…
##   <dttm>              <lgl>                      <dbl>            <dbl>
## 1 2008-01-02 00:00:00 NA                          7.53             7.51
## 2 2008-01-03 00:00:00 NA                          7.53             7.51
## 3 2008-01-04 00:00:00 NA                          7.53             7.51
## 4 2008-01-07 00:00:00 NA                          7.52             7.51
## 5 2008-01-08 00:00:00 NA                          7.51             7.5 
## 6 2008-01-09 00:00:00 NA                          7.51             7.5 
## # … with 4 more variables: `Tasa de fondeo gubernamental` <dbl>, `TIIE a 28
## #   días` <dbl>, `TIIE a 91 días` <dbl>, `Tasa objetivo` <dbl>

Escogí esta base a proposito ya que está repleta de valores nulos o NA. Claramente si quisieramos trabajar con ella éstos valores no nos sirven de nada, entonces ¿qué podemos hacer en éste caso? Existen varios métodos para depurar la base y eliminar éstos valores, vamos desde el más complicado al más sencillo:

# Forma complicada

delete.na <- function(df, n=0) {
 df[rowSums(is.na(df)) <= n,]
}
delete.na(tasas_inter)
## # A tibble: 521 x 8
##    Fecha               `TIIE a 182 día… `TIIE a un día` `Tasa de fondeo…
##    <dttm>              <lgl>                      <dbl>            <dbl>
##  1 2011-04-07 00:00:00 TRUE                        4.51             4.52
##  2 2011-04-14 00:00:00 TRUE                        4.51             4.52
##  3 2011-04-20 00:00:00 TRUE                        4.52             4.53
##  4 2011-04-28 00:00:00 TRUE                        4.5              4.51
##  5 2011-05-05 00:00:00 TRUE                        4.5              4.51
##  6 2011-05-12 00:00:00 TRUE                        4.48             4.5 
##  7 2011-05-19 00:00:00 TRUE                        4.49             4.51
##  8 2011-05-26 00:00:00 TRUE                        4.34             4.38
##  9 2011-06-02 00:00:00 TRUE                        4.45             4.47
## 10 2011-06-09 00:00:00 TRUE                        4.48             4.5 
## # … with 511 more rows, and 4 more variables: `Tasa de fondeo
## #   gubernamental` <dbl>, `TIIE a 28 días` <dbl>, `TIIE a 91 días` <dbl>, `Tasa
## #   objetivo` <dbl>
# Forma sencilla

tasas_inter <- na.omit(tasas_inter)
head(tasas_inter)
## # A tibble: 6 x 8
##   Fecha               `TIIE a 182 día… `TIIE a un día` `Tasa de fondeo…
##   <dttm>              <lgl>                      <dbl>            <dbl>
## 1 2011-04-07 00:00:00 TRUE                        4.51             4.52
## 2 2011-04-14 00:00:00 TRUE                        4.51             4.52
## 3 2011-04-20 00:00:00 TRUE                        4.52             4.53
## 4 2011-04-28 00:00:00 TRUE                        4.5              4.51
## 5 2011-05-05 00:00:00 TRUE                        4.5              4.51
## 6 2011-05-12 00:00:00 TRUE                        4.48             4.5 
## # … with 4 more variables: `Tasa de fondeo gubernamental` <dbl>, `TIIE a 28
## #   días` <dbl>, `TIIE a 91 días` <dbl>, `Tasa objetivo` <dbl>

Modificando una base de datos con Dplyr

Uno de los paquetes que más vamos a utilizar para trabajar con bases de datos, además de todos los que ya hemos visto, es dplyr de Tidyverse, ya que nos permite utilizar funciones sumamente útiles, como filtros para las bases de datos, formas de reordenarlas, crear variables nuevas, etc, siendo que nos simplifica bastante el trabajo, ya que añgunas de éstas cosas se pueden hacer sin ese paquete, pero requeriría de más comandos y más tiempo perdido. Trabajemos ésta vez con la base de datos precargada iris.

# Cargamos el paquete
library(dplyr)

# Leemos la base de datos (no es necesario cargarla)
attach(iris)
head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa

Función filter()

Ahora, supongamos que queremos filtrar los datos a, por ejemplo, únicamente las filas que tienen la variable versicolor, para ello podemos hacer lo siguiente:

head(filter(iris, Species == "versicolor"))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
## 1          7.0         3.2          4.7         1.4 versicolor
## 2          6.4         3.2          4.5         1.5 versicolor
## 3          6.9         3.1          4.9         1.5 versicolor
## 4          5.5         2.3          4.0         1.3 versicolor
## 5          6.5         2.8          4.6         1.5 versicolor
## 6          5.7         2.8          4.5         1.3 versicolor

¿Qué tal si queremos filtrar la base a, por ejemplo, únicamente valores de Sepal.Length mayores a 5? Para ello simplemente tendríamos que hacer lo siguiente:

head(filter(iris, Sepal.Length > 5))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          5.4         3.9          1.7         0.4  setosa
## 3          5.4         3.7          1.5         0.2  setosa
## 4          5.8         4.0          1.2         0.2  setosa
## 5          5.7         4.4          1.5         0.4  setosa
## 6          5.4         3.9          1.3         0.4  setosa

¿Y para valores menores a 5?

head(filter(iris, Sepal.Length < 5))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          4.9         3.0          1.4         0.2  setosa
## 2          4.7         3.2          1.3         0.2  setosa
## 3          4.6         3.1          1.5         0.2  setosa
## 4          4.6         3.4          1.4         0.3  setosa
## 5          4.4         2.9          1.4         0.2  setosa
## 6          4.9         3.1          1.5         0.1  setosa

De igual forma podemos utilizar varios filtros a la vez, por ejemplo:

head(filter(iris, Sepal.Length > 5, Species == c("versicolor", "virginica"), Petal.Width > 2))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
## 1          7.6         3.0          6.6         2.1 virginica
## 2          7.2         3.6          6.1         2.5 virginica
## 3          6.4         3.2          5.3         2.3 virginica
## 4          7.7         3.8          6.7         2.2 virginica
## 5          7.7         3.0          6.1         2.3 virginica
## 6          6.9         3.1          5.4         2.1 virginica

Como vemos, es posible decirle a R que queremos que nos devuelva una base de datos que incluya valores de Sepal.Length mayores a 5, únicamente las especies versicolor y virginica, además de valores de Petal.Width mayores a 2. En este caso estamos haciendo uso de la teoría de conjuntos para ello, por lo que debemos tener en cuenta que si no hubiera ninguna fila con valores de Sepal.Length mayores a 5 y valores de Petal.Width mayores a 2 a la vez entonces no nos devolvería nada. De igual forma podemos usar el argumento <= para valores menores o iguales a un cierto valor o >= para valores mayores o iguales. Visto desde un punto de vista matemático, estaríamos diciendo que la función </> es un intervalo cerrado, mientras que la función <=/>= es un intervalo abierto.

Otra de las ventajas de la función filter() es que al considerar los NA como valores menores a cualquier otro (independientemente de que sean negativos) entonces al aplicar la función, todos éstos valores nulos van a desaparecer.

Ahora, ¿y si quisieramos encontrar valores entre un cierto intervalo para, por ejemplo, Petal.Width con valores entre 6 y 7? Podemos utilizar la función between() de la siguiente manera:

head(filter(iris, between(Sepal.Length, 6, 7 )))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
## 1          7.0         3.2          4.7         1.4 versicolor
## 2          6.4         3.2          4.5         1.5 versicolor
## 3          6.9         3.1          4.9         1.5 versicolor
## 4          6.5         2.8          4.6         1.5 versicolor
## 5          6.3         3.3          4.7         1.6 versicolor
## 6          6.6         2.9          4.6         1.3 versicolor

Ahora, ¿qué pasa si queremos filtrar fechas? Esto es un poco diferente, ya que cuando R detecta que tenemos fechas en una base de datos las lee al revés, por lo que tenemos que corregir el formato de ellas, por lo que tenemos que corregir el formato de ellas. Vamos a retomar la base de datos que tenemos de tasas de interés, ya que ésta tiene el formato de fechas al que me refiero. Para corregir el formato lo haré de la siguiente manera:

tasas_inter$Fecha <-as.Date(tasas_inter$Fecha,"%m/%d/%Y")

Y ahora que ya tenemos filtrada la base de datos entonces podemos filtrarla por fecha, tal que:

#Filtramos
tasas_inter <- filter(tasas_inter, Fecha == "2011-04-28")

# Visualizamos los datos
head(tasas_inter)
## # A tibble: 1 x 8
##   Fecha      `TIIE a 182 día… `TIIE a un día` `Tasa de fondeo… `Tasa de fondeo…
##   <date>     <lgl>                      <dbl>            <dbl>            <dbl>
## 1 2011-04-28 TRUE                         4.5             4.51             4.48
## # … with 3 more variables: `TIIE a 28 días` <dbl>, `TIIE a 91 días` <dbl>,
## #   `Tasa objetivo` <dbl>

Función arrange()

Ahora, imaginemos que queremos reordenar los valores de la variable Petal.Length de nuestra base de datos de menor a mayor. Esto lo podemos hacer de la siguiente manera:

# Observando los primeros 6 valores

head(arrange(iris, Petal.Length))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          4.6         3.6          1.0         0.2  setosa
## 2          4.3         3.0          1.1         0.1  setosa
## 3          5.8         4.0          1.2         0.2  setosa
## 4          5.0         3.2          1.2         0.2  setosa
## 5          4.7         3.2          1.3         0.2  setosa
## 6          5.4         3.9          1.3         0.4  setosa
# Observando los últimos 6 valores

tail(arrange(iris, Petal.Length))
##     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
## 145          7.3         2.9          6.3         1.8 virginica
## 146          7.9         3.8          6.4         2.0 virginica
## 147          7.6         3.0          6.6         2.1 virginica
## 148          7.7         3.8          6.7         2.2 virginica
## 149          7.7         2.8          6.7         2.0 virginica
## 150          7.7         2.6          6.9         2.3 virginica

¿Y si quisieramos reordenar Species por órden alfabético?

head(arrange(iris, Species))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa

De igual forma podemos reordenar de mayor a menor de la siguiente manera:

head(arrange(iris, desc(Petal.Length)))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
## 1          7.7         2.6          6.9         2.3 virginica
## 2          7.7         3.8          6.7         2.2 virginica
## 3          7.7         2.8          6.7         2.0 virginica
## 4          7.6         3.0          6.6         2.1 virginica
## 5          7.9         3.8          6.4         2.0 virginica
## 6          7.3         2.9          6.3         1.8 virginica

O invertir el órden alfabético, tal que:

head(arrange(iris, desc(Species)))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
## 1          6.3         3.3          6.0         2.5 virginica
## 2          5.8         2.7          5.1         1.9 virginica
## 3          7.1         3.0          5.9         2.1 virginica
## 4          6.3         2.9          5.6         1.8 virginica
## 5          6.5         3.0          5.8         2.2 virginica
## 6          7.6         3.0          6.6         2.1 virginica

Lógicamente, con ésta función los valores nulos NA quedarán al final (o al principio, si usamos la función desc()).

¿Y si quisiéramos saber cual es el valor mayor de Sepal.Width? ¿O el valor menor? Podemos hacerlo de la siguiente manera:

# Valor mayor
arrange(iris, desc(Sepal.Width))[1,]
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.7         4.4          1.5         0.4  setosa
# Valor menor 
arrange(iris, Sepal.Width)[1,]
##   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
## 1            5           2          3.5           1 versicolor

Función select()

Ésta función nos permite filtrar valores seleccionando las columnas que nos interesan. Supongamos que queremos únicamente loss primeros 5 renglones de las columnas Sepal.Width y Sepal.Width. Ésto lo podemos hacer de la siguiente manera:

select(iris[1:5,], Sepal.Length, Sepal.Width)
##   Sepal.Length Sepal.Width
## 1          5.1         3.5
## 2          4.9         3.0
## 3          4.7         3.2
## 4          4.6         3.1
## 5          5.0         3.6

Ahora, supongamos que queremos que nos dé los primeros 5 renglores pero ordenados de menor a mayor para Sepal.Length. En este caso lo podemos hacer de la siguiente manera:

Baseord <- arrange(iris, Sepal.Length)

select(Baseord[1:5,], Sepal.Length, Sepal.Width)
##   Sepal.Length Sepal.Width
## 1          4.3         3.0
## 2          4.4         2.9
## 3          4.4         3.0
## 4          4.4         3.2
## 5          4.5         2.3

Y si quisieramos hacer lo mismo pero solo con valores de Sepal.Length mayores a 5, entonces podemos hacer lo siguiente:

basefilt <- filter(iris, Sepal.Length > 5)

select(basefilt[1:5,], Sepal.Length, Sepal.Width)
##   Sepal.Length Sepal.Width
## 1          5.1         3.5
## 2          5.4         3.9
## 3          5.4         3.7
## 4          5.8         4.0
## 5          5.7         4.4

Ahora, vamos a hacer algo aún más específico. Vamos a suponer que queremos filtrar nuestra base para las observaciones 20 a 30 ordenado de menor a mayor, pero además de eso queremos que solo nos arroje aquellas columnas que terminen su nombre con las letras dth. Ésto lo podemos hacer de la siguiente manera:

basefilt1 <- arrange(iris, Sepal.Width)

select(basefilt1[20:30,], Sepal.Width,Species, ends_with("dth"))
##    Sepal.Width    Species Petal.Width
## 20         2.6 versicolor         1.0
## 21         2.6 versicolor         1.2
## 22         2.6 versicolor         1.2
## 23         2.6  virginica         2.3
## 24         2.6  virginica         1.4
## 25         2.7 versicolor         1.4
## 26         2.7 versicolor         1.0
## 27         2.7 versicolor         1.2
## 28         2.7 versicolor         1.6
## 29         2.7 versicolor         1.3
## 30         2.7  virginica         1.9

Renombrando columnas con rename()

Ésta función es de las mas sencillas de utilizar, ya que simplemente nos ayudará a renombrar a nuestro gusto las columnas, por ejemplo, supongamos que queremos que Sepal.Width ahora se llame columna ejemplo, haremos lo siguiente:

head(rename(iris, "columna ejemplo" = Sepal.Width ))
##   Sepal.Length columna ejemplo Petal.Length Petal.Width Species
## 1          5.1             3.5          1.4         0.2  setosa
## 2          4.9             3.0          1.4         0.2  setosa
## 3          4.7             3.2          1.3         0.2  setosa
## 4          4.6             3.1          1.5         0.2  setosa
## 5          5.0             3.6          1.4         0.2  setosa
## 6          5.4             3.9          1.7         0.4  setosa

Función mutate()

¿Y si quisieramos crear columnas nuevas con cálculos a partir de las que ya tenemos? Por ejemplo, multiplicar los valores de Sepal.Length con los de Petal.Length o restarle 5 a Petal.Length. Ésto lo podemos hacer de la siguiente forma:

head(mutate(iris, 
       "variable nueva" = Sepal.Length * Petal.Length,
       "variable nueva 2" = Petal.Length - 5))
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species variable nueva
## 1          5.1         3.5          1.4         0.2  setosa           7.14
## 2          4.9         3.0          1.4         0.2  setosa           6.86
## 3          4.7         3.2          1.3         0.2  setosa           6.11
## 4          4.6         3.1          1.5         0.2  setosa           6.90
## 5          5.0         3.6          1.4         0.2  setosa           7.00
## 6          5.4         3.9          1.7         0.4  setosa           9.18
##   variable nueva 2
## 1             -3.6
## 2             -3.6
## 3             -3.7
## 4             -3.5
## 5             -3.6
## 6             -3.3

Y si quisieramos hacer los cálculos pero eliminar las variables originales, entonces utilizaríamos la función transmute(), por ejemplo:

head(transmute(iris, 
       "variable nueva" = Sepal.Length * Petal.Length,
       "variable nueva 2" = Petal.Length - 5))
##   variable nueva variable nueva 2
## 1           7.14             -3.6
## 2           6.86             -3.6
## 3           6.11             -3.7
## 4           6.90             -3.5
## 5           7.00             -3.6
## 6           9.18             -3.3

Referencias

  1. Torgo, L. (2016). Data mining with R: learning with case studies. CRC press.
  2. Wickham, H., & Grolemund, G. (2016). R for data science: import, tidy, transform, visualize, and model data. " O’Reilly Media, Inc.".
  3. Mendoza Vega, J. (2017). R para principantes. Ciudad de México: UNAM.
  4. Kolaczyk, E. D., & Csárdi, G. (2014). Statistical analysis of network data with R (Vol. 65). New York: Springer.
  5. Wickham, H. (2017). The tidyverse. R package ver, 1(1), 1.
  6. Wickham, H., & Wickham, M. H. (2017). Package tidyverse. Easily Install and Load the ‘Tidyverse.
  7. Wickham, H., & Francois, R. (2014, June). Dplyr. In useR! Conference.
R-Conomics
Todos los derechos reservados