Limpieza de datos con R

Camila Salazar

¿Qué vamos a aprender?

En este tutorial vamos a aprender a usar algunos paquetes para limpiar datos y estructurar información en R. Anteriormente vimos algunas características que deben tener los datos limpios:

  1. Cada columna es una variable: una variable contiene todos los valores que miden el atributo (altura, peso, temperatura, etc)
  2. Cada fila es una observación

¿Qué paquetes vamos a necesitar?

library(dplyr)
library(tidyr) 
library(readxl)

Importar los datos

Los archivos para este tutorial los pueden encontrar en este enlace: Archivos

Antes de comenzar, hay que cambiar el directorio de trabajo y seleccionar el folder en donde tenemos nuestros archivos. Esto se hace con el comando setwd().

Ahora podemos importar los archivos de varias formas. Podemos hacerlo desde el menú de arriba, usando: File -> Import Dataset y seleccionando el tipo de archivo que queremos importar.

También podemos hacerlo escribiendo el código. Es siempre recomendable asignar el archivo que importamos a un objeto con el símbolo <-. Inicialmente vamos a importar unos archivos .xlsx, por lo que usamos el paquete readxl, que ya instalamos.

Los archivos que vamos a usar inicialmente son:

#Recuerden cambiar el directorio de trabajo
setwd("C:/Users/Camila Salazar/Documents/R/limpieza")
morosidad16 <- read_xlsx("morosidad16.xlsx")
morosidad17<- read_xlsx("morosidad17.xlsx")

Explorar los datos y unir las bases

Antes de comenzar a limpiar o analizar los datos tenemos que explorar los datos. Para estos primeros ejercicios vamos a usar las bases de datos de morosidad con la CCSS.

Ambas bases de datos tienen las siguientes variables:

  • id: cédula del deudor ya sea cédula física o jurídica.
  • nombre: Nombre de la persona física o jurídica.
  • deuda16 y deuda17 : monto de la deuda en colones.
  • situación: situación en la que se encuentra la deuda
  • lugar.pago: sucursal donde se tiene que cancelar la deuda
  • Estado: Estado de la deuda

Cómo primer paso vamos a unir ambas bases de datos.

Unir bases de datos

Para unir bases de datos necesitamos una o más variables en común entre las dos bases de datos. Existen varias funciones para unir bases de datos. Una de ellas es merge, que sirve para unir columnas de dos bases de datos diferentes. Para unir bases es clave hacerse la pregunta: ¿Queremos conservar todas las variables o solo las que hacen match?. De acuerdo a la respuesta, así va a depender la fórmula que usemos.

La sintaxis de merge() es simple:
merge(base1, base2, by.x="nombre variable base 1", by.y="nombre variable base 2")

En el caso en el que la variable se llame igual en las dos bases: merge(base1, base2, by="nombre variable")

En esos ejemplos, el comando une solamente los casos en común entre las dos bases.

Si queremos que se unan todos los casos, usamos la opción all=TRUE: merge(base1, base2, by="nombre variable", all=TRUE)

Si queremos unir por más de una variable: Si las variables se llaman igual en ambas bases: merge(base1, base2, by=c("variable1", "variable2")) Si las variables se llaman diferente en ambas bases: merge(base1, base2, by.x=c("variable1", "variable2"), by.y=c("variable1", "variable2"))

Pueden ver este documento donde se muestra cómo funciona esta función con detalle. La función merge

Para este ejercicio queremos unir las dos bases de morosidad en una sola, dejando todas las observaciones de ambas bases, entonces usamos el comando:

morosidad<-merge(morosidad17, morosidad16, by= "id", all=TRUE)

Ahora podemos convertirla base a una tibble para facilitar la lectura

morosidad <-tbl_df(morosidad)

Otra forma: Usando Dplyr

También podemos unir bases con funciones del programa Dplyr. Las funciones se ilustran en la imagen:

La que utilicemos va a depender de qué es lo queramos unir. En nuestro ejemplo, queremos unir todas las observaciones entonces vamos a utilizar la función full_join.

morosidad<-full_join(morosidad17, morosidad16, by= "id")

¿Qué pasa si las variables se llama diferente? La sintaxis de by sería: by = c("variable1" = "variable2").

¿Qué pasa si queremos unir por más de una variable? La sintaxis de by sería: by = c("variable1", "variable2").

RECOMENDACIÓN: Para que los comandos sean más sencillos, traten de que las variables se llamen igual en las diferentes bases de datos. Esto pueden hacerlo en Excel antes de importar la base, o en R con el comando rename(): rename(base, nombre_nuevo = nombre anterior)

Explorar los datos

Ahora que tenemos una nueva base de datos, podemos explorar sus contenidos. Usemos las siguientes funciones:

Si queremos imprimir la base de datos, nada más ponemos el nombre del objeto:

morosidad
## # A tibble: 78,703 x 10
##         id nombre.x     deuda17 situacion.x lugar.pago.x Estado nombre.y  
##      <dbl> <chr>          <dbl> <chr>       <chr>        <chr>  <chr>     
##  1  3.10e9 AUTOTRANSP~  1172309 COBRO JUDI~ SUCURSAL BA~ Inact~ AUTOTRANS~
##  2  1.69e7 COLEGIAL M~  1006884 COBRO ADMI~ SUCURSAL OF~ Inact~ COLEGIAL ~
##  3  1.61e7 CRUZ ALVAR~   148193 COBRO ADMI~ SUCURSAL OF~ Inact~ CRUZ ALVA~
##  4  3.30e7 JUAN CARLO~  1603657 COBRO ADMI~ SUCURSAL LI~ Inact~ JUAN CARL~
##  5  1.76e9 NOINDICAOT~   812751 COBRO JUDI~ SUCURSAL NI~ Inact~ <NA>      
##  6  1.63e8 OLIVIER CO~   121205 COBRO ADMI~ SUCURSAL QU~ Inact~ OLIVIER C~
##  7  7.11e7 VERONICA W~    40642 COBRO ADMI~ SUCURSAL SA~ Inact~ VERONICA ~
##  8  3.10e9 &COM SOCIE~    20000 COBRO ADMI~ SUCURSAL SA~ Activo &COM SOCI~
##  9  3.10e9 3 101 4243~ 18354949 COBRO JUDI~ SUCURSAL OF~ Activo 3 101 424~
## 10  3.10e9 3-101-3185~   459839 COBRO JUDI~ SUCURSAL OF~ Inact~ 3-101-318~
## # ... with 78,693 more rows, and 3 more variables: deuda16 <dbl>,
## #   situacion.y <chr>, lugar.pago.y <chr>

dim() Esta función nos permite ver la dimensión de la base de datos, en este caso tenemos 10 variables y 78.703 observaciones

dim(morosidad)
## [1] 78703    10

head() Nos permite ver las primeras filas de la base de datos. Incluso podemos seleccionar la cantidad de filas que queremos ver por ejemplo head(base, n=20), lo cual nos muestra las primeras 20 filas. También podemos ver que nos muestra el tipo de variable.

head(morosidad)
## # A tibble: 6 x 10
##       id nombre.x deuda17 situacion.x lugar.pago.x Estado nombre.y deuda16
##    <dbl> <chr>      <dbl> <chr>       <chr>        <chr>  <chr>      <dbl>
## 1 3.10e9 AUTOTRA~ 1172309 COBRO JUDI~ SUCURSAL BA~ Inact~ AUTOTRA~ 2207161
## 2 1.69e7 COLEGIA~ 1006884 COBRO ADMI~ SUCURSAL OF~ Inact~ COLEGIA~  582400
## 3 1.61e7 CRUZ AL~  148193 COBRO ADMI~ SUCURSAL OF~ Inact~ CRUZ AL~  101928
## 4 3.30e7 JUAN CA~ 1603657 COBRO ADMI~ SUCURSAL LI~ Inact~ JUAN CA~ 1027254
## 5 1.76e9 NOINDIC~  812751 COBRO JUDI~ SUCURSAL NI~ Inact~ <NA>          NA
## 6 1.63e8 OLIVIER~  121205 COBRO ADMI~ SUCURSAL QU~ Inact~ OLIVIER~   89377
## # ... with 2 more variables: situacion.y <chr>, lugar.pago.y <chr>

tail() Nos permite ver las últimas filas. Tiene la misma sintaxis que head()

tail(morosidad)
## # A tibble: 6 x 10
##       id nombre.x deuda17 situacion.x lugar.pago.x Estado nombre.y deuda16
##    <dbl> <chr>      <dbl> <chr>       <chr>        <chr>  <chr>      <dbl>
## 1 3.10e9 <NA>          NA <NA>        <NA>         <NA>   SUPER M~   25130
## 2 8.01e8 <NA>          NA <NA>        <NA>         <NA>   CRUZ ME~  888571
## 3 2.05e8 <NA>          NA <NA>        <NA>         <NA>   CASTRO ~  768936
## 4 3.10e9 <NA>          NA <NA>        <NA>         <NA>   TRANSPO~  152840
## 5 2.07e8 <NA>          NA <NA>        <NA>         <NA>   CORRALE~   29234
## 6 2.04e8 <NA>          NA <NA>        <NA>         <NA>   VARGAS ~  503536
## # ... with 2 more variables: situacion.y <chr>, lugar.pago.y <chr>

glimpse() nos permite exploarar las variables. Nos dice, al lado de cada variable cuál es el tipo. Por ejemplo nos dice que nombre.x es caracter y que deuda17 es “double”, el cual es un formato numérico.

glimpse(morosidad)
## Observations: 78,703
## Variables: 10
## $ id           <dbl> 3101618215, 16919357, 16099052, 33000529, 1760103...
## $ nombre.x     <chr> "AUTOTRANSPORTES Y CONSTRUCTORA LOPES DE MATINA S...
## $ deuda17      <dbl> 1172309, 1006884, 148193, 1603657, 812751, 121205...
## $ situacion.x  <chr> "COBRO JUDICIAL", "COBRO ADMINISTRATIVO", "COBRO ...
## $ lugar.pago.x <chr> "SUCURSAL BATAAN", "SUCURSAL OFICINAS CENTRALES",...
## $ Estado       <chr> "Inactivo", "Inactivo", "Inactivo", "Inactivo", "...
## $ nombre.y     <chr> "AUTOTRANSPORTES Y CONSTRUCTORA LOPEZ DE MATINA S...
## $ deuda16      <dbl> 2207161, 582400, 101928, 1027254, NA, 89377, 2822...
## $ situacion.y  <chr> "COBRO JUDICIAL", "COBRO ADMINISTRATIVO", "COBRO ...
## $ lugar.pago.y <chr> "SUCURSAL BATAAN", "SUCURSAL OFICINAS CENTRALES",...

dplyr

Uno de los paquetes que más funciona para manipular datos de forma fácil es dplyr. Este paquete tiene, entre otras, cinco funciones para manipular datos: select() filter() arrange()``mutate() summarize().

Veámos cómo se usa

select()

Select nos permite seleccionar columnas. La sintaxis sería: select(dataframe, col1, col2) conde col1, col2, se refiere a los nombres de las columnas que queramos seleccionar.

Por ejemplo supongamos que queremos seleccionar únicamente las columnas de id y deuda:

select(morosidad, id, deuda17, deuda16)
## # A tibble: 78,703 x 3
##            id  deuda17  deuda16
##         <dbl>    <dbl>    <dbl>
##  1 3101618215  1172309  2207161
##  2   16919357  1006884   582400
##  3   16099052   148193   101928
##  4   33000529  1603657  1027254
##  5 1760103328   812751       NA
##  6  163009967   121205    89377
##  7   71130310    40642    28229
##  8 3101289026    20000    20000
##  9 3101424370 18354949 13939588
## 10 3101318586   459839   355367
## # ... with 78,693 more rows

También podemos seleccionar todas las columnas menos algunas, esto lo hacemos poniendo - antes del nombre de la columna que no queremos seleccionar. Por ejemplo, si queremos todas las columnas menos Estado:

select(morosidad, -Estado)
## # A tibble: 78,703 x 9
##         id nombre.x    deuda17 situacion.x lugar.pago.x nombre.y   deuda16
##      <dbl> <chr>         <dbl> <chr>       <chr>        <chr>        <dbl>
##  1  3.10e9 AUTOTRANS~  1172309 COBRO JUDI~ SUCURSAL BA~ AUTOTRANS~  2.21e6
##  2  1.69e7 COLEGIAL ~  1006884 COBRO ADMI~ SUCURSAL OF~ COLEGIAL ~  5.82e5
##  3  1.61e7 CRUZ ALVA~   148193 COBRO ADMI~ SUCURSAL OF~ CRUZ ALVA~  1.02e5
##  4  3.30e7 JUAN CARL~  1603657 COBRO ADMI~ SUCURSAL LI~ JUAN CARL~  1.03e6
##  5  1.76e9 NOINDICAO~   812751 COBRO JUDI~ SUCURSAL NI~ <NA>       NA     
##  6  1.63e8 OLIVIER C~   121205 COBRO ADMI~ SUCURSAL QU~ OLIVIER C~  8.94e4
##  7  7.11e7 VERONICA ~    40642 COBRO ADMI~ SUCURSAL SA~ VERONICA ~  2.82e4
##  8  3.10e9 &COM SOCI~    20000 COBRO ADMI~ SUCURSAL SA~ &COM SOCI~  2.00e4
##  9  3.10e9 3 101 424~ 18354949 COBRO JUDI~ SUCURSAL OF~ 3 101 424~  1.39e7
## 10  3.10e9 3-101-318~   459839 COBRO JUDI~ SUCURSAL OF~ 3-101-318~  3.55e5
## # ... with 78,693 more rows, and 2 more variables: situacion.y <chr>,
## #   lugar.pago.y <chr>

Si queremos seleccionar un rango de columnas por ejemplo de id a situacion usamos :.

select(morosidad, id:situacion.x)
## # A tibble: 78,703 x 4
##            id nombre.x                            deuda17 situacion.x     
##         <dbl> <chr>                                 <dbl> <chr>           
##  1 3101618215 AUTOTRANSPORTES Y CONSTRUCTORA LO~  1172309 COBRO JUDICIAL  
##  2   16919357 COLEGIAL MENDEZ ROGER               1006884 COBRO ADMINISTR~
##  3   16099052 CRUZ ALVARADO FAVIAN                 148193 COBRO ADMINISTR~
##  4   33000529 JUAN CARLOS SOLIS MOLINA            1603657 COBRO ADMINISTR~
##  5 1760103328 NOINDICAOTRO                         812751 COBRO JUDICIAL  
##  6  163009967 OLIVIER COLLIN                       121205 COBRO ADMINISTR~
##  7   71130310 VERONICA WINTER BOLAÑOS               40642 COBRO ADMINISTR~
##  8 3101289026 &COM SOCIEDAD ANONIMA                 20000 COBRO ADMINISTR~
##  9 3101424370 3 101 424370 SOCIEDAD ANONIMA      18354949 COBRO JUDICIAL  
## 10 3101318586 3-101-318586 SOCIEDAD ANONIMA        459839 COBRO JUDICIAL  
## # ... with 78,693 more rows

Si queremos guardar el resultado de esa función en un nuevo objeto, debemos asignarlo con <-. Por ejemplo para este ejericio nos interesa quedarnos únicamente con columnas que no estén repetidas. Si observamos la base, nos damos cuenta que la columna de nombre, lugar de pago y situación se repiten, entonces vamos a deseleccionar esas columnas y crear un nuevo objeto que se llame morosidad1.

morosidad1 <- select(morosidad, -nombre.y, -situacion.y, -lugar.pago.y)
morosidad1
## # A tibble: 78,703 x 7
##            id nombre.x     deuda17 situacion.x lugar.pago.x Estado deuda16
##         <dbl> <chr>          <dbl> <chr>       <chr>        <chr>    <dbl>
##  1 3101618215 AUTOTRANSP~  1172309 COBRO JUDI~ SUCURSAL BA~ Inact~  2.21e6
##  2   16919357 COLEGIAL M~  1006884 COBRO ADMI~ SUCURSAL OF~ Inact~  5.82e5
##  3   16099052 CRUZ ALVAR~   148193 COBRO ADMI~ SUCURSAL OF~ Inact~  1.02e5
##  4   33000529 JUAN CARLO~  1603657 COBRO ADMI~ SUCURSAL LI~ Inact~  1.03e6
##  5 1760103328 NOINDICAOT~   812751 COBRO JUDI~ SUCURSAL NI~ Inact~ NA     
##  6  163009967 OLIVIER CO~   121205 COBRO ADMI~ SUCURSAL QU~ Inact~  8.94e4
##  7   71130310 VERONICA W~    40642 COBRO ADMI~ SUCURSAL SA~ Inact~  2.82e4
##  8 3101289026 &COM SOCIE~    20000 COBRO ADMI~ SUCURSAL SA~ Activo  2.00e4
##  9 3101424370 3 101 4243~ 18354949 COBRO JUDI~ SUCURSAL OF~ Activo  1.39e7
## 10 3101318586 3-101-3185~   459839 COBRO JUDI~ SUCURSAL OF~ Inact~  3.55e5
## # ... with 78,693 more rows

filter()

La función filter nos permite filtrar filas.

La sintaxis es simple: filter(base, condicion). Donde condición es la condión lógica por la que queremos filtrar datos. Para ello usamos operadores lógicos:

  • >: mayor que
  • <: menor que
  • >=: mayor o igual que
  • <=: menor o igual que
  • ==: igual que (se ponen dos signos de igual)
  • !=: diferente
  • &: y
  • |: o
  • is.na(variable): filtra los valores en blanco de la variable seleccionada.
  • !is.na(variable): filtra los valores que no están en blanco de la variable.

Por ejemplo si queremos filtrar solamente las deudas superiores a un millón:

filter(morosidad1, deuda17>1000000)
## # A tibble: 30,438 x 7
##            id nombre.x     deuda17 situacion.x lugar.pago.x Estado deuda16
##         <dbl> <chr>          <dbl> <chr>       <chr>        <chr>    <dbl>
##  1 3101618215 AUTOTRANSP~  1172309 COBRO JUDI~ SUCURSAL BA~ Inact~  2.21e6
##  2   16919357 COLEGIAL M~  1006884 COBRO ADMI~ SUCURSAL OF~ Inact~  5.82e5
##  3   33000529 JUAN CARLO~  1603657 COBRO ADMI~ SUCURSAL LI~ Inact~  1.03e6
##  4 3101424370 3 101 4243~ 18354949 COBRO JUDI~ SUCURSAL OF~ Activo  1.39e7
##  5 3101451884 3-101-4518~  4043946 DIFICIL CO~ SUCURSAL OR~ Inact~  2.26e6
##  6 3101453271 3-101-4532~  2899815 COBRO JUDI~ SUCURSAL OF~ Inact~  1.87e6
##  7 3101456991 3-101-4569~ 13112166 DIFICIL CO~ SUCURSAL OF~ Inact~  9.45e6
##  8 3101460168 3-101-4601~  3425068 COBRO ADMI~ SUCURSAL OF~ Inact~  1.76e6
##  9 3101461558 3-101-4615~  3878289 COBRO JUDI~ SUCURSAL OF~ Inact~  2.75e6
## 10 3101464936 3-101-4649~ 26820522 DIFICIL CO~ SUCURSAL CA~ Inact~  1.72e7
## # ... with 30,428 more rows

O las deudas que crecieron entre 2016 y 2017:

filter(morosidad1, deuda17>deuda16)
## # A tibble: 56,539 x 7
##            id nombre.x    deuda17 situacion.x lugar.pago.x  Estado deuda16
##         <dbl> <chr>         <dbl> <chr>       <chr>         <chr>    <dbl>
##  1   16919357 COLEGIAL ~  1006884 COBRO ADMI~ SUCURSAL OFI~ Inact~  5.82e5
##  2   16099052 CRUZ ALVA~   148193 COBRO ADMI~ SUCURSAL OFI~ Inact~  1.02e5
##  3   33000529 JUAN CARL~  1603657 COBRO ADMI~ SUCURSAL LIM~ Inact~  1.03e6
##  4  163009967 OLIVIER C~   121205 COBRO ADMI~ SUCURSAL QUE~ Inact~  8.94e4
##  5   71130310 VERONICA ~    40642 COBRO ADMI~ SUCURSAL SAN~ Inact~  2.82e4
##  6 3101424370 3 101 424~ 18354949 COBRO JUDI~ SUCURSAL OFI~ Activo  1.39e7
##  7 3101318586 3-101-318~   459839 COBRO JUDI~ SUCURSAL OFI~ Inact~  3.55e5
##  8 3101451639 3-101-451~    72487 COBRO JUDI~ SUCURSAL ORO~ Inact~  4.82e4
##  9 3101451884 3-101-451~  4043946 DIFICIL CO~ SUCURSAL ORO~ Inact~  2.26e6
## 10 3101452285 3-101-452~   430970 DIFICIL CO~ SUCURSAL ALA~ Inact~  3.01e5
## # ... with 56,529 more rows

O solamente las deudas mayores a un millón y de díficil cobro:

filter(morosidad1, deuda17>1000000 & situacion.x=="DIFICIL COBRO")
## # A tibble: 9,482 x 7
##            id nombre.x    deuda17 situacion.x lugar.pago.x  Estado deuda16
##         <dbl> <chr>         <dbl> <chr>       <chr>         <chr>    <dbl>
##  1 3101451884 3-101-451~  4043946 DIFICIL CO~ SUCURSAL ORO~ Inact~  2.26e6
##  2 3101456991 3-101-456~ 13112166 DIFICIL CO~ SUCURSAL OFI~ Inact~  9.45e6
##  3 3101464936 3-101-464~ 26820522 DIFICIL CO~ SUCURSAL CAR~ Inact~  1.72e7
##  4 3101468953 3-101-468~ 12208332 DIFICIL CO~ SUCURSAL OFI~ Inact~  8.56e6
##  5 3101469242 3-101-469~ 25961834 DIFICIL CO~ SUCURSAL OFI~ Inact~  1.84e7
##  6 3101474709 3-101-474~  2696393 DIFICIL CO~ SUCURSAL OFI~ Inact~  1.67e6
##  7 3101475511 3-101-475~  3295147 DIFICIL CO~ SUCURSAL OFI~ Inact~  2.17e6
##  8 3101479948 3-101-479~  1861627 DIFICIL CO~ SUCURSAL OFI~ Inact~  1.12e6
##  9 3101480717 3-101-480~  1910537 DIFICIL CO~ SUCURSAL CIU~ Inact~  1.17e6
## 10 3101482133 3-101-482~  5339391 DIFICIL CO~ SUCURSAL SAN~ Inact~  3.30e6
## # ... with 9,472 more rows

En este ejemplo, tenemos deudas del 2016 y del 2017, y nos interesa analizar únicamente los casos de las empresas o personas que han estado morosas por los dos años. Para ello podemos usar la función filter:

morosidad1 <- filter(morosidad1, !is.na(deuda17), !is.na(deuda16))

El código de arriba lo que hace es filtrar la base por todos aquellos registros que no tengan valores vacíos en 2017 y luego por todos los que no tienen registros vacíos en 2016. Como podemos ver, esto nos da como resultado menos registros en nuestra base de datos.

mutate()

Mutate nos permite crear nuevas columnas de forma fácil.

Podemos crear una variable que me diga cuánto cambió la deuda, que es la diferencia entre deuda17 y deuda16:

morosidad1 <- mutate(morosidad1, cambio.deuda=deuda17-deuda16)

Ahora podemos crear una nueva variable que me categorice el cambio en la deuda en si aumentó o no. Esto podemos hacerlo con la función if_else() o ifelse (funcionar igual). La sintaxis es: ifelse(condición, valor cierto, valor falso). (Es similar a la función if en Excel).

morosidad1 <- mutate(morosidad1, tipo.cambio=ifelse(cambio.deuda<0,"disminuyó", "aumentó"))

Con mutate podemos crear multiples variables a la vez, separando cada una por coma, por ejemplo:

morosidad1 <- mutate(morosidad1, cambio.deuda=deuda17-deuda16,
                     tipo.cambio=ifelse(cambio.deuda<0,"disminuyó", "aumentó"))

arrange()

Arrange nos permite ordenar las base por una o varias columnas

Por ejemplo, queremos ordenar la base en orden ascendente por deuda17 y por cambio.deuda:

morosidad1 <- arrange(morosidad1, deuda17, cambio.deuda)

Si lo queremos en orden descendente usamos desc()

morosidad1 <- arrange(morosidad1, desc(deuda17), desc(cambio.deuda))

Simplificar el trabajo: %>%

Un operador muy útil cuando trabajamos con dplyr es pipe operator que visualmente se ve así %>%. Este operador nos va a facilitar muchísimo el trabajo con funciones y nos permite hacer comando con menos líneas de código.

¿Cómo funciona el %>%? Lo primero es poner el ibjeto (tabla o dataframe) al cual queremos aplicar las operaciones de la forma base %>% funcion(). Esto nos ahorra estar poniendo como primer argumento de las funciones de dplyr al objeto.

Por ejemplo, recapitulemos todas las líneas de código que usamos anteriormente para limpiar la base de datos:

morosidad1 <- select(morosidad, -nombre.y, -situacion.y, -lugar.pago.y)
morosidad1 <- filter(morosidad1, !is.na(deuda17), !is.na(deuda16))
morosidad1 <- mutate(morosidad1, cambio.deuda=deuda17-deuda16)
morosidad1 <- mutate(morosidad1, tipo.cambio=ifelse(cambio.deuda<0,"disminuyó", "aumentó"))
morosidad1 <- arrange(morosidad1, desc(deuda17), desc(cambio.deuda))

Todos los pasos realizados anteriormente podríamos haberlos hecho de forma más simple usando el %>%:

morosidad2 <- morosidad %>%
  select(-nombre.y, -situacion.y, -lugar.pago.y) %>%
  filter(!is.na(deuda17), !is.na(deuda16)) %>%
  mutate(cambio.deuda=deuda17-deuda16,
       tipo.cambio=ifelse(cambio.deuda<0,"disminuyó", "aumentó")) %>%
  arrange(desc(deuda17), desc(cambio.deuda))

Exportar base limpia a otros formatos

Ahora que tenemos la base limpia podemos exportarla a otros formatos por ejemplo a csv.

write.csv(morosidad2, "baselimpia.csv")

tidyr

tidyr es un paquete diseñado para tener datos ¨tidy¨ o limpios. Esos datos siguen dos principios que ya hemos visto reiteradamente: Cada variable está en una sola columna y cada fila es una observación.

Para entender mejor qué es “tidy data”, puede leer este artículo: Tidy data - Hadley Wickham

Este paquete tiene 4 funciones principales gather() spread() separate() y unite().

Antes de comenzar a ver las funciones importemos los archivos de trabajo:

#Ponemos tbl_df() para convertirlo de una vez a una tibble
estudiantes <- tbl_df(read.csv("students.csv", header = T, sep= ","))
estudiantes2<- tbl_df(read.csv("students2.csv", header = T, sep= ","))

Veamos estudiantes:

estudiantes
## # A tibble: 5 x 3
##   grade  male female
##   <fct> <int>  <int>
## 1 A         1      5
## 2 B         5      0
## 3 C         5      2
## 4 D         5      5
## 5 E         7      4

¿Cuál es el problema? male y female son valores de la variable sexo, por lo que hay que cambiar la estructura de la base de datos. Esta estructura de una base de datos se conoce como “formato ancho” y tenemos que convertirla a un “formato largo”. Para eso usamos la función gather().

gather()

La función toma las columnas múltiples, las colapsa en una sola y crea una nueva columna con los valores respectivos.

La sintaxis es gather(data, key, value, columnas) o data %>% gather(key, value, columnas). Donde:

  • data: es la tabla o el data frame
  • key: es el nombre que le voy a dar a la variable que voy a “fundir”.
  • value: nombre de la variable que va a guardar los valores.
  • columna: las columnas que quiero fundir. Podemos ponerlas separadas por coma, o pondemos usar el operador - para seleccionar todas las columnas menos una.

En este ejemplo para reestructurar estudiantes el comando sería:

estudiantes_long <- gather(estudiantes, sexo, frecuencia, -grade)
estudiantes_long
## # A tibble: 10 x 3
##    grade sexo   frecuencia
##    <fct> <chr>       <int>
##  1 A     male            1
##  2 B     male            5
##  3 C     male            5
##  4 D     male            5
##  5 E     male            7
##  6 A     female          5
##  7 B     female          0
##  8 C     female          2
##  9 D     female          5
## 10 E     female          4

spread()

Es la función contraria a gather(), que nos devolvería a la tabla original. Es decir, convierte la base a formato ancho nuevamente.

estudiantes_wide <- spread(estudiantes_long, sexo, frecuencia)
estudiantes_wide
## # A tibble: 5 x 3
##   grade female  male
##   <fct>  <int> <int>
## 1 A          5     1
## 2 B          0     5
## 3 C          2     5
## 4 D          5     5
## 5 E          4     7

Veamos ahora qué pasa con estudiantes2:

estudiantes2
## # A tibble: 5 x 5
##   grade male_1 female_1 male_2 female_2
##   <fct>  <int>    <int>  <int>    <int>
## 1 A          3        4      3        4
## 2 B          6        4      3        5
## 3 C          7        4      3        8
## 4 D          4        0      8        1
## 5 E          1        1      2        7

En este caso tenemos un doble problema tenemos valores de una misma variable en diferentes columnas y diferentes variables en una sola. En este caso nos separa a los hombres y mujeres segun la clase en la que están: 1 y 2.

Entonces tenemos que hacer dos pasos. Primero usamos la función gather():

estudiantes2_long <- gather(estudiantes2, sexo_clase, frecuencia, -grade)
estudiantes2_long
## # A tibble: 20 x 3
##    grade sexo_clase frecuencia
##    <fct> <chr>           <int>
##  1 A     male_1              3
##  2 B     male_1              6
##  3 C     male_1              7
##  4 D     male_1              4
##  5 E     male_1              1
##  6 A     female_1            4
##  7 B     female_1            4
##  8 C     female_1            4
##  9 D     female_1            0
## 10 E     female_1            1
## 11 A     male_2              3
## 12 B     male_2              3
## 13 C     male_2              3
## 14 D     male_2              8
## 15 E     male_2              2
## 16 A     female_2            4
## 17 B     female_2            5
## 18 C     female_2            8
## 19 D     female_2            1
## 20 E     female_2            7

Y ahora usamos la función separate().

separate()

Esta función nos permite separar columnas.

La sintaxis es:

separate(data, col, into, sep), donde:

  • data: es la tabla o el data frame
  • col: la columna que hay que separar
  • into: las columnas por las que vamos a separar. Se pueden poner como vector de la forma c(“col1”, “col2”)
  • sep: separador, por ejemplo comas, puntos, guion bajo u otros caracteres. Si no se especifica el argumento R trata de identificar el patrón para separar los datos.

En este ejemplo, queremos separar el sexo de la clase.

estudiantes2_long2 <- separate(estudiantes2_long, sexo_clase, c("sexo", "clase"))
#En este caso R detectó el caracter para separar, el resultado es igual a si hubiéramos puesto la opción sep="_"
estudiantes2_long2
## # A tibble: 20 x 4
##    grade sexo   clase frecuencia
##    <fct> <chr>  <chr>      <int>
##  1 A     male   1              3
##  2 B     male   1              6
##  3 C     male   1              7
##  4 D     male   1              4
##  5 E     male   1              1
##  6 A     female 1              4
##  7 B     female 1              4
##  8 C     female 1              4
##  9 D     female 1              0
## 10 E     female 1              1
## 11 A     male   2              3
## 12 B     male   2              3
## 13 C     male   2              3
## 14 D     male   2              8
## 15 E     male   2              2
## 16 A     female 2              4
## 17 B     female 2              5
## 18 C     female 2              8
## 19 D     female 2              1
## 20 E     female 2              7

Estos pasos podemos simplificarlos en uno solo con el uso del %>%:

estudiantes2_long <- estudiantes2 %>%
  gather(sexo_clase, frecuencia, -grade) %>%
  separate(sexo_clase, c("sexo", "clase"))  %>%
  print
## # A tibble: 20 x 4
##    grade sexo   clase frecuencia
##    <fct> <chr>  <chr>      <int>
##  1 A     male   1              3
##  2 B     male   1              6
##  3 C     male   1              7
##  4 D     male   1              4
##  5 E     male   1              1
##  6 A     female 1              4
##  7 B     female 1              4
##  8 C     female 1              4
##  9 D     female 1              0
## 10 E     female 1              1
## 11 A     male   2              3
## 12 B     male   2              3
## 13 C     male   2              3
## 14 D     male   2              8
## 15 E     male   2              2
## 16 A     female 2              4
## 17 B     female 2              5
## 18 C     female 2              8
## 19 D     female 2              1
## 20 E     female 2              7
#el comando print, nos imprime el resultado

unite()

Es el contrario a separate.

La sintaxis es:

unite(data, col, ... , sep), donde:

  • data: es la tabla o el data frame
  • col: la nueva columna con los valores unidos
  • ...: la lista de columnas que queremos unir
  • sep: separador que va a unir las columnas, por ejemplo _.

En este caso si queremos volver a la tabla original:

estudiantes2_unida <- estudiantes2_long %>%
  unite(sexo_clase, sexo, clase, sep="-") %>%
  print
## # A tibble: 20 x 3
##    grade sexo_clase frecuencia
##    <fct> <chr>           <int>
##  1 A     male-1              3
##  2 B     male-1              6
##  3 C     male-1              7
##  4 D     male-1              4
##  5 E     male-1              1
##  6 A     female-1            4
##  7 B     female-1            4
##  8 C     female-1            4
##  9 D     female-1            0
## 10 E     female-1            1
## 11 A     male-2              3
## 12 B     male-2              3
## 13 C     male-2              3
## 14 D     male-2              8
## 15 E     male-2              2
## 16 A     female-2            4
## 17 B     female-2            5
## 18 C     female-2            8
## 19 D     female-2            1
## 20 E     female-2            7