Capítulo 2 Introducción a R
R (R Core Team) es un entorno y lenguaje de programación que permite el análisis estadístico de información y reportes gráficos. Es ampliamente usado en investigación por la comunidad estadística en campos como la biomedicina, minería de datos, matemáticas financieras, entre otros. Ha ganado mucha popularidad en los últimos años al ser un software libre que está en constante crecimiento por las aportaciones de otros usuarios y que permite la interacción con software estadísticos como STATA, SAS, SPSS, etc.. R permite la incorporación de librerías y paqueterías con funcionalidades específicas, por lo que es un lenguaje de programación muy completo y fácil de usar.
2.1 ¿Cómo obtener R?
R puede ser fácilmente descargado de forma gratuita desde el sitio oficial http://www.r-project.org/. R está disponible para las plataformas Windows, Mac y Linux.
2.2 ¿Qué es RStudio?
RStudio es un Entorno de Desarrollo Integrado (IDE, por sus siglas en inglés) para R. Este permite y facilita el desarrollo y ejecución de sintaxis para código en R, incluye una consola y proporciona herramientas para la gestión del espacio de trabajo. RStudio está disponible para Windows, Mac y Linux o para navegadores conectados a RStudio Server o RStudio Server Pro.
Algunas de las principales características de Rstudio que lo hacen una gran herramienta para trabajar en R, son:
- Auto completado de código
- Sangría inteligente
- Resaltado de sintaxis
- Facilidad para definir funciones
- Soporte integrado
- Documentación integrada
- Administración de directorios y proyectos
- Visor de datos
- Depurador interactivo para corregir errores
- Conección con Rmarkwon y Sweave
La siguiente imagen muestra la forma en la que está estructurado RStudio. El orden de los páneles puede ser elegido por el usuario, así como las características de tipo de letra, tamaño y color de fondo, entre otras características.
2.3 Lectura de datos
El primer paso para analizar datos es incorporarlos a la sesión de R para que puedan ser manipulados y observados. Existen múltiples librerías y funciones en R que permiten leer la información proveniente de un archivo externo, el cual puede tener una de muchas posibles extensiones.
Usualmente, no creamos los datos desde la sesión de R, sino que a través de un archivo externo se realiza la lectura de datos escritos en un archivo. Los más comúnes son:
La paquetería readr fue desarrollada recientemente para lidiar con la lectura de archivos grandes rápidamente. Esta paquetería proporciona funciones que suelen ser mucho más rápidas que las funciones base que proporciona R.
Ventajas de readr:
Por lo general, son mucho más rápidos (~ 10x) que sus funciones equivalentes.
Producen tibbles:
- No convierten vectores de caracteres en factores.
- No usan nombres de filas ni modifican los nombres de columnas.
Reproducibilidad
2.3.1 Archivos csv
A la hora de importar conjuntos de datos en R, uno de los formatos más habituales en los que hallamos información es en archivos separados por comas (comma separated values), cuya extensión suele ser .csv. En ellos encontramos múltiples líneas que recogen la tabla de interés, y en las cuales los valores aparecen, de manera consecutiva, separados por el carácter ,.
Para importar este tipo de archivos en nuestra sesión de R, se utiliza la función read_csv()
. Para acceder a su documentación utilizamos el comando ?read_csv
.
El único argumento que debemos de pasar a esta función de manera obligatoria, es file
, el nombre o la ruta completa del archivo que pretendemos importar.
library(readr)
read_csv(
file,col_names = TRUE,
col_types = NULL,
locale = default_locale(),
na = c("", "NA"),
quoted_na = TRUE,
quote = "\"",
comment = "")
La paquetería readr fue desarrollada recientemente para lidiar con la lectura de archivos grandes rápidamente. El paquete proporciona reemplazos para funciones como read.table(), read.csv() entre otras. Esta paquetería proporciona funciones que suelen ser mucho más rápidas que las funciones base que proporciona R.
Ventajas de readr:
Por lo general, son mucho más rápidos (~ 10x) que sus funciones equivalentes.
Producen tibbles:
- No convierten vectores de caracteres en factores.
- No usan nombres de filas ni modifican los nombres de columnas.
Reproducibilidad
No convierte, automáticamente, las columnas con cadenas de caracteres a factores, como sí hacen por defecto las otras funciones base de R.
Reconoce ocho clases diferentes de datos (enteros, lógicos, etc.), dejando el resto como cadenas de caracteres.
Veamos un ejemplo:
La base de datos llamada AmesHousing contiene un conjunto de datos con información de la Oficina del Tasador de Ames utilizada para calcular los valores tasados para las propiedades residenciales individuales vendidas en Ames, Iowa, de 2006 a 2010. FUENTES: Ames, Oficina del Tasador de Iowa.
Pueden descargar los datos para la clase aquí
<- read.csv("data/ames.csv")
base head(base, 2)
## MS_SubClass MS_Zoning Lot_Frontage
## 1 One_Story_1946_and_Newer_All_Styles Residential_Low_Density 141
## 2 One_Story_1946_and_Newer_All_Styles Residential_High_Density 80
## Lot_Area Street Alley Lot_Shape Land_Contour Utilities
## 1 31770 Pave No_Alley_Access Slightly_Irregular Lvl AllPub
## 2 11622 Pave No_Alley_Access Regular Lvl AllPub
## Lot_Config Land_Slope Neighborhood Condition_1 Condition_2 Bldg_Type
## 1 Corner Gtl North_Ames Norm Norm OneFam
## 2 Inside Gtl North_Ames Feedr Norm OneFam
## House_Style Overall_Cond Year_Built Year_Remod_Add Roof_Style Roof_Matl
## 1 One_Story Average 1960 1960 Hip CompShg
## 2 One_Story Above_Average 1961 1961 Gable CompShg
## Exterior_1st Exterior_2nd Mas_Vnr_Type Mas_Vnr_Area Exter_Cond Foundation
## 1 BrkFace Plywood Stone 112 Typical CBlock
## 2 VinylSd VinylSd None 0 Typical CBlock
## Bsmt_Cond Bsmt_Exposure BsmtFin_Type_1 BsmtFin_SF_1 BsmtFin_Type_2
## 1 Good Gd BLQ 2 Unf
## 2 Typical No Rec 6 LwQ
## BsmtFin_SF_2 Bsmt_Unf_SF Total_Bsmt_SF Heating Heating_QC Central_Air
## 1 0 441 1080 GasA Fair Y
## 2 144 270 882 GasA Typical Y
## Electrical First_Flr_SF Second_Flr_SF Gr_Liv_Area Bsmt_Full_Bath
## 1 SBrkr 1656 0 1656 1
## 2 SBrkr 896 0 896 0
## Bsmt_Half_Bath Full_Bath Half_Bath Bedroom_AbvGr Kitchen_AbvGr TotRms_AbvGrd
## 1 0 1 0 3 1 7
## 2 0 1 0 2 1 5
## Functional Fireplaces Garage_Type Garage_Finish Garage_Cars Garage_Area
## 1 Typ 2 Attchd Fin 2 528
## 2 Typ 0 Attchd Unf 1 730
## Garage_Cond Paved_Drive Wood_Deck_SF Open_Porch_SF Enclosed_Porch
## 1 Typical Partial_Pavement 210 62 0
## 2 Typical Paved 140 0 0
## Three_season_porch Screen_Porch Pool_Area Pool_QC Fence
## 1 0 0 0 No_Pool No_Fence
## 2 0 120 0 No_Pool Minimum_Privacy
## Misc_Feature Misc_Val Mo_Sold Year_Sold Sale_Type Sale_Condition Sale_Price
## 1 None 0 5 2010 WD Normal 215000
## 2 None 0 6 2010 WD Normal 105000
## Longitude Latitude
## 1 -93.61975 42.05403
## 2 -93.61976 42.05301
<- read_csv("data/ames.csv")
tidy head(tidy, 2)
## # A tibble: 2 × 74
## MS_SubClass MS_Zoning Lot_Frontage Lot_Area Street Alley Lot_Shape
## <chr> <chr> <dbl> <dbl> <chr> <chr> <chr>
## 1 One_Story_1946_and_New… Resident… 141 31770 Pave No_A… Slightly…
## 2 One_Story_1946_and_New… Resident… 80 11622 Pave No_A… Regular
## # ℹ 67 more variables: Land_Contour <chr>, Utilities <chr>, Lot_Config <chr>,
## # Land_Slope <chr>, Neighborhood <chr>, Condition_1 <chr>, Condition_2 <chr>,
## # Bldg_Type <chr>, House_Style <chr>, Overall_Cond <chr>, Year_Built <dbl>,
## # Year_Remod_Add <dbl>, Roof_Style <chr>, Roof_Matl <chr>,
## # Exterior_1st <chr>, Exterior_2nd <chr>, Mas_Vnr_Type <chr>,
## # Mas_Vnr_Area <dbl>, Exter_Cond <chr>, Foundation <chr>, Bsmt_Cond <chr>,
## # Bsmt_Exposure <chr>, BsmtFin_Type_1 <chr>, BsmtFin_SF_1 <dbl>, …
¿Y si el archivo que necesitamos leer esta en excel?
2.3.2 Archivos txt
Uno de los archivos más comunes es el .txt. La librería readr también cuenta con funciones que permiten leer fácilmente los datos contenidos en formato tabular.
<- read_delim("data/ames.txt", delim = ";", col_names = TRUE)
ames_txt head(ames_txt, 2)
## # A tibble: 2 × 74
## MS_SubClass MS_Zoning Lot_Frontage Lot_Area Street Alley Lot_Shape
## <chr> <chr> <dbl> <dbl> <chr> <chr> <chr>
## 1 One_Story_1946_and_New… Resident… 141 31770 Pave No_A… Slightly…
## 2 One_Story_1946_and_New… Resident… 80 11622 Pave No_A… Regular
## # ℹ 67 more variables: Land_Contour <chr>, Utilities <chr>, Lot_Config <chr>,
## # Land_Slope <chr>, Neighborhood <chr>, Condition_1 <chr>, Condition_2 <chr>,
## # Bldg_Type <chr>, House_Style <chr>, Overall_Cond <chr>, Year_Built <dbl>,
## # Year_Remod_Add <dbl>, Roof_Style <chr>, Roof_Matl <chr>,
## # Exterior_1st <chr>, Exterior_2nd <chr>, Mas_Vnr_Type <chr>,
## # Mas_Vnr_Area <dbl>, Exter_Cond <chr>, Foundation <chr>, Bsmt_Cond <chr>,
## # Bsmt_Exposure <chr>, BsmtFin_Type_1 <chr>, BsmtFin_SF_1 <dbl>, …
La función read_delim() funciona para leer archivos con diferentes delimitadores posibles, es decir, es posible especificar si las columnas están separadas por espacios, comas, punto y coma, tabulador o algún otro delimitador (““,”,“,”;“,”, “@”).
Adicionalmente, se puede especificar si el archivo contiene encabezado, si existen renglones a saltar, codificación, tipo de variable y muchas más opciones. Todos estos detalles pueden consultarse en la documentación de ayuda.
2.3.3 Archivos xls y xlsx
La paquetería readxl facilita la obtención de datos tabulares de archivos de Excel. Admite tanto el formato .xls heredado como el formato .xlsx moderno basado en XML.
Esta paquetería pone a disposición las siguientes funciones:
read_xlsx()
lee un archivo con extensión xlsx.
read_xlsx(
path,sheet = NULL,
range = NULL,
col_names = TRUE,
col_types = NULL,
na = "",
trim_ws = TRUE,
skip = 0,
n_max = Inf,
guess_max = min(1000, n_max),
progress = readxl_progress(),
.name_repair = "unique"
)
read_xls()
lee un archivo con extensión xls.
read_xls(
path,sheet = NULL,
range = NULL,
col_names = TRUE,
col_types = NULL,
na = "",
trim_ws = TRUE,
skip = 0,
n_max = Inf,
guess_max = min(1000, n_max),
progress = readxl_progress(),
.name_repair = "unique"
)
read_excel()
determina si el archivo es de tipo xls o xlsx para después llamar a una de las funciones mencionadas anteriormente.
read_excel(
path,sheet = NULL,
range = NULL,
col_names = TRUE,
col_types = NULL,
na = "",
trim_ws = TRUE,
skip = 0,
n_max = Inf,
guess_max = min(1000, n_max),
progress = readxl_progress(),
.name_repair = "unique"
)
EJERCICIO: Leer archivo excel de la carpeta del curso
2.3.4 Archivos json
Se utiliza la función fromJSON
de la paquetería jsonlite
library(jsonlite)
<- jsonlite::fromJSON("data/ames.json")
base_json head(base_json, 2)
## MS_SubClass MS_Zoning Lot_Frontage
## 1 One_Story_1946_and_Newer_All_Styles Residential_Low_Density 141
## 2 One_Story_1946_and_Newer_All_Styles Residential_High_Density 80
## Lot_Area Street Alley Lot_Shape Land_Contour Utilities
## 1 31770 Pave No_Alley_Access Slightly_Irregular Lvl AllPub
## 2 11622 Pave No_Alley_Access Regular Lvl AllPub
## Lot_Config Land_Slope Neighborhood Condition_1 Condition_2 Bldg_Type
## 1 Corner Gtl North_Ames Norm Norm OneFam
## 2 Inside Gtl North_Ames Feedr Norm OneFam
## House_Style Overall_Cond Year_Built Year_Remod_Add Roof_Style Roof_Matl
## 1 One_Story Average 1960 1960 Hip CompShg
## 2 One_Story Above_Average 1961 1961 Gable CompShg
## Exterior_1st Exterior_2nd Mas_Vnr_Type Mas_Vnr_Area Exter_Cond Foundation
## 1 BrkFace Plywood Stone 112 Typical CBlock
## 2 VinylSd VinylSd None 0 Typical CBlock
## Bsmt_Cond Bsmt_Exposure BsmtFin_Type_1 BsmtFin_SF_1 BsmtFin_Type_2
## 1 Good Gd BLQ 2 Unf
## 2 Typical No Rec 6 LwQ
## BsmtFin_SF_2 Bsmt_Unf_SF Total_Bsmt_SF Heating Heating_QC Central_Air
## 1 0 441 1080 GasA Fair Y
## 2 144 270 882 GasA Typical Y
## Electrical First_Flr_SF Second_Flr_SF Gr_Liv_Area Bsmt_Full_Bath
## 1 SBrkr 1656 0 1656 1
## 2 SBrkr 896 0 896 0
## Bsmt_Half_Bath Full_Bath Half_Bath Bedroom_AbvGr Kitchen_AbvGr TotRms_AbvGrd
## 1 0 1 0 3 1 7
## 2 0 1 0 2 1 5
## Functional Fireplaces Garage_Type Garage_Finish Garage_Cars Garage_Area
## 1 Typ 2 Attchd Fin 2 528
## 2 Typ 0 Attchd Unf 1 730
## Garage_Cond Paved_Drive Wood_Deck_SF Open_Porch_SF Enclosed_Porch
## 1 Typical Partial_Pavement 210 62 0
## 2 Typical Paved 140 0 0
## Three_season_porch Screen_Porch Pool_Area Pool_QC Fence
## 1 0 0 0 No_Pool No_Fence
## 2 0 120 0 No_Pool Minimum_Privacy
## Misc_Feature Misc_Val Mo_Sold Year_Sold Sale_Type Sale_Condition Sale_Price
## 1 None 0 5 2010 WD Normal 215000
## 2 None 0 6 2010 WD Normal 105000
## Longitude Latitude
## 1 -93.6198 42.054
## 2 -93.6198 42.053
2.3.5 Archivos rds
Un tipo de archivo que resulta de particular interés, es el .RDS. Este archivo comprime cualquier objeto o resultado que sea usado o producido en R. Uno puede almacenar el objeto de interés de la siguiente manera:
saveRDS(base_json, "data/ames.rds")
Puede observarse que en el explorador de archivos se encuentra ahora el nuevo archivo con extensión .rds, el cual puede ser posteriormente incorporado a una sesión de R para seguir trabajando con él.
<- readRDS("data/ames.rds") base_rds
Algunas de las grandes ventajas que tiene almacenar los archivos en formato rds, son las siguientes:
No es necesario volver a ejecutar procesos largos cuando ya se ha logrado realizar una vez.
El tiempo de lectura de la información es considerablemente más rápido.
2.4 Consultas de datos
Ahora que ya se ha estudiado la manera de cargar datos, aprenderemos como manipularlos con dplyr. El paquete dplyr proporciona un conjunto de funciones muy útiles para manipular data-frames y así reducir el número de repeticiones, la probabilidad de cometer errores y el número de caracteres que hay que escribir. Como valor extra, podemos encontrar que la gramática de dplyr es más fácil de entender.
Revisaremos algunas de sus funciones más usadas (verbos), así como el uso de pipes (%>%) para combinarlas.
select()
filter()
arrange()
mutate()
summarise()
join()
group_by()
Primero tenemos que instalar y cargar la paquetería (parte de tidyverse):
# install.packages("dplyr")
library(dplyr)
library(readr)
Usaremos el dataset AmesHousing que se proporcionó en el capítulo anterior (el alumno puede hacer el ejercicio con datos propios)
<- read_csv("data/ames.csv")
ames_housing
glimpse(ames_housing)
## Rows: 2,930
## Columns: 74
## $ MS_SubClass <chr> "One_Story_1946_and_Newer_All_Styles", "One_Story_1…
## $ MS_Zoning <chr> "Residential_Low_Density", "Residential_High_Densit…
## $ Lot_Frontage <dbl> 141, 80, 81, 93, 74, 78, 41, 43, 39, 60, 75, 0, 63,…
## $ Lot_Area <dbl> 31770, 11622, 14267, 11160, 13830, 9978, 4920, 5005…
## $ Street <chr> "Pave", "Pave", "Pave", "Pave", "Pave", "Pave", "Pa…
## $ Alley <chr> "No_Alley_Access", "No_Alley_Access", "No_Alley_Acc…
## $ Lot_Shape <chr> "Slightly_Irregular", "Regular", "Slightly_Irregula…
## $ Land_Contour <chr> "Lvl", "Lvl", "Lvl", "Lvl", "Lvl", "Lvl", "Lvl", "H…
## $ Utilities <chr> "AllPub", "AllPub", "AllPub", "AllPub", "AllPub", "…
## $ Lot_Config <chr> "Corner", "Inside", "Corner", "Corner", "Inside", "…
## $ Land_Slope <chr> "Gtl", "Gtl", "Gtl", "Gtl", "Gtl", "Gtl", "Gtl", "G…
## $ Neighborhood <chr> "North_Ames", "North_Ames", "North_Ames", "North_Am…
## $ Condition_1 <chr> "Norm", "Feedr", "Norm", "Norm", "Norm", "Norm", "N…
## $ Condition_2 <chr> "Norm", "Norm", "Norm", "Norm", "Norm", "Norm", "No…
## $ Bldg_Type <chr> "OneFam", "OneFam", "OneFam", "OneFam", "OneFam", "…
## $ House_Style <chr> "One_Story", "One_Story", "One_Story", "One_Story",…
## $ Overall_Cond <chr> "Average", "Above_Average", "Above_Average", "Avera…
## $ Year_Built <dbl> 1960, 1961, 1958, 1968, 1997, 1998, 2001, 1992, 199…
## $ Year_Remod_Add <dbl> 1960, 1961, 1958, 1968, 1998, 1998, 2001, 1992, 199…
## $ Roof_Style <chr> "Hip", "Gable", "Hip", "Hip", "Gable", "Gable", "Ga…
## $ Roof_Matl <chr> "CompShg", "CompShg", "CompShg", "CompShg", "CompSh…
## $ Exterior_1st <chr> "BrkFace", "VinylSd", "Wd Sdng", "BrkFace", "VinylS…
## $ Exterior_2nd <chr> "Plywood", "VinylSd", "Wd Sdng", "BrkFace", "VinylS…
## $ Mas_Vnr_Type <chr> "Stone", "None", "BrkFace", "None", "None", "BrkFac…
## $ Mas_Vnr_Area <dbl> 112, 0, 108, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6…
## $ Exter_Cond <chr> "Typical", "Typical", "Typical", "Typical", "Typica…
## $ Foundation <chr> "CBlock", "CBlock", "CBlock", "CBlock", "PConc", "P…
## $ Bsmt_Cond <chr> "Good", "Typical", "Typical", "Typical", "Typical",…
## $ Bsmt_Exposure <chr> "Gd", "No", "No", "No", "No", "No", "Mn", "No", "No…
## $ BsmtFin_Type_1 <chr> "BLQ", "Rec", "ALQ", "ALQ", "GLQ", "GLQ", "GLQ", "A…
## $ BsmtFin_SF_1 <dbl> 2, 6, 1, 1, 3, 3, 3, 1, 3, 7, 7, 1, 7, 3, 3, 1, 3, …
## $ BsmtFin_Type_2 <chr> "Unf", "LwQ", "Unf", "Unf", "Unf", "Unf", "Unf", "U…
## $ BsmtFin_SF_2 <dbl> 0, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 0…
## $ Bsmt_Unf_SF <dbl> 441, 270, 406, 1045, 137, 324, 722, 1017, 415, 994,…
## $ Total_Bsmt_SF <dbl> 1080, 882, 1329, 2110, 928, 926, 1338, 1280, 1595, …
## $ Heating <chr> "GasA", "GasA", "GasA", "GasA", "GasA", "GasA", "Ga…
## $ Heating_QC <chr> "Fair", "Typical", "Typical", "Excellent", "Good", …
## $ Central_Air <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "…
## $ Electrical <chr> "SBrkr", "SBrkr", "SBrkr", "SBrkr", "SBrkr", "SBrkr…
## $ First_Flr_SF <dbl> 1656, 896, 1329, 2110, 928, 926, 1338, 1280, 1616, …
## $ Second_Flr_SF <dbl> 0, 0, 0, 0, 701, 678, 0, 0, 0, 776, 892, 0, 676, 0,…
## $ Gr_Liv_Area <dbl> 1656, 896, 1329, 2110, 1629, 1604, 1338, 1280, 1616…
## $ Bsmt_Full_Bath <dbl> 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, …
## $ Bsmt_Half_Bath <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ Full_Bath <dbl> 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 2, …
## $ Half_Bath <dbl> 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, …
## $ Bedroom_AbvGr <dbl> 3, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3, 3, 2, 1, 4, 4, …
## $ Kitchen_AbvGr <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ TotRms_AbvGrd <dbl> 7, 5, 6, 8, 6, 7, 6, 5, 5, 7, 7, 6, 7, 5, 4, 12, 8,…
## $ Functional <chr> "Typ", "Typ", "Typ", "Typ", "Typ", "Typ", "Typ", "T…
## $ Fireplaces <dbl> 2, 0, 0, 2, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, …
## $ Garage_Type <chr> "Attchd", "Attchd", "Attchd", "Attchd", "Attchd", "…
## $ Garage_Finish <chr> "Fin", "Unf", "Unf", "Fin", "Fin", "Fin", "Fin", "R…
## $ Garage_Cars <dbl> 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, …
## $ Garage_Area <dbl> 528, 730, 312, 522, 482, 470, 582, 506, 608, 442, 4…
## $ Garage_Cond <chr> "Typical", "Typical", "Typical", "Typical", "Typica…
## $ Paved_Drive <chr> "Partial_Pavement", "Paved", "Paved", "Paved", "Pav…
## $ Wood_Deck_SF <dbl> 210, 140, 393, 0, 212, 360, 0, 0, 237, 140, 157, 48…
## $ Open_Porch_SF <dbl> 62, 0, 36, 0, 34, 36, 0, 82, 152, 60, 84, 21, 75, 0…
## $ Enclosed_Porch <dbl> 0, 0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ Three_season_porch <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ Screen_Porch <dbl> 0, 120, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 140, …
## $ Pool_Area <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ Pool_QC <chr> "No_Pool", "No_Pool", "No_Pool", "No_Pool", "No_Poo…
## $ Fence <chr> "No_Fence", "Minimum_Privacy", "No_Fence", "No_Fenc…
## $ Misc_Feature <chr> "None", "None", "Gar2", "None", "None", "None", "No…
## $ Misc_Val <dbl> 0, 0, 12500, 0, 0, 0, 0, 0, 0, 0, 0, 500, 0, 0, 0, …
## $ Mo_Sold <dbl> 5, 6, 6, 4, 3, 6, 4, 1, 3, 6, 4, 3, 5, 2, 6, 6, 6, …
## $ Year_Sold <dbl> 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 201…
## $ Sale_Type <chr> "WD", "WD", "WD", "WD", "WD", "WD", "WD", "WD", "WD…
## $ Sale_Condition <chr> "Normal", "Normal", "Normal", "Normal", "Normal", "…
## $ Sale_Price <dbl> 215000, 105000, 172000, 244000, 189900, 195500, 213…
## $ Longitude <dbl> -93.61975, -93.61976, -93.61939, -93.61732, -93.638…
## $ Latitude <dbl> 42.05403, 42.05301, 42.05266, 42.05125, 42.06090, 4…
2.4.1 Seleccionar columnas
Observamos que nuestros datos tienen 2,930 observaciones y 74 variables, con select() podemos seleccionar las variables que se indiquen.
%>% select(Lot_Area, Neighborhood, Year_Sold, Sale_Price) ames_housing
## # A tibble: 2,930 × 4
## Lot_Area Neighborhood Year_Sold Sale_Price
## <dbl> <chr> <dbl> <dbl>
## 1 31770 North_Ames 2010 215000
## 2 11622 North_Ames 2010 105000
## 3 14267 North_Ames 2010 172000
## 4 11160 North_Ames 2010 244000
## 5 13830 Gilbert 2010 189900
## 6 9978 Gilbert 2010 195500
## 7 4920 Stone_Brook 2010 213500
## 8 5005 Stone_Brook 2010 191500
## 9 5389 Stone_Brook 2010 236500
## 10 7500 Gilbert 2010 189000
## # ℹ 2,920 more rows
¡¡ RECORDAR !!
El operador pipe (%>%) se usa para conectar un elemento con una función o acción a realizar. En este caso solo se indica que en los datos de ames se seleccionan 4 variables.
Con select() y contains() podemos seleccionar variables con alguna cadena de texto.
%>% select(contains("Area")) ames_housing
## # A tibble: 2,930 × 5
## Lot_Area Mas_Vnr_Area Gr_Liv_Area Garage_Area Pool_Area
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 31770 112 1656 528 0
## 2 11622 0 896 730 0
## 3 14267 108 1329 312 0
## 4 11160 0 2110 522 0
## 5 13830 0 1629 482 0
## 6 9978 20 1604 470 0
## 7 4920 0 1338 582 0
## 8 5005 0 1280 506 0
## 9 5389 0 1616 608 0
## 10 7500 0 1804 442 0
## # ℹ 2,920 more rows
De igual manera, con select(), ends_with y start_with() podemos seleccionar que inicien o terminen con alguna cadena de texto.
%>% select(starts_with("Garage")) ames_housing
## # A tibble: 2,930 × 5
## Garage_Type Garage_Finish Garage_Cars Garage_Area Garage_Cond
## <chr> <chr> <dbl> <dbl> <chr>
## 1 Attchd Fin 2 528 Typical
## 2 Attchd Unf 1 730 Typical
## 3 Attchd Unf 1 312 Typical
## 4 Attchd Fin 2 522 Typical
## 5 Attchd Fin 2 482 Typical
## 6 Attchd Fin 2 470 Typical
## 7 Attchd Fin 2 582 Typical
## 8 Attchd RFn 2 506 Typical
## 9 Attchd RFn 2 608 Typical
## 10 Attchd Fin 2 442 Typical
## # ℹ 2,920 more rows
Funciones útiles para select():
contains(): Selecciona variables cuyo nombre contiene la cadena de texto.
ends_with(): Selecciona variables cuyo nombre termina con la cadena de caracteres.
everything(): Selecciona todas las columnas.
matches(): Selecciona las variables cuyos nombres coinciden con una expresión regular.
num_range(): Selecciona las variables por posición.
start_with(): Selecciona variables cuyos nombres empiezan con la cadena de caracteres.
any_of: Selecciona cualquiera de estas variables, en caso de existir
EJERCICIO:
- Crear con datos propios una consulta de columnas usando como variable auxiliar cada una de las listadas anteriormente. Será suficiente con realizar un ejemplo de cada una.
2.4.2 Filtrar observaciones
La función filter() nos permite filtrar filas según una condición, primero notemos que la variable Sale_Condition tiene distintas categorías.
table(ames_housing$Sale_Condition)
##
## Abnorml AdjLand Alloca Family Normal Partial
## 190 12 24 46 2413 245
¡¡ SPOILER !!
En un modelo predictivo de Machine Learning, no es correcto agregar columnas cuyo valor es conocido hasta el momento de la observación. Es decir, no deben agregarse variables que no se conozca su valor al momento de la predicción, como es el caso de condición de venta.
Ahora usaremos la función filter para quedarnos solo con las observaciones con condición de venta “normal”.
%>% filter(Sale_Condition == "Normal") ames_housing
## # A tibble: 2,413 × 74
## MS_SubClass MS_Zoning Lot_Frontage Lot_Area Street Alley Lot_Shape
## <chr> <chr> <dbl> <dbl> <chr> <chr> <chr>
## 1 One_Story_1946_and_Ne… Resident… 141 31770 Pave No_A… Slightly…
## 2 One_Story_1946_and_Ne… Resident… 80 11622 Pave No_A… Regular
## 3 One_Story_1946_and_Ne… Resident… 81 14267 Pave No_A… Slightly…
## 4 One_Story_1946_and_Ne… Resident… 93 11160 Pave No_A… Regular
## 5 Two_Story_1946_and_Ne… Resident… 74 13830 Pave No_A… Slightly…
## 6 Two_Story_1946_and_Ne… Resident… 78 9978 Pave No_A… Slightly…
## 7 One_Story_PUD_1946_an… Resident… 41 4920 Pave No_A… Regular
## 8 One_Story_PUD_1946_an… Resident… 43 5005 Pave No_A… Slightly…
## 9 One_Story_PUD_1946_an… Resident… 39 5389 Pave No_A… Slightly…
## 10 Two_Story_1946_and_Ne… Resident… 60 7500 Pave No_A… Regular
## # ℹ 2,403 more rows
## # ℹ 67 more variables: Land_Contour <chr>, Utilities <chr>, Lot_Config <chr>,
## # Land_Slope <chr>, Neighborhood <chr>, Condition_1 <chr>, Condition_2 <chr>,
## # Bldg_Type <chr>, House_Style <chr>, Overall_Cond <chr>, Year_Built <dbl>,
## # Year_Remod_Add <dbl>, Roof_Style <chr>, Roof_Matl <chr>,
## # Exterior_1st <chr>, Exterior_2nd <chr>, Mas_Vnr_Type <chr>,
## # Mas_Vnr_Area <dbl>, Exter_Cond <chr>, Foundation <chr>, Bsmt_Cond <chr>, …
También se puede usar para filtrar variables numéricas:
%>% filter(Lot_Area > 1000 & Sale_Price >= 150000) ames_housing
## # A tibble: 1,677 × 74
## MS_SubClass MS_Zoning Lot_Frontage Lot_Area Street Alley Lot_Shape
## <chr> <chr> <dbl> <dbl> <chr> <chr> <chr>
## 1 One_Story_1946_and_Ne… Resident… 141 31770 Pave No_A… Slightly…
## 2 One_Story_1946_and_Ne… Resident… 81 14267 Pave No_A… Slightly…
## 3 One_Story_1946_and_Ne… Resident… 93 11160 Pave No_A… Regular
## 4 Two_Story_1946_and_Ne… Resident… 74 13830 Pave No_A… Slightly…
## 5 Two_Story_1946_and_Ne… Resident… 78 9978 Pave No_A… Slightly…
## 6 One_Story_PUD_1946_an… Resident… 41 4920 Pave No_A… Regular
## 7 One_Story_PUD_1946_an… Resident… 43 5005 Pave No_A… Slightly…
## 8 One_Story_PUD_1946_an… Resident… 39 5389 Pave No_A… Slightly…
## 9 Two_Story_1946_and_Ne… Resident… 60 7500 Pave No_A… Regular
## 10 Two_Story_1946_and_Ne… Resident… 75 10000 Pave No_A… Slightly…
## # ℹ 1,667 more rows
## # ℹ 67 more variables: Land_Contour <chr>, Utilities <chr>, Lot_Config <chr>,
## # Land_Slope <chr>, Neighborhood <chr>, Condition_1 <chr>, Condition_2 <chr>,
## # Bldg_Type <chr>, House_Style <chr>, Overall_Cond <chr>, Year_Built <dbl>,
## # Year_Remod_Add <dbl>, Roof_Style <chr>, Roof_Matl <chr>,
## # Exterior_1st <chr>, Exterior_2nd <chr>, Mas_Vnr_Type <chr>,
## # Mas_Vnr_Area <dbl>, Exter_Cond <chr>, Foundation <chr>, Bsmt_Cond <chr>, …
Notemos que en el ejemplo anterior se usa &, que ayuda a filtrar por dos condiciones.
También puede usarse | para filtrar por alguna de las dos condiciones.
%>% filter(Lot_Area < 1000 | Sale_Price <= 150000) ames_housing
## # A tibble: 1,271 × 74
## MS_SubClass MS_Zoning Lot_Frontage Lot_Area Street Alley Lot_Shape
## <chr> <chr> <dbl> <dbl> <chr> <chr> <chr>
## 1 One_Story_1946_and_Ne… Resident… 80 11622 Pave No_A… Regular
## 2 One_Story_1946_and_Ne… Resident… 140 19138 Pave No_A… Regular
## 3 One_Story_1946_and_Ne… Resident… 0 11241 Pave No_A… Slightly…
## 4 One_Story_1946_and_Ne… Resident… 0 12537 Pave No_A… Slightly…
## 5 One_Story_1946_and_Ne… Resident… 65 8450 Pave No_A… Regular
## 6 One_Story_1946_and_Ne… Resident… 70 8400 Pave No_A… Regular
## 7 One_Story_1946_and_Ne… Resident… 70 10500 Pave No_A… Regular
## 8 Two_Story_PUD_1946_an… Resident… 21 1680 Pave No_A… Regular
## 9 Two_Story_PUD_1946_an… Resident… 21 1680 Pave No_A… Regular
## 10 Two_Story_PUD_1946_an… Resident… 21 1680 Pave No_A… Regular
## # ℹ 1,261 more rows
## # ℹ 67 more variables: Land_Contour <chr>, Utilities <chr>, Lot_Config <chr>,
## # Land_Slope <chr>, Neighborhood <chr>, Condition_1 <chr>, Condition_2 <chr>,
## # Bldg_Type <chr>, House_Style <chr>, Overall_Cond <chr>, Year_Built <dbl>,
## # Year_Remod_Add <dbl>, Roof_Style <chr>, Roof_Matl <chr>,
## # Exterior_1st <chr>, Exterior_2nd <chr>, Mas_Vnr_Type <chr>,
## # Mas_Vnr_Area <dbl>, Exter_Cond <chr>, Foundation <chr>, Bsmt_Cond <chr>, …
Las condiciones pueden ser expresiones lógicas construidas mediante los operadores relacionales y lógicos:
< : Menor que
> : Mayor que
== : Igual que
<= : Menor o igual que
>= : Mayor o igual que
!= : Diferente que
%in% : Pertenece al conjunto
is.na : Es NA
!is.na : No es NA
EJERCICIO:
Practicar la función de filtro de observaciones usando los operadores auxiliares.
Concatenar el resultado de seleccionar columnas y posteriormente filtrar columnas.
2.4.3 Ordenar registros
La función arrange() se utiliza para ordenar las filas de un data frame de acuerdo a una o varias variables. Este ordenamiento puede ser ascendente o descendente.
Por defecto arrange() ordena las filas por orden ascendente:
%>% arrange(Sale_Price) ames_housing
## # A tibble: 2,930 × 74
## MS_SubClass MS_Zoning Lot_Frontage Lot_Area Street Alley Lot_Shape
## <chr> <chr> <dbl> <dbl> <chr> <chr> <chr>
## 1 One_Story_1945_and_Ol… Resident… 68 9656 Pave No_A… Regular
## 2 One_Story_1946_and_Ne… A_agr 80 14584 Pave No_A… Regular
## 3 One_Story_1945_and_Ol… C_all 60 7879 Pave No_A… Regular
## 4 One_Story_1945_and_Ol… Resident… 60 8088 Pave Grav… Regular
## 5 One_Story_1946_and_Ne… C_all 50 9000 Pave No_A… Regular
## 6 One_and_Half_Story_Fi… Resident… 50 5925 Pave No_A… Regular
## 7 One_Story_1946_and_Ne… Resident… 50 5000 Pave No_A… Regular
## 8 Two_Story_1945_and_Ol… C_all 50 8500 Pave Paved Regular
## 9 One_Story_1945_and_Ol… C_all 72 9392 Pave No_A… Regular
## 10 One_Story_1945_and_Ol… Resident… 50 5925 Pave No_A… Regular
## # ℹ 2,920 more rows
## # ℹ 67 more variables: Land_Contour <chr>, Utilities <chr>, Lot_Config <chr>,
## # Land_Slope <chr>, Neighborhood <chr>, Condition_1 <chr>, Condition_2 <chr>,
## # Bldg_Type <chr>, House_Style <chr>, Overall_Cond <chr>, Year_Built <dbl>,
## # Year_Remod_Add <dbl>, Roof_Style <chr>, Roof_Matl <chr>,
## # Exterior_1st <chr>, Exterior_2nd <chr>, Mas_Vnr_Type <chr>,
## # Mas_Vnr_Area <dbl>, Exter_Cond <chr>, Foundation <chr>, Bsmt_Cond <chr>, …
Si las queremos ordenar de forma ascendente, lo haremos del siguiente modo:
%>% arrange(desc(Sale_Price)) ames_housing
## # A tibble: 2,930 × 74
## MS_SubClass MS_Zoning Lot_Frontage Lot_Area Street Alley Lot_Shape
## <chr> <chr> <dbl> <dbl> <chr> <chr> <chr>
## 1 Two_Story_1946_and_Ne… Resident… 104 21535 Pave No_A… Slightly…
## 2 Two_Story_1946_and_Ne… Resident… 160 15623 Pave No_A… Slightly…
## 3 Two_Story_1946_and_Ne… Resident… 118 35760 Pave No_A… Slightly…
## 4 One_Story_1946_and_Ne… Resident… 106 12720 Pave No_A… Regular
## 5 One_Story_1946_and_Ne… Resident… 100 12919 Pave No_A… Slightly…
## 6 One_Story_1946_and_Ne… Resident… 105 13693 Pave No_A… Regular
## 7 One_Story_1946_and_Ne… Resident… 52 51974 Pave No_A… Slightly…
## 8 Two_Story_1946_and_Ne… Resident… 114 17242 Pave No_A… Slightly…
## 9 Two_Story_1946_and_Ne… Resident… 107 13891 Pave No_A… Regular
## 10 Two_Story_1946_and_Ne… Resident… 85 16056 Pave No_A… Slightly…
## # ℹ 2,920 more rows
## # ℹ 67 more variables: Land_Contour <chr>, Utilities <chr>, Lot_Config <chr>,
## # Land_Slope <chr>, Neighborhood <chr>, Condition_1 <chr>, Condition_2 <chr>,
## # Bldg_Type <chr>, House_Style <chr>, Overall_Cond <chr>, Year_Built <dbl>,
## # Year_Remod_Add <dbl>, Roof_Style <chr>, Roof_Matl <chr>,
## # Exterior_1st <chr>, Exterior_2nd <chr>, Mas_Vnr_Type <chr>,
## # Mas_Vnr_Area <dbl>, Exter_Cond <chr>, Foundation <chr>, Bsmt_Cond <chr>, …
Si se desea usar dos o más columnas para realizar el ordenamiento, deben separarse por comas cada una de las características
%>%
ames_housing arrange(Sale_Condition, desc(Sale_Price), Lot_Area) %>%
select(Sale_Condition, Sale_Price, Lot_Area)
## # A tibble: 2,930 × 3
## Sale_Condition Sale_Price Lot_Area
## <chr> <dbl> <dbl>
## 1 Abnorml 745000 15623
## 2 Abnorml 552000 14836
## 3 Abnorml 475000 11778
## 4 Abnorml 390000 13418
## 5 Abnorml 328900 5119
## 6 Abnorml 310000 14541
## 7 Abnorml 290000 9950
## 8 Abnorml 287000 15498
## 9 Abnorml 258000 12090
## 10 Abnorml 257000 10994
## # ℹ 2,920 more rows
Notemos que en el ejemplo anterior usamos dos pipes (%>%), como habíamos mencionado se pueden usar los necesarios para combinar funciones.
2.4.4 Agregar / Modificar
Con la función mutate() podemos computar transformaciones de variables en un data frame. A menudo, tendremos la necesidad de crear nuevas variables que se calculan a partir de variables existentes. La función mutate() proporciona una interfaz clara para realizar este tipo de operaciones.
Por ejemplo, haremos el cálculo de la antigüedad del inmueble a partir de las variables Year_Sold y Year_Remod_Add:
<- ames_housing %>%
ejemplo_mutate select(Year_Sold, Year_Remod_Add) %>%
mutate(Antique = Year_Sold - Year_Remod_Add)
ejemplo_mutate
## # A tibble: 2,930 × 3
## Year_Sold Year_Remod_Add Antique
## <dbl> <dbl> <dbl>
## 1 2010 1960 50
## 2 2010 1961 49
## 3 2010 1958 52
## 4 2010 1968 42
## 5 2010 1998 12
## 6 2010 1998 12
## 7 2010 2001 9
## 8 2010 1992 18
## 9 2010 1996 14
## 10 2010 1999 11
## # ℹ 2,920 more rows
El ejemplo anterior crea una nueva variable. Ahora se presenta otro ejemplo en donde se modifica una variable ya creada.
%>%
ejemplo_mutate mutate(Antique = Antique * 12)
## # A tibble: 2,930 × 3
## Year_Sold Year_Remod_Add Antique
## <dbl> <dbl> <dbl>
## 1 2010 1960 600
## 2 2010 1961 588
## 3 2010 1958 624
## 4 2010 1968 504
## 5 2010 1998 144
## 6 2010 1998 144
## 7 2010 2001 108
## 8 2010 1992 216
## 9 2010 1996 168
## 10 2010 1999 132
## # ℹ 2,920 more rows
En este segundo ejemplo, se modifica el número de años de antigüedad y se multiplica por un factor de 12 para modificar el tiempo en una escala de meses.
2.4.5 Resumen estadístico
La función summarise() se comporta de forma análoga a la función mutate(), excepto que en lugar de añadir nuevas columnas crea un nuevo data frame.
Podemos usar el ejemplo anterior y calcular la media de la variable creada Antique:
%>%
ames_housing select(Year_Sold, Year_Remod_Add) %>%
mutate(Antique = Year_Sold - Year_Remod_Add) %>%
summarise(Mean_Antique = mean(Antique))
## # A tibble: 1 × 1
## Mean_Antique
## <dbl>
## 1 23.5
Solo fue necesario agregar un pipe, especificar el nombre de la variable creada y la operación a realizar.
A continuación se muestran funciones que trabajando conjuntamente con la función summarise() facilitarán nuestro trabajo diario. Las primeras pertenecen al paquete base y las otras son del paquete dplyr. Todas ellas toman como argumento un vector y devuelven un único resultado:
min(), max() : Valores max y min.
mean() : Media.
median() : Mediana.
sum() : Suma de los valores.
var(), sd() : Varianza y desviación estándar.
first() : Primer valor en un vector.
last() : El último valor en un vector
n() : El número de valores en un vector.
n_distinct() : El número de valores distintos en un vector.
nth() : Extrae el valor que ocupa la posición n en un vector.
Mas adelante veremos como combinar esta función con la función group_by() para calcular estadísticos agrupados por alguna característica de interés.
EJERCICIO:
- Realizar una consulta usando summarise() y cada una de las funciones estadísticas listadas anteriormente.
2.4.6 Agrupamiento
La función group_by() agrupa un conjunto de filas de acuerdo con los valores de una o más columnas o expresiones.
Usaremos el ejemplo anterior. Primero creamos nuestra nueva variable Antique, después agrupamos por vecindario y al final calculamos la media de la variable Antique. Gracias al agrupamiento, nos regresara una media por cada grupo creado, es decir, nos regresara el promedio de la antigüedad por vecindario.
%>%
ames_housing mutate(Antique = Year_Sold - Year_Remod_Add) %>%
group_by(Neighborhood) %>%
summarise(Mean_Antique = round(mean(Antique), 0))
## # A tibble: 28 × 2
## Neighborhood Mean_Antique
## <chr> <dbl>
## 1 Bloomington_Heights 2
## 2 Blueste 25
## 3 Briardale 35
## 4 Brookside 39
## 5 Clear_Creek 28
## 6 College_Creek 8
## 7 Crawford 29
## 8 Edwards 33
## 9 Gilbert 9
## 10 Green_Hills 14
## # ℹ 18 more rows
¡¡ RECORDAR !!
En este link se encuentra un buen resumen de las funciones básicas de dplyr
2.5 Orden y estructura
Un conjunto de datos puede ser representado de muchas maneras distintas y contener en todos los casos la misma información. Sin embargo, no todos los modos en que se presenta la información resulta óptimo para su procesamiento y análisis. Los conjuntos de datos ordenados serán más fáciles de trabajar y analizar.
Algunas de las características principales que presentan los conjuntos de datos ordenados son las siguientes:
Cada variable debe tener su propia columna.
Cada observación debe tener su propio renglón.
Cada valor debe tener su propia celda.
La figura anterior muestra la estructura de orden que debe tener un conjunto de datos. A pesar de que pueda parecer intuitivo y sencillo, en la práctica es considerable el número de conjuntos de datos desordenados. La limpieza y ordenamiento debe ser trabajado de forma impecable a fin de que puedan realizarse buenas prácticas. El tiempo de limpieza y ordenamiento varía mucho dependiendo de la dimensión del conjunto de datos.
Algunos de los principales problemas que pueden tener los conjuntos de datos no ordenados son:
- Una variable puede estar dispersa en múltiples columnas
- Una observación puede estar esparcida en múltiples renglones
La paquetería tidyr cuenta con funciones para resolver dichos problemas. Entre las principales funciones que tiene la paquetería, se encuentran pivot_longer(), pivot_wider(), separate() y unite(), mismas que se analizarán a continuación.
2.5.1 Pivote horizontal
La función pivot_wider() resulta muy útil a la hora de organizar los datos. Su función consiste en dispersar una variable clave en múltiples columnas.
Lo primero que se debe hacer para poder hacer uso de dicha función es instalar y cargar la librería.
El siguiente conjunto de datos contiene el número de localidades rurales y urbanas por municipio de la Ciudad de México. Como es posible observar, algunos municipios aparecen más de una vez en el marco de datos, esto se debe a que cada municipio puede tener ambos ámbitos, rural y urbano. Para hacer que el conjunto de datos sea ordenado, es necesario que cada observación aparezca una sola vez por renglón y cada una de las categorías (rural y urbano) de la variable “Ámbito” deberá ocupar el lugar de una columna.
El siguiente código muestra cómo convertir los datos no ordenados en un conjunto ordenado.
library(tidyr)
<- readRDS("data/loc_mun_cdmx.rds")
Resumen
%>% pivot_wider(
Resumen names_from = Ambito,
values_from = Total_localidades
)
## # A tibble: 16 × 3
## NOM_MUN Rural Urbano
## <chr> <int> <int>
## 1 Álvaro Obregón 3 1
## 2 La Magdalena Contreras 8 1
## 3 Cuajimalpa de Morelos 14 2
## 4 Tláhuac 31 5
## 5 Xochimilco 78 1
## 6 Tlalpan 95 4
## 7 Milpa Alta 187 10
## 8 Azcapotzalco NA 1
## 9 Benito Juárez NA 1
## 10 Coyoacán NA 1
## 11 Cuauhtémoc NA 1
## 12 Gustavo A. Madero NA 1
## 13 Iztacalco NA 1
## 14 Iztapalapa NA 1
## 15 Miguel Hidalgo NA 1
## 16 Venustiano Carranza NA 1
En la tabla actual existe ahora un y solo un registro por cada observación (nombre de municipio en este caso). El valor que le corresponde a cada una de las columnas creadas es la frecuencia absoluta de localidades que tienen la característica “Rural” y “Urbano” respectivamente.
Pero… ¿qué pasa cuando no existen todos los valores en ambas columnas? Si no se especifica la manera de llenar los datos faltantes, estos contendrán NAs. Siempre se puede elegir el caracter o número con el cual se imputan los datos faltantes.
%>%
fish_encounters pivot_wider(names_from = station, values_from = seen)
## # A tibble: 19 × 12
## fish Release I80_1 Lisbon Rstr Base_TD BCE BCW BCE2 BCW2 MAE MAW
## <fct> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
## 1 4842 1 1 1 1 1 1 1 1 1 1 1
## 2 4843 1 1 1 1 1 1 1 1 1 1 1
## 3 4844 1 1 1 1 1 1 1 1 1 1 1
## 4 4845 1 1 1 1 1 NA NA NA NA NA NA
## 5 4847 1 1 1 NA NA NA NA NA NA NA NA
## 6 4848 1 1 1 1 NA NA NA NA NA NA NA
## 7 4849 1 1 NA NA NA NA NA NA NA NA NA
## 8 4850 1 1 NA 1 1 1 1 NA NA NA NA
## 9 4851 1 1 NA NA NA NA NA NA NA NA NA
## 10 4854 1 1 NA NA NA NA NA NA NA NA NA
## 11 4855 1 1 1 1 1 NA NA NA NA NA NA
## 12 4857 1 1 1 1 1 1 1 1 1 NA NA
## 13 4858 1 1 1 1 1 1 1 1 1 1 1
## 14 4859 1 1 1 1 1 NA NA NA NA NA NA
## 15 4861 1 1 1 1 1 1 1 1 1 1 1
## 16 4862 1 1 1 1 1 1 1 1 1 NA NA
## 17 4863 1 1 NA NA NA NA NA NA NA NA NA
## 18 4864 1 1 NA NA NA NA NA NA NA NA NA
## 19 4865 1 1 1 NA NA NA NA NA NA NA NA
%>%
fish_encounters pivot_wider(names_from = station, values_from = seen, values_fill = 0)
## # A tibble: 19 × 12
## fish Release I80_1 Lisbon Rstr Base_TD BCE BCW BCE2 BCW2 MAE MAW
## <fct> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
## 1 4842 1 1 1 1 1 1 1 1 1 1 1
## 2 4843 1 1 1 1 1 1 1 1 1 1 1
## 3 4844 1 1 1 1 1 1 1 1 1 1 1
## 4 4845 1 1 1 1 1 0 0 0 0 0 0
## 5 4847 1 1 1 0 0 0 0 0 0 0 0
## 6 4848 1 1 1 1 0 0 0 0 0 0 0
## 7 4849 1 1 0 0 0 0 0 0 0 0 0
## 8 4850 1 1 0 1 1 1 1 0 0 0 0
## 9 4851 1 1 0 0 0 0 0 0 0 0 0
## 10 4854 1 1 0 0 0 0 0 0 0 0 0
## 11 4855 1 1 1 1 1 0 0 0 0 0 0
## 12 4857 1 1 1 1 1 1 1 1 1 0 0
## 13 4858 1 1 1 1 1 1 1 1 1 1 1
## 14 4859 1 1 1 1 1 0 0 0 0 0 0
## 15 4861 1 1 1 1 1 1 1 1 1 1 1
## 16 4862 1 1 1 1 1 1 1 1 1 0 0
## 17 4863 1 1 0 0 0 0 0 0 0 0 0
## 18 4864 1 1 0 0 0 0 0 0 0 0 0
## 19 4865 1 1 1 0 0 0 0 0 0 0 0
Ejercicio:
Realiza un pivote horizontal a través del ámbito y el total de localidades.
Rellena los datos faltantes con ceros.
En caso de que existan múltiples columnas que se desean dispersar mediante el pivote de una columna con múltiples categorías, es posible especificar tal re estructuración a través del siguiente código.
%>% arrange(NAME) us_rent_income
## # A tibble: 104 × 5
## GEOID NAME variable estimate moe
## <chr> <chr> <chr> <dbl> <dbl>
## 1 01 Alabama income 24476 136
## 2 01 Alabama rent 747 3
## 3 02 Alaska income 32940 508
## 4 02 Alaska rent 1200 13
## 5 04 Arizona income 27517 148
## 6 04 Arizona rent 972 4
## 7 05 Arkansas income 23789 165
## 8 05 Arkansas rent 709 5
## 9 06 California income 29454 109
## 10 06 California rent 1358 3
## # ℹ 94 more rows
%>%
us_rent_income pivot_wider(names_from = variable, values_from = c(estimate, moe))
## # A tibble: 52 × 6
## GEOID NAME estimate_income estimate_rent moe_income moe_rent
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 01 Alabama 24476 747 136 3
## 2 02 Alaska 32940 1200 508 13
## 3 04 Arizona 27517 972 148 4
## 4 05 Arkansas 23789 709 165 5
## 5 06 California 29454 1358 109 3
## 6 08 Colorado 32401 1125 109 5
## 7 09 Connecticut 35326 1123 195 5
## 8 10 Delaware 31560 1076 247 10
## 9 11 District of Columbia 43198 1424 681 17
## 10 12 Florida 25952 1077 70 3
## # ℹ 42 more rows
Ejercicio:
Agrupa los datos de localidades por ámbito
Agrega una columna con el porcentaje de localidades por alcaldía
Realiza un pivote horizontal sobre el ámbito y las variables numéricas de total de localidades y su respectivo porcentaje creado en el paso anterior
Ordena los registros de forma descendente de acuerdo con el total de localidades rural y urbano.
Adicionalmente, se puede especificar una función de agregación que operara antes de acomodar los datos en las respectivas columnas indicadas. Un ejemplo de funciones agregadas en la re estructuración de tabla se muestra a continuación, donde se muestra la media de los valores en las categorías tension y breaks.
<- warpbreaks[c("wool", "tension", "breaks")] %>% as_tibble()
warpbreaks warpbreaks
## # A tibble: 54 × 3
## wool tension breaks
## <fct> <fct> <dbl>
## 1 A L 26
## 2 A L 30
## 3 A L 54
## 4 A L 25
## 5 A L 70
## 6 A L 52
## 7 A L 51
## 8 A L 26
## 9 A L 67
## 10 A M 18
## # ℹ 44 more rows
%>%
warpbreaks pivot_wider(
names_from = wool,
values_from = breaks,
values_fn = ~mean(.x, na.rm = T)
)
## # A tibble: 3 × 3
## tension A B
## <fct> <dbl> <dbl>
## 1 L 44.6 28.2
## 2 M 24 28.8
## 3 H 24.6 18.8
Ejercicio:
Sobre el conjunto de localidades crea una variable con 5 categorías numéricas creadas aleatoriamente.
Elimina la columna con el nombre del municipio.
Crea un pivote horizontal con el ámbito, sumando el total de localidades y rellenando con ceros los datos faltantes.
Ordena las categorías numéricas de forma ascendente.
2.5.2 Pivote vertical
pivot_longer() es podría ser la función inversa de la anterior, se necesita comúnmente para ordenar los conjuntos de datos capturados en crudo, ya que a menudo no son capturados acorde a las mejores estructuras para facilitar el análisis.
El conjunto de datos relig_income almacena recuentos basados en una encuesta que (entre otras cosas) preguntó a las personas sobre su religión e ingresos anuales:
relig_income
## # A tibble: 18 × 11
## religion `<$10k` `$10-20k` `$20-30k` `$30-40k` `$40-50k` `$50-75k` `$75-100k`
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Agnostic 27 34 60 81 76 137 122
## 2 Atheist 12 27 37 52 35 70 73
## 3 Buddhist 27 21 30 34 33 58 62
## 4 Catholic 418 617 732 670 638 1116 949
## 5 Don’t k… 15 14 15 11 10 35 21
## 6 Evangel… 575 869 1064 982 881 1486 949
## 7 Hindu 1 9 7 9 11 34 47
## 8 Histori… 228 244 236 238 197 223 131
## 9 Jehovah… 20 27 24 24 21 30 15
## 10 Jewish 19 19 25 25 30 95 69
## 11 Mainlin… 289 495 619 655 651 1107 939
## 12 Mormon 29 40 48 51 56 112 85
## 13 Muslim 6 7 9 10 9 23 16
## 14 Orthodox 13 17 23 32 32 47 38
## 15 Other C… 9 7 11 13 13 14 18
## 16 Other F… 20 33 40 46 49 63 46
## 17 Other W… 5 2 3 4 2 7 3
## 18 Unaffil… 217 299 374 365 341 528 407
## # ℹ 3 more variables: `$100-150k` <dbl>, `>150k` <dbl>,
## # `Don't know/refused` <dbl>
¿Crees que ésta es la mejor estructura para la tabla? ¿Cómo imaginas que podría modificarse?
Este conjunto de datos contiene tres variables:
religión, almacenada en las filas
income repartidos entre los nombres de columna
count almacenado en los valores de las celdas.
Para ordenarlo usamos pivot_longer():
%>%
relig_income pivot_longer(cols = -religion, names_to = "income", values_to = "count")
## # A tibble: 180 × 3
## religion income count
## <chr> <chr> <dbl>
## 1 Agnostic <$10k 27
## 2 Agnostic $10-20k 34
## 3 Agnostic $20-30k 60
## 4 Agnostic $30-40k 81
## 5 Agnostic $40-50k 76
## 6 Agnostic $50-75k 137
## 7 Agnostic $75-100k 122
## 8 Agnostic $100-150k 109
## 9 Agnostic >150k 84
## 10 Agnostic Don't know/refused 96
## # ℹ 170 more rows
El primer argumento es el conjunto de datos para remodelar, relig_income.
El segundo argumento describe qué columnas necesitan ser reformadas. En este caso, es cada columna aparte de religion.
El names_to da el nombre de la variable que se creará a partir de los datos almacenados en los nombres de columna, es decir, ingresos.
Los values_to dan el nombre de la variable que se creará a partir de los datos almacenados en el valor de la celda, es decir, count. Ni la columna names_to ni la values_to existen en relig_income, por lo que las proporcionamos como cadenas de caracteres entre comillas.
2.5.3 Unión de columnas
Es común que en los conjuntos de datos exista información esparcida en distintas columnas que sería deseable (en muy pocas ocasiones) tenerlas en una sola columna. Algunos ejemplos de esta situación deseable son las fechas y claves geoestadísticas. La función unite() sirve para concatenar el contenido de columnas mediante un separador elegible.
Se usará la variable de la clave geoestadística de localidades del país como ejemplo.
El formato para las claves geoestadísticas para estado, municipio y localidad son claves alfanuméricas que contienen 2, 3 y 4 caracteres respectivamente. Es indispensable que al trabajar con claves geoestadísticas, las claves estén en su formato original. A continuación se hará la homologación de las claves para usar la función unite().
library(magrittr)
library(readxl)
library(stringr)
<- read_excel("data/Margin CONAPO.xlsx", sheet = "Margin CONAPO")
Datos Datos
## # A tibble: 107,458 × 21
## ENT NOM_ENT MUN NOM_MUN LOC NOM_LOC POB_TOT VPH ANAL10 SPRIM10
## <dbl> <chr> <dbl> <chr> <dbl> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 1 Aguascalient… 1 Aguasc… 1 Aguasc… 722250 184123 2.26 10.9
## 2 1 Aguascalient… 1 Aguasc… 96 Agua A… 37 11 17.9 48.1
## 3 1 Aguascalient… 1 Aguasc… 104 Ardill… 14 3 0 20
## 4 1 Aguascalient… 1 Aguasc… 106 Arella… 1382 255 5.60 24.7
## 5 1 Aguascalient… 1 Aguasc… 112 Bajío … 55 11 14.3 38.1
## 6 1 Aguascalient… 1 Aguasc… 114 Reside… 757 202 0 1.63
## 7 1 Aguascalient… 1 Aguasc… 120 Buenav… 935 217 10.7 29.5
## 8 1 Aguascalient… 1 Aguasc… 121 Cabeci… 184 44 4.55 32.6
## 9 1 Aguascalient… 1 Aguasc… 125 Cañada… 395 82 8.86 23.9
## 10 1 Aguascalient… 1 Aguasc… 126 Cañada… 509 123 4.75 19.6
## # ℹ 107,448 more rows
## # ℹ 11 more variables: SEXC10 <dbl>, SEE10 <dbl>, SAGUAE10 <dbl>,
## # PROM_OCC10 <dbl>, PISOTIE10 <dbl>, SREFRI10 <dbl>, IM_2010 <dbl>,
## # GM_2010 <chr>, IMC0A100 <dbl>, LUG_NAL <dbl>, LUG_EDO <dbl>
Como puede apreciarse en la tabla anterior, las claves de los campos Ent, Mun y Loc aparecen como numéricos. La estructura deseada para estos campos es de tipo alfanumérico y de longitud 2, 3 y 4 respectivamente. Para lograr esta estructura de datos, es necesario concatenar tantos ceros como sean necesarios antes del valor actual hasta lograr la longitud deseada.
<- Datos %>% select(ENT, MUN, LOC)
Datos2 $ENT %<>% str_pad(width = 2, side = "left", pad = "0")
Datos2$MUN %<>% str_pad(width = 3, side = "left", pad = "0")
Datos2$LOC %<>% str_pad(width = 4, side = "left", pad = "0")
Datos2
%>% head(5) Datos2
## # A tibble: 5 × 3
## ENT MUN LOC
## <chr> <chr> <chr>
## 1 01 001 0001
## 2 01 001 0096
## 3 01 001 0104
## 4 01 001 0106
## 5 01 001 0112
%>%
Datos2 unite("CVE_GEO", c("ENT","MUN","LOC"), sep="", remove = F) %>%
head(5)
## # A tibble: 5 × 4
## CVE_GEO ENT MUN LOC
## <chr> <chr> <chr> <chr>
## 1 010010001 01 001 0001
## 2 010010096 01 001 0096
## 3 010010104 01 001 0104
## 4 010010106 01 001 0106
## 5 010010112 01 001 0112
%>%
Datos2 unite("CVE_GEO", c("ENT","MUN","LOC"), sep="/",remove = T) %>%
head(5)
## # A tibble: 5 × 1
## CVE_GEO
## <chr>
## 1 01/001/0001
## 2 01/001/0096
## 3 01/001/0104
## 4 01/001/0106
## 5 01/001/0112
En el código anterior se carga la librería magrittr para poder hacer uso del operador pipe doble “%<>%”, que permite al igual que el operador pipe simple “%>%”, usar como argumento al primer elemento y mandarlo hacia la función definida, además de guardar el resultado final de la cadena de pipes en el argumento original que fue usado como insumo para la función. Es importante tener en cuenta que el dato será reescrito y no se podrá tener acceso a su información almacenada antes de ser usado el operador.
Es opción del programador poder eliminar las variables originales que crearon la nueva variable o mantenerlas en el conjunto de datos. Esta opción está disponible en el parámetro remove de la función unite().
2.5.4 Separador de columnas
Los procesos que se han visto hasta ahora han tenido cada uno una función inversa, este es también el caso de la función unite que tiene por objetivo unir dos o más columnas en una. La función separate() separará una columna en dos o más dependiendo de la longitud que tenga y de las especificaciones de separación.
<- Datos2 %>% unite("CVE_GEO", c("ENT","MUN","LOC"), sep = "", remove = T)
Datos_unite1 %>% head(5) Datos_unite1
## # A tibble: 5 × 1
## CVE_GEO
## <chr>
## 1 010010001
## 2 010010096
## 3 010010104
## 4 010010106
## 5 010010112
%>%
Datos_unite1 separate("CVE_GEO", c("EDO","MUNI","LOC"), sep = c(2, 5), remove=F) %>%
head(5)
## # A tibble: 5 × 4
## CVE_GEO EDO MUNI LOC
## <chr> <chr> <chr> <chr>
## 1 010010001 01 001 0001
## 2 010010096 01 001 0096
## 3 010010104 01 001 0104
## 4 010010106 01 001 0106
## 5 010010112 01 001 0112
Ya sea que se le especifique el número de caracteres que debe de contar para hacer un corte o que se le indique qué caracter debe identificar para hacer la separación, la función separate() puede dividir la columna indicada y crear nuevas a partir de la original.