Introducción a R y Rstudio para análisis de Datos sociales

1. Introducción

La siguiente introducción a R y Rstudio está realizada con un fin muy práctico: es para personas que no tienen idea de estadística ni de programación, y con mucho tesón buscan aprender ambas. Este pequeño documento se ha hecho (y se seguirá haciendo) de a poco y con ánimos de enseñar a quienes necesitan aprender por trabajo o por curiosidad intelectual.

Antes que todo: R y Rstudio son cosas completamente diferentes. R es un lenguaje de programación, como C, C++, Python, y Rstudio es una interfaz gráfica con la cual puedes trabajar en lenguaje R. Aunque actualmente RStudio permite trabajar en otros lenguajes como C++, Python y SQL, sigue siendo el IDE (Interface Development Envirorment) preferido para R.

1.1 Instalando R y RStudio

Debemos instalar dos cosas distintas. La primera es instalar R desde este link. Buscamos el sistema operativo que corresponde al computador que estás utilizando.

Recuadro de muestra que se abrirá al entrar a la zona de descargas de R

Recuadro de muestra que se abrirá al entrar a la zona de descargas de R

Luego de descargarlo, debes seguir los pasos clásicos de instalación de programas en tu sistema operativo.

Luego de ello, instalamos RStudio desde este link, descargando el instalador que necesitamos según el sistema operativo que corresponde:


Página web de Rstudio/Posit con los distintos instalasdores según sistema operativo

Página web de Rstudio/Posit con los distintos instalasdores según sistema operativo


1.2 Analizando el entorno

Una de las grandes ventajas que tiene el entorno de RStudio es que tiene una gran cantidad de funcionalidades. acá sólamente explicaremos la estructura básica para comenzar a trabajar. Una revisión exhaustiva sólo se hará con el tiempo.

Entorno de RStudio

Entorno de RStudio

Hablaremos por cada uno de los cuadrantes marcados:

1)Script (Source): En la esquina superior izquierda tenemos la ventana con el script de lo que queremos programar. un script es literalmente un guión, una forma de registrar el código que vamos a ejecutar para lograr cierto resultado. Para guardar un script, bajos a la esquina superior izquierda, donde aparece el símbolo de un disquette (espero que eso sea explicativo) y guardamos el archivo. La extensión de los scripts de r terminan en “.R”

Es de extrema necesidad aprender a ser ordenado en el código, comentando secciones utilizando # para que tú en el futuro y tus colegas comprendan el orden de trabajo y el código en específico. A medida que se aprendan más habilidades, más limpio quedarán los scripts, pero quizás lleges a un nivel muy alto donde no todos van a poder entenderlo, por lo que es importante comentarlos.

Es muy recomendable usar scripts pequeños, ya que leer scripts muy largos es tedioso y confuso, y tener varios scripts pequeños y bien nombrados es preferible a un solo archivo largo.

2) Entorno (Environments): La esquina superior derecha es una ventana con una serie de pestañas, dentro de las que destacaremos a futuro dos: el entorno o “environment” y la pestaña “Git”. Basta por ahora comprender que el entorno es una pestaña que enlista todos los objetos que están cargados para poder ser utilizados, sean bases de datos, listas, strings, funciones o matrices.

3) Consola: Este entorno permite ver dos elementos básicos: permite poder hacer las mismas cosas que se hacen en el script, pero sin dejar registro lógico legible para los demás, por lo que no es recomentable. Por otra parte, nos entrega algo que veremos siempre: los resultados del procesamiento de las funciones (veremos los resultados de tablas, porcentajes, y a futuro algo muy útil como los “summary”, pero también los errores, que debemos aprender a leer y buscar soluciones.

Otra aplicación útil para mirar ahí (ya que no necesida dejar registro en el script) es observar la ayuda y manuales de cada paquete o funciones específicas. Basta simplemente escribir ? antes de la función, y de desplegará a la derecha ayuda sobre el manual.

Vea el ejemplo analizando la función ?dplyr::group_by del paquete dplyr.

4) Output: La esquina inferior derecha tiene una serie de pestañas relevantes que veremos desde un comienzo. Primero, está la pestaña “Files” donde muestra todos los archivos del proyecto en que estamos trabajando(es decir, muestra el contenido de la carpeta). La pestaña “Packages” es la lista de paquetes que están instalador en el computador (no necesariamente activos). “Plots”, que es una pequeña visualización sobre los gráficos que se están realizando, y finalmente “Help” que es el visualizador de los manuales de ayuda de cada paquete y funciones.

Con esto listo ¡es momento de empezar a inspeccionar los datos!

dato: Si te gustan las interfaces de otros colores más que el blanco, puedes editarla yendo a tools -> global options -> Appareance -> eliges tu tema preferido.


2. Preparación de datos

2.1 Carga de paquetes en RStudio

Lo primero que debes saber es cómo cargar paquetes. los paquetes son colecciones de funciones que permiten hacer distintas acciones matemáticas, estadísticas, etc, y que nos van a ayudar a agrupar, filtrar, reordenar, categorizar y calcular diversas cosas.

La sintaxis para instalar paquetes es install.packages("nombre_paquete", dependencies = T) que en este caso significa “instala el paquete llamado [nombre_paquete]” y dependencies = T significa que instalará librerías adicionales para el funcionamiento del paquete, de manera de asegurar su uso.

Luego usando la función library() llamaremos a dicho paquete (¡instalarlo no es suficiente!). “llamar un paquete” es básicamente el principio por el cual activamos sus funciones en el script. Los paquetes se instalan en el computador y saldrán disponible en la pestaña “Packages” en la esquina inferior derecha, pero los paquetes se deben llamar en cada script.

Haremos un ejemplo instalando paquetes básicos que usaremos más adelante:

install.packages("readxl", dependencies = T)
install.packages("tidyverse", dependencies = T, INSTALL_opts = '--no-lock')
install.packages("haven", dependencies = T)
install.packages("car", dependencies = T)

En este caso instalamos los paquetes readxl, tidyverse,haven, y car. Se agregó otro argumento a tidyverse llamado INSTALL_opts para corregir un error temporal.

library(readxl)
library(tidyverse)
library(haven)

## leeremos la base de datos de la cep

cep <-read.csv("bbdd/encuesta_cep/base_87.csv")

También es probable que el csv no carge con más de una sola variable, pues algunos archivos csv las columnas están cortadas con puntos y coma. Para ello usamos la función read.csv2.

Veremos que se crea el objeto llamado “cep”, que es el dataframe de la encuesta con 2915 observaciones (filas) y 2019 variables (columnas):

Esquina superior derecha con el entorno de variables, funciones, bases de datos, y listas

Esquina superior derecha con el entorno de variables, funciones, bases de datos, y listas

¿Qué pasa cuando son otros formatos como el de spss y stata? Una de las ventajas de RStudio es que puedes abrir diversos formatos de bases de datos. Algunos están en los paquetes base, y otras veces podemos acceder a ellos con paquetes específicos. Te dejo a continuación la lista de formas de abrirlo, con sus respectivos paquetes.

## abrir con excel
cep_excel <-readxl::read_excel("bbdd/encuesta_cep/base_87.xlsx")


## para archivos de STATA

cep_stata <-haven::read_dta("bbdd/encuesta_cep/base_87.dta")

## para archivos SPSS 

cep_spss <-haven::read_spss("bbdd/encuesta_cep/base_87.sav")

## para archivos de R 

#cep_R <-readRDS("bbdd/encuesta_cep/base_87.rds")

en R, el significado de :: indica a qué paquete pertecene la función que estamos llamando. En este sentido readxl::read_excel significa “la función read_excel, del paquete readxl”. ¿Para qué se utiliza esto? para diferenciar funciones que se llaman iguales, pero hacen cosas diferentes y son de paquetes distintos.

2.2 inspección de datos en R

Ya con datos cargados, tenemos que aprender algunas funciones para analizar la naturaleza de los datos: el tamaño de la base de datos, el tipo de datos que hay por columna, los nombres de las variables y los nombres de cada categoría de las variables. Para eso usaremos las funciones names(),glimpse(),view() y class().

2.2.1 names()

Esta función entrega todos los nombres de cada variable o columna de nuestro data frame. Si aplicamos esto a la encuesta CEP Nº87 obtenemos lo siguiente:

names(cep)
##   [1] "X"                 "info_enc_30"       "info_enc_30_otro" 
##   [4] "mesp_112"          "mesp_113"          "esp_1"            
##   [7] "esp_8"             "esp_9"             "esp_69"           
##  [10] "esp_114_a"         "esp_114_b"         "esp_4"            
##  [13] "esp_49"            "esp_50"            "esp_55_a"         
##  [16] "esp_55_b"          "esp_115"           "mesp_116"         
##  [19] "mesp_117"          "mesp_117_1"        "mesp_117_2"       
##  [22] "esp_40_a"          "esp_40_b"          "esp_87"           
##  [25] "esp_88"            "iden_pol_2"        "democracia_21"    
##  [28] "democracia_19"     "pobreza_62"        "pobreza_63"       
##  [31] "medio_ambiente_37" "mtf_42_d"          "mtf_43_b"         
##  [34] "interes_pol_1_b"   "esp_44"            "confianza_6_c"    
##  [37] "confianza_6_j"     "confianza_6_d"     "confianza_6_h"    
##  [40] "confianza_6_i"     "confianza_6_k"     "confianza_6_o"    
##  [43] "confianza_6_p"     "confianza_6_r"     "confianza_6_a"    
##  [46] "confianza_6_b"     "confianza_6_g"     "confianza_6_y"    
##  [49] "confianza_6_m"     "confianza_6_ab"    "confianza_6_ac"   
##  [52] "confianza_6_ad"    "confianza_6_ae"    "confianza_6_af"   
##  [55] "esp_89_a"          "esp_89_b"          "esp_89_c"         
##  [58] "esp_120_a"         "esp_120_b"         "esp_120_c"        
##  [61] "confianza_8_a"     "mesp_90_1"         "mesp_90_2"        
##  [64] "mesp_90_3"         "mesp_11_q"         "mesp_11_b"        
##  [67] "mesp_11_c"         "mesp_11_p"         "mesp_11_r"        
##  [70] "constitucion_5_a"  "constitucion_5_b"  "constitucion_5_c" 
##  [73] "esp_91_a"          "esp_91_b"          "esp_91_d"         
##  [76] "esp_91_e"          "esp_91_f"          "esp_122"          
##  [79] "mesp_36_a"         "mesp_36_b"         "mesp_36_e"        
##  [82] "mesp_36_f"         "nmesp_36_aa"       "nmesp_36_bb"      
##  [85] "nmesp_36_ee"       "nmesp_36_ff"       "esp_92_a"         
##  [88] "esp_92_b"          "esp_92_c"          "esp_92_d"         
##  [91] "esp_92_e"          "esp_92_f"          "esp_92_g"         
##  [94] "esp_93_a"          "esp_93_b"          "esp_93_c"         
##  [97] "esp_93_d"          "esp_93_e"          "esp_93_f"         
## [100] "esp_93_g"          "esp_126_1"         "esp_126_2"        
## [103] "percepcion_1_a"    "percepcion_1_b"    "percepcion_1_c"   
## [106] "esp_127_1"         "esp_127_2"         "esp_127_3"        
## [109] "esp_127_4"         "esp_94_a"          "esp_94_b"         
## [112] "esp_94_c"          "esp_94_d"          "esp_94_e"         
## [115] "esp_94_f"          "esp_94_g"          "esp_94_h"         
## [118] "esp_94_i"          "esp_94_j"          "esp_129"          
## [121] "esp_130"           "esp_95"            "esp_96_1"         
## [124] "esp_96_2"          "esp_97"            "esp_131"          
## [127] "esp_132"           "esp_133_a"         "esp_133_b"        
## [130] "esp_134"           "esp_135_a"         "esp_135_b"        
## [133] "esp_136"           "esp_137_a"         "esp_137_b"        
## [136] "esp_138_a"         "esp_138_b"         "esp_139"          
## [139] "esp_140"           "esp_141_a"         "esp_141_b"        
## [142] "esp_142_a"         "esp_142_b"         "esp_142_c"        
## [145] "esp_143_a"         "esp_143_b"         "esp_143_c"        
## [148] "esp_143_d"         "uesp_143_e"        "resp_143_e"       
## [151] "esp_143_f"         "esp_111_d"         "rol_gobierno_27"  
## [154] "esp_17"            "esp_145_1"         "esp_145_2"        
## [157] "esp_146_a"         "esp_146_b"         "esp_146_c"        
## [160] "esp_146_d"         "esp_147_a"         "esp_147_b"        
## [163] "esp_147_c"         "esp_147_d"         "esp_147_e"        
## [166] "esp_148_a"         "esp_148_b"         "esp_148_c"        
## [169] "esp_148_d"         "esp_148_e"         "esp_148_f"        
## [172] "esp_148_g"         "esp_148_h"         "esp_148_i"        
## [175] "esp_148_j"         "sexo"              "edad"             
## [178] "estado_civil"      "info_enc_29"       "info_enc_23"      
## [181] "esc_nivel_1"       "info_enc_12_b"     "mesp_73"          
## [184] "mesp_149"          "mesp_150"          "mesp_151"         
## [187] "rmesp_152"         "esp_153"           "info_enc_1_a_1"   
## [190] "info_enc_1_a_2"    "info_enc_57"       "info_hogar_17"    
## [193] "religion_82"       "religion_2"        "bienestar_21"     
## [196] "interes_pol_2_c"   "interes_pol_2_d"   "interes_pol_2_e"  
## [199] "info_hogar_1_a"    "info_hogar_2_b"    "info_hogar_2_c"   
## [202] "info_hogar_32"     "info_hogar_33"     "info_hogar_21_n"  
## [205] "info_enc_60"       "info_enc_52"       "info_enc_54"      
## [208] "gse"               "muestra"           "zona_u_r"         
## [211] "id_region"         "region"            "id_estrato"       
## [214] "estrato"           "encuesta"          "encuesta_a"       
## [217] "encuesta_m"        "secu"              "pond"


Estos nombres nos parecen algo incomprensibles pues están codificados de una forma particular. para entenderlos es necesario que revises el libro de códigos que entrega la CEP para saber cuál es cada variable, por lo que un trabajo indispensable para cualquiera es comprender bien la base de datos, así a futuro eligiremos las variables de interés y no todo el dataframe. Esto no es exclusivo de la CEP, sino que de prácticamente la totalidad de bases de datos públicas.

2.2.2 glimpse()

glimpse(cep)
## Rows: 2,915
## Columns: 219
## $ X                 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1…
## $ info_enc_30       <int> 5, 5, 5, 5, 5, 5, 11, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, …
## $ info_enc_30_otro  <int> NA, NA, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, N…
## $ mesp_112          <int> 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, 2, 1…
## $ mesp_113          <int> NA, 9, NA, NA, 1, 2, 4, 99, NA, NA, NA, 4, NA, NA, 9…
## $ esp_1             <int> 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2…
## $ esp_8             <int> 3, 2, 3, 5, 5, 4, 2, 3, 3, 1, 5, 5, 3, 2, 2, 3, 3, 1…
## $ esp_9             <int> 1, 3, 7, 5, 1, 7, 7, 88, 7, 7, 7, 1, 7, 1, 7, 7, 7, …
## $ esp_69            <int> 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1…
## $ esp_114_a         <int> 2, 1, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2…
## $ esp_114_b         <int> NA, 1, NA, NA, 2, NA, 2, NA, NA, NA, NA, NA, NA, 1, …
## $ esp_4             <int> NA, 2, NA, NA, 5, NA, 2, NA, NA, NA, NA, NA, NA, 3, …
## $ esp_49            <int> NA, 1, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA, NA, 1,…
## $ esp_50            <int> NA, 1, NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, 6,…
## $ esp_55_a          <int> NA, 3, NA, NA, 1, NA, 1, NA, NA, NA, NA, NA, NA, 1, …
## $ esp_55_b          <int> 1, NA, 1, 1, NA, 1, NA, 1, 1, 1, 1, 1, 1, NA, 1, 1, …
## $ esp_115           <int> 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2…
## $ mesp_116          <int> 5, 1, 5, 5, 4, 5, 2, 5, 5, 5, 4, 5, 5, 5, 5, 5, 3, 5…
## $ mesp_117          <int> 2, 2, 3, 3, 3, 3, 2, 2, 3, 2, 2, 3, 3, 3, 3, 2, 2, 3…
## $ mesp_117_1        <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ mesp_117_2        <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ esp_40_a          <int> 3, 2, 4, 10, 10, 4, 5, 4, 4, 10, 9, 4, 2, 3, 4, 4, 4…
## $ esp_40_b          <int> 2, 3, 10, 4, 9, 9, 4, 1, 3, 8, 10, 3, 3, 10, NA, 1, …
## $ esp_87            <int> 10, 10, 4, 10, 6, 4, 8, 4, 6, 7, 5, 10, 1, 1, 5, 9, …
## $ esp_88            <int> 2, 2, 88, 3, 3, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 2, 2, …
## $ iden_pol_2        <int> 1, 4, 3, 6, 5, 4, 88, 6, 5, 99, 6, 5, 3, 5, 5, 88, 5…
## $ democracia_21     <int> 2, 2, 3, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 3, 1…
## $ democracia_19     <int> 1, 1, 10, 1, 10, 5, 7, 8, 4, 99, 10, 10, 10, 10, 5, …
## $ pobreza_62        <int> 1, 6, 5, 10, 6, 5, 9, 6, 8, 7, 6, 7, 10, 10, 8, 10, …
## $ pobreza_63        <int> 10, 7, 6, 5, 7, 5, 10, 6, 4, 5, 7, 7, 10, 10, 7, 10,…
## $ medio_ambiente_37 <int> 9, 8, 1, 1, 1, 3, 1, 1, 1, 3, 1, 6, 1, 1, 5, 1, 1, 4…
## $ mtf_42_d          <int> 1, 2, 3, 5, 5, 4, 2, 4, 5, 1, 4, 3, 2, 2, 4, 2, 5, 4…
## $ mtf_43_b          <int> 1, 4, 4, 5, 5, 5, 2, 4, 5, 1, 5, 3, 2, 3, 4, 5, 5, 4…
## $ interes_pol_1_b   <int> 5, 5, 5, 3, 3, 3, 4, 2, 4, 5, 4, 5, 3, 5, 1, 4, 3, 4…
## $ esp_44            <int> 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1…
## $ confianza_6_c     <int> 1, 3, 4, 3, 1, 2, 3, 3, 3, 4, 2, 3, 2, 3, 3, 2, 3, 3…
## $ confianza_6_j     <int> 3, 4, 4, 3, 2, 3, 4, 3, 3, 4, 3, 3, 2, 3, 3, 2, 3, 4…
## $ confianza_6_d     <int> 1, 3, 3, 3, 1, 3, 4, 2, 1, 4, 3, 3, 2, 3, 3, 3, 3, 3…
## $ confianza_6_h     <int> 1, 4, 3, 3, 1, 3, 3, 4, 2, 4, 2, 3, 4, 2, 2, 2, 4, 3…
## $ confianza_6_i     <int> 3, 3, 3, 3, 2, 3, 4, 3, 2, 4, 3, 3, 2, 3, 3, 2, 3, 3…
## $ confianza_6_k     <int> 4, 3, 4, 3, 1, 3, 3, 3, 2, 4, 3, 3, 3, 3, 3, 3, 3, 3…
## $ confianza_6_o     <int> 1, 2, 3, 3, 2, 3, 3, 3, 2, 4, 2, 3, 2, 3, 3, 2, 3, 3…
## $ confianza_6_p     <int> 4, 3, 3, 3, 1, 3, 2, 3, 2, 4, 3, 3, 2, 3, 1, 88, 3, …
## $ confianza_6_r     <int> 1, 3, 3, 2, 1, 1, 1, 2, 2, 4, 2, 3, 2, 3, 3, 2, 3, 3…
## $ confianza_6_a     <int> 4, 4, 4, 3, 3, 4, 4, 4, 3, 4, 3, 3, 3, 3, 3, 88, 2, …
## $ confianza_6_b     <int> 4, 4, 4, 4, 1, 1, 4, 4, 3, 4, 3, 1, 2, 2, 3, 2, 4, 4…
## $ confianza_6_g     <int> 1, 3, 3, 3, 3, 2, 1, 3, 2, 4, 2, 3, 88, 3, 1, 3, 3, …
## $ confianza_6_y     <int> 4, 3, 4, 3, 1, 2, 2, 3, 3, 4, 2, 3, 2, 3, 3, 2, 3, 3…
## $ confianza_6_m     <int> 2, 2, 1, 2, 1, 3, 1, 1, 2, 4, 2, 3, 2, 3, 1, 2, 2, 3…
## $ confianza_6_ab    <int> 3, 4, 4, 3, 2, 3, 4, 3, 3, 4, 3, 3, 2, 3, 3, 3, 3, 3…
## $ confianza_6_ac    <int> 1, 4, 3, 4, 3, 4, 4, 3, 3, 4, 2, 3, 3, 3, 3, 2, 3, 2…
## $ confianza_6_ad    <int> 2, 2, 1, 88, 2, 2, 1, 3, 3, 4, 2, 3, 2, 3, 3, 2, 4, …
## $ confianza_6_ae    <int> 2, 4, 1, 4, 1, 2, 4, 3, 3, 4, 2, 3, 2, 3, 3, 3, 4, 3…
## $ confianza_6_af    <int> 1, 2, 2, 2, 1, 2, 2, 3, 2, 4, 2, 3, 2, 3, 3, 88, 4, …
## $ esp_89_a          <int> 88, 1, 88, 88, 88, 1, 88, 1, 88, 88, 88, 88, 88, 88,…
## $ esp_89_b          <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ esp_89_c          <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ esp_120_a         <int> NA, 1, NA, NA, NA, 2, NA, 3, NA, NA, NA, NA, NA, NA,…
## $ esp_120_b         <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ esp_120_c         <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ confianza_8_a     <int> 3, 4, 4, 4, 4, 4, 4, 4, 2, 3, 3, 4, 1, 4, 3, 4, 3, 1…
## $ mesp_90_1         <int> 88, 99, 88, 88, 1, 1, 88, 99, 88, 88, 88, 88, 88, 88…
## $ mesp_90_2         <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ mesp_90_3         <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ mesp_11_q         <int> 3, 3, 3, 4, 88, 2, 3, 3, 3, 88, 88, 1, 2, 2, 3, 88, …
## $ mesp_11_b         <int> 7, 1, 7, 2, 2, 7, 1, 88, 7, 6, 6, 1, 2, 88, 7, 88, 7…
## $ mesp_11_c         <int> 7, 1, 7, 2, 1, 7, 1, 88, 7, 6, 6, 1, 2, 2, 7, 88, 7,…
## $ mesp_11_p         <int> 7, 1, 7, 2, 2, 7, 1, 2, 7, 6, 6, 1, 2, 2, 7, 88, 7, …
## $ mesp_11_r         <int> 7, 1, 7, 2, 1, 7, 1, 88, 7, 6, 6, 1, 2, 3, 7, 88, 7,…
## $ constitucion_5_a  <int> 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2…
## $ constitucion_5_b  <int> NA, 1, NA, NA, NA, 4, 88, 88, NA, NA, NA, 1, NA, NA,…
## $ constitucion_5_c  <int> 3, NA, 3, 88, 3, NA, NA, NA, 3, 99, 99, NA, 88, 5, 8…
## $ esp_91_a          <int> 1, 6, 4, 3, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6…
## $ esp_91_b          <int> 6, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6…
## $ esp_91_d          <int> 6, 6, 6, 5, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6…
## $ esp_91_e          <int> 4, 6, 8, 5, 5, 5, 6, 6, 6, 6, 3, 6, 6, 6, 6, 6, 5, 6…
## $ esp_91_f          <int> 6, 5, 5, 4, 5, 4, 6, 5, 5, 6, 5, 6, 6, 6, 6, 6, 4, 5…
## $ esp_122           <int> 1, 8, 8, 4, 7, 7, NA, 2, 5, NA, 4, NA, NA, NA, NA, N…
## $ mesp_36_a         <int> 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ mesp_36_b         <int> 1, 1, 1, 5, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ mesp_36_e         <int> 1, 1, 8, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ mesp_36_f         <int> 1, 1, 8, 5, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 1, 1…
## $ nmesp_36_aa       <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ nmesp_36_bb       <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ nmesp_36_ee       <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ nmesp_36_ff       <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ esp_92_a          <int> 1, 1, 2, 4, 4, 5, 5, 3, 4, 5, 3, 2, 3, 2, 4, 5, 3, 4…
## $ esp_92_b          <int> 1, 5, 5, 3, 4, 5, 5, 2, 5, 5, 5, 2, 3, 2, 3, 5, 5, 4…
## $ esp_92_c          <int> 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1…
## $ esp_92_d          <int> 1, 1, 1, 2, 3, 1, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2…
## $ esp_92_e          <int> 1, 1, 1, 3, 1, 3, 1, 2, 1, 1, 2, 2, 1, 2, 1, 4, 1, 3…
## $ esp_92_f          <int> 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1…
## $ esp_92_g          <int> 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1…
## $ esp_93_a          <int> NA, NA, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,…
## $ esp_93_b          <int> NA, 1, 3, 2, 1, 2, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, …
## $ esp_93_c          <int> NA, NA, NA, 2, NA, NA, NA, 1, NA, NA, NA, 1, NA, 1, …
## $ esp_93_d          <int> NA, NA, NA, 2, 1, NA, NA, 3, 1, NA, 1, 1, NA, 1, NA,…
## $ esp_93_e          <int> NA, NA, NA, 1, NA, 1, NA, 1, NA, NA, 1, 1, NA, 1, NA…
## $ esp_93_f          <int> NA, NA, NA, 1, NA, NA, NA, 1, NA, NA, NA, 1, NA, 1, …
## $ esp_93_g          <int> NA, NA, NA, 1, NA, NA, NA, 1, NA, NA, NA, 1, NA, 1, …
## $ esp_126_1         <int> 1, 99, 1, 1, 1, 1, 1, 1, 88, 1, 1, 88, 88, 88, 1, 1,…
## $ esp_126_2         <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, 2, 2, NA, NA, NA…
## $ percepcion_1_a    <int> 7, 1, 7, 16, 3, 1, 11, 10, 10, 7, 10, 7, 3, 1, 17, 1…
## $ percepcion_1_b    <int> 11, 6, 2, 7, 10, 5, 13, 5, 17, 6, 7, 6, NA, 11, 3, 3…
## $ percepcion_1_c    <int> 6, 10, 3, 8, 7, 16, 17, 1, 5, 16, 5, NA, NA, 6, 1, 1…
## $ esp_127_1         <int> 88, 99, 88, 1, 1, 88, 1, 1, 88, 88, 1, 88, 88, 88, 1…
## $ esp_127_2         <int> NA, NA, NA, 2, 2, NA, 2, 2, NA, NA, 2, NA, NA, NA, 2…
## $ esp_127_3         <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ esp_127_4         <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ esp_94_a          <int> 1, 4, 4, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1…
## $ esp_94_b          <int> 1, 4, 3, 2, 3, 1, 2, 2, 2, 3, 1, 1, 3, 3, 4, 8, 1, 1…
## $ esp_94_c          <int> 3, 3, 3, 8, 2, 2, 1, 2, 3, 1, 1, 1, 3, 3, 3, 8, 2, 2…
## $ esp_94_d          <int> 1, 3, 4, 2, 3, 2, 2, 2, 3, 1, 3, 1, 4, 3, 3, 3, 3, 2…
## $ esp_94_e          <int> 2, 3, 4, 8, 3, 2, 1, 3, 2, 4, 4, 1, 2, 3, 4, 2, 3, 3…
## $ esp_94_f          <int> 1, 3, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 3, 1, 3, 1, 2…
## $ esp_94_g          <int> 1, 4, 4, 2, 1, 1, 8, 2, 3, 1, 1, 1, 3, 3, 4, 2, 2, 2…
## $ esp_94_h          <int> 3, 3, 4, 8, 1, 1, 1, 1, 3, 1, 1, 1, 2, 3, 1, 1, 1, 2…
## $ esp_94_i          <int> 3, 4, 8, 8, 3, 2, 1, 2, 3, 1, 3, 1, 3, 3, 4, 1, 1, 3…
## $ esp_94_j          <int> 3, 3, 8, 8, 3, 1, 1, 2, 4, 3, 3, 1, 4, 3, 4, 2, 1, 2…
## $ esp_129           <int> 1, 2, 3, 3, 3, 3, 2, 2, 2, 1, 2, 1, 1, 4, 5, 1, 2, 3…
## $ esp_130           <int> 5, 5, 4, 4, 3, 5, 5, 4, 4, 5, 5, 5, 5, 5, 1, 3, 5, 3…
## $ esp_95            <int> 9, 1, 8, 10, 6, 5, 10, 5, 4, 1, 7, 7, 1, 1, 10, 9, 7…
## $ esp_96_1          <int> 88, 1, 1, 88, 1, 1, 88, 1, 88, 88, 1, 88, 1, 88, 1, …
## $ esp_96_2          <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 2, NA, 2, NA…
## $ esp_97            <int> 1, 1, 3, 3, 3, 3, 6, 1, 3, 3, 5, 1, 1, 1, 6, 3, 1, 7…
## $ esp_131           <int> 2, 2, 3, 3, 3, 1, 2, 1, 2, 2, 1, 1, 1, 2, 3, 1, 1, 3…
## $ esp_132           <int> 1, 99, NA, NA, NA, 88, 88, 1, 88, 88, 1, 88, 88, 1, …
## $ esp_133_a         <int> 1, 2, NA, NA, NA, 3, 5, 1, 3, 5, 5, 88, 4, 3, NA, 3,…
## $ esp_133_b         <int> 3, NA, NA, NA, NA, 1, NA, 3, 1, NA, 2, NA, NA, NA, N…
## $ esp_134           <int> 1, 1, 3, 4, 2, 2, 2, 3, 3, 2, 2, 2, 3, 5, 5, 2, 2, 3…
## $ esp_135_a         <int> 2, 7, NA, NA, 7, 9, 7, NA, NA, 5, 3, 7, NA, NA, NA, …
## $ esp_135_b         <int> 3, NA, NA, NA, 2, 10, NA, NA, NA, 7, 11, 4, NA, NA, …
## $ esp_136           <int> 1, 1, 2, 4, 4, 5, 2, 4, 4, 1, 4, 88, 3, 5, 5, 2, 5, …
## $ esp_137_a         <int> 1, 2, 3, 3, 3, 3, 3, 4, 2, 2, 3, 2, 2, 4, 4, 5, 5, 4…
## $ esp_137_b         <int> 1, 2, 3, 3, 2, 3, 3, 4, 3, 2, 2, 2, 2, 4, 2, 1, 4, 3…
## $ esp_138_a         <int> 1, 2, 2, 2, 3, 3, 3, 1, 2, 1, 3, 2, 2, 3, 3, 3, 3, 3…
## $ esp_138_b         <int> 1, 2, 2, 3, 2, 1, 2, 1, 3, 1, 3, 2, 2, 3, 3, 3, 3, 2…
## $ esp_139           <int> 1, 1, 88, 88, 1, 1, 1, 1, 88, 99, 1, 88, 99, 1, 1, 1…
## $ esp_140           <int> 1, 1, 88, 88, 1, 88, 1, 1, 1, 99, 88, 88, 99, 88, 88…
## $ esp_141_a         <int> 1, 1, 3, 1, 1, 3, 1, 1, 2, 8, 6, 1, 3, 1, 1, 6, 1, 1…
## $ esp_141_b         <int> 6, NA, 8, 4, 3, 1, NA, 9, 9, 9, NA, 2, NA, 7, NA, 1,…
## $ esp_142_a         <int> 6, 6, 8, 5, 2, 5, 6, 2, 5, 6, 6, 6, 6, 6, 6, 6, 5, 6…
## $ esp_142_b         <int> 6, 6, 6, 4, 4, 2, 6, 2, 4, 6, 6, 5, 6, 6, 6, 6, 6, 6…
## $ esp_142_c         <int> 2, 6, 2, 4, 4, 1, 6, 1, 4, 6, 6, 6, 6, 6, 6, 6, 5, 4…
## $ esp_143_a         <int> 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2…
## $ esp_143_b         <int> 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2…
## $ esp_143_c         <int> 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2…
## $ esp_143_d         <int> 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2…
## $ uesp_143_e        <int> 7, NA, 7, 2, 7, 7, 7, 2, 7, 2, 7, NA, NA, 2, NA, NA,…
## $ resp_143_e        <int> NA, 2, NA, NA, NA, NA, NA, NA, NA, NA, NA, 2, 2, NA,…
## $ esp_143_f         <int> 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
## $ esp_111_d         <int> 1, 2, 7, 3, 1, 7, 7, 4, 7, 4, 2, 4, 3, 3, 1, 2, 4, 2…
## $ rol_gobierno_27   <int> 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2…
## $ esp_17            <int> 3, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3…
## $ esp_145_1         <int> NA, 99, 1, 1, NA, NA, NA, NA, NA, 1, 1, NA, NA, NA, …
## $ esp_145_2         <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ esp_146_a         <int> 1, 4, 5, 5, 5, 4, 5, 4, 3, 3, 3, 5, 5, 3, 4, 3, 5, 3…
## $ esp_146_b         <int> 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5…
## $ esp_146_c         <int> 1, 4, 4, 5, 3, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 4, 5, 5…
## $ esp_146_d         <int> 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 5, 5, 3, 5, 5…
## $ esp_147_a         <int> 1, 4, 2, 3, 3, 2, 8, 5, 3, 5, 3, 5, 5, 5, 1, 3, 4, 4…
## $ esp_147_b         <int> 1, 5, 5, 4, 5, 4, 5, 5, 5, 1, 5, 5, 5, 5, 2, 3, 5, 3…
## $ esp_147_c         <int> 1, 4, 5, 3, 5, 4, 5, 5, 5, 1, 5, 5, 5, 5, 2, 3, 2, 3…
## $ esp_147_d         <int> 1, 5, 4, 3, 4, 4, 5, 5, 3, 1, 5, 5, 3, 1, 2, 3, 5, 3…
## $ esp_147_e         <int> 3, 5, 5, 4, 3, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 4, 5, 3…
## $ esp_148_a         <int> 5, 5, 4, 5, 1, 4, 5, 5, 2, 1, 5, 5, 5, 5, 5, 4, 2, 5…
## $ esp_148_b         <int> 5, 5, 5, 5, 5, 5, 2, 5, 5, 1, 5, 5, 5, 5, 5, 4, 5, 5…
## $ esp_148_c         <int> 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 8, 4, 5…
## $ esp_148_d         <int> 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 4, 5, 5…
## $ esp_148_e         <int> 5, 5, 4, 5, 5, 5, 5, 5, 4, 1, 5, 5, 5, 5, 5, 2, 4, 5…
## $ esp_148_f         <int> 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 3, 5, 5…
## $ esp_148_g         <int> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5…
## $ esp_148_h         <int> 5, 4, 5, 5, 5, 5, 2, 4, 3, 3, 5, 5, 5, 5, 5, 3, 3, 5…
## $ esp_148_i         <int> 3, 4, 2, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 3, 4, 3…
## $ esp_148_j         <int> 3, 5, 4, 4, 5, 5, 5, 4, 5, 1, 5, 5, 5, 5, 5, 3, 4, 3…
## $ sexo              <int> 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1…
## $ edad              <int> 49, 35, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
## $ estado_civil      <int> 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4…
## $ info_enc_29       <int> 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ info_enc_23       <int> 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1…
## $ esc_nivel_1       <int> 1, 4, 4, 4, 4, 4, 4, 6, 4, 3, 5, 4, 2, 4, 4, 4, 7, 7…
## $ info_enc_12_b     <int> 5, 9, 7, 7, 5, 7, 7, 2, 7, 7, 7, 5, 1, 5, 7, 5, 1, 7…
## $ mesp_73           <int> 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
## $ mesp_149          <int> 4, NA, 4, 4, 2, 3, NA, 1, 4, 4, 2, 1, 1, 1, 4, 1, 4,…
## $ mesp_150          <int> 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ mesp_151          <int> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
## $ rmesp_152         <int> NA, 2, NA, NA, NA, NA, NA, NA, NA, NA, NA, 1, 4, NA,…
## $ esp_153           <int> 3, 2, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3…
## $ info_enc_1_a_1    <int> 66666, 66666, 55555, 55555, 9333, 55555, 55555, 9999…
## $ info_enc_1_a_2    <int> 10, 10, 10, 10, 9, 10, 10, 10, 10, NA, NA, 5, 9, 10,…
## $ info_enc_57       <int> 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
## $ info_hogar_17     <int> 2, NA, 3, 9, 5, 5, NA, NA, 8, 4, 9, 3, 4, 5, 3, 2, 2…
## $ religion_82       <int> 2, 9, 9, 1, 2, 2, 9, 10, 1, 9, 9, 9, 2, 2, 9, 2, 1, …
## $ religion_2        <int> 2, 9, 9, 9, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 5, 9…
## $ bienestar_21      <int> 2, 2, 88, 1, 2, 3, 2, 3, 2, 2, 2, 1, 1, 1, 2, 3, 3, …
## $ interes_pol_2_c   <int> 3, 2, 3, 2, 2, 1, 3, 1, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2…
## $ interes_pol_2_d   <int> 3, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3, 3, 3, 2, 3, 1…
## $ interes_pol_2_e   <int> 3, 2, 2, 2, 2, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 2, 1, 2…
## $ info_hogar_1_a    <int> 3, 1, 2, 2, 3, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 3, 2, 3…
## $ info_hogar_2_b    <int> 0, 2, 1, 1, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0, 1, 2…
## $ info_hogar_2_c    <int> 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1…
## $ info_hogar_32     <int> 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2…
## $ info_hogar_33     <int> 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1…
## $ info_hogar_21_n   <int> 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
## $ info_enc_60       <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ info_enc_52       <int> 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 10…
## $ info_enc_54       <int> 1, 1, 1, 88, 1, 1, 88, 1, 1, 88, 88, 99, 99, 88, 88,…
## $ gse               <int> 4, 3, 4, 3, 4, 3, 3, 2, 3, 4, 3, 3, 3, 3, 3, 4, 4, 4…
## $ muestra           <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ zona_u_r          <int> 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1…
## $ id_region         <int> 10, 14, 10, 9, 9, 10, 9, 14, 14, 8, 9, 8, 8, 8, 8, 9…
## $ region            <chr> "LOS LAGOS", "LOS RÍOS", "LOS LAGOS", "ARAUCANÍA", "…
## $ id_estrato        <int> 6, 8, 7, 3, 3, 7, 4, 6, 6, 1, 3, 3, 4, 4, 2, 5, 3, 3…
## $ estrato           <chr> "Costa sur", "Percordillera sur", "Lagos sur", "Vall…
## $ encuesta          <int> 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, …
## $ encuesta_a        <int> 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022…
## $ encuesta_m        <int> 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7…
## $ secu              <int> 87118, 87520, 87116, 87079, 87060, 87112, 87096, 871…
## $ pond              <dbl> 2.3424945, 0.3496257, 3.6989190, 1.2542517, 1.658597…

Como podemos ver, esta función es la que más datos nos entrega: nos da la dimensiones de la base de datos, nos dice los nombres de las variables nos señala el tipo de variable que tenemos (int = integer | chr = character | dbl = double), y nos dan una breve muestra de los datos (filas) que corresponden a cada columna, de manera de poner ver qué tipo de dato estamos observando. La mayoría de los datos que tiene esta encuesta son numéricos discretos (números enteros), por lo que probablemente sea una codificación de categorías.


2.2.3 class()

Dentro de una variable en particular, a veces queremos saber qué tipo de categorías contiene y en qué orden están.

class(cep$interes_pol_1_b)
## [1] "integer"
class(cep$region)
## [1] "character"

El signo “$” indica una variable específica de un data frame. en este caso estoy pidiendo la clase de la variable “interes_pol_1_b” dentro del dataframe “cep”. Al preguntar por ella y por la variable región, vemos que la primera es numérica (integer) y la otra son caractéres sin valor numérico epecífico.

2.2.4 Tipos de variables

1) logical

Estos también se llaman datos “booleanos”, propios de la lógica bouleana. Sólo tiene dos valores: TRUE y FALSE. Son particularmente útiles para modificar y crear nuevas variables en base a ciertas condicIones, como argumento en distintas funciones de cada paquete, y también muy usadas en funciones e iteraciones.

Ejemplo:

boul <-c(TRUE,TRUE,FALSE,TRUE,FALSE,FALSE)

print(boul)
## [1]  TRUE  TRUE FALSE  TRUE FALSE FALSE
class(boul)
## [1] "logical"

Hicimos una lista de valores bouleanos en la lista llamada boul, donde cada valor puede ser entendida como cada fila de una columna, separada por comas. Luego se imprime con el comando print() donde sale la lista creada, y luego con la función class() sabemos qué tipo es.

2) Integer

Los integer indican los valores reales sin decimales. se identifican por el sufijo L al final del valor para indicar que es un integer.

integer <- 186L
print(integer)
## [1] 186
class(integer)
## [1] "integer"

3) Double

Una variable double es otra variable numérica en R que significa “Double-precision floating point”, usada para expresar valores contínuos

3) Character

Se les llama así a variables de tipo categórica. Se escriben con comillas para asignar la categoría. Estas se pueden contar, sacar porcentajes o tasas.

ejemplo:

genero <-c("femenino", "femenino", "masculino", "otro", "femenino", "otro", "masculino")

class(genero)
## [1] "character"

4) numeric

Son literalmente números. Con este tipo de variables podemos hacer distintas operaciones matemáticas. se caracteriza por escribirse el número de manera directa sin comillas ni otros indicadores.

altura <-c(1.67,1.98,2.2,1.50,1.46,1.69,1.62,1.73)

print(altura)
## [1] 1.67 1.98 2.20 1.50 1.46 1.69 1.62 1.73
class(altura)
## [1] "numeric"

Nótese que puedes agregar tanto numeros enteros como decimales.

5) factor

Los factores son variables especiales, pues son caracteres pero que pueden incluir un elemento llamado “niveles” (levels). Los niveles son todos los valores únicos que puede tomar una variable factor. En otras palabras, una variable de clase factor es una categoría, pero internamente R interpreta que tienen un valor numérico de tipo ordinal.

En las variables de tipo character, cuando se ordenan las variables sólo se consideran por orden alfabetico. En cambio en los factores puedes asignar órdenes específicos, lo que será útil para gráficos pero también para regresiones.

Hagamos un ejemplo considerando si tenemos datos de la clase social de las personas. las categorías son “clase baja”, “clase media” y “clase alta”

clase <-c("clase baja", "clase baja","clase alta", "clase media", "clase baja", "clase media", "clase media")
class(clase)
## [1] "character"
table(clase)
## clase
##  clase alta  clase baja clase media 
##           1           3           3

Como puedes observar, la forma de presentación no es como uno la espera: generalmente buscaría ordenar por baja, media o alta (o alta, media y baja), pero como los caracteres sólo se ordenan alfabéticamente y para el computador son lo mismo, debemos pasarlos a factores y ordenarlos. Utilizaremos las funciones as.factor()y levels():

clase <-as.factor(clase)
levels(clase) <-c("clase baja", "clase media", "clase alta")
class(clase)
## [1] "factor"
table(clase)
## clase
##  clase baja clase media  clase alta 
##           1           3           3

En las lineas anteriores transformamos la variable clase en un factor con la función as.factor, luego indicamos cuál es el orden de niveles que tendrá el factor con la función levels() y luego al computar una nueva tabla aparece con el orden que indicamos.

Es importante señalar que para transformar un objeto, no sirve simplemente poner as.factor(nombre_variable), sino que hay reasignar el objeto que se quiere transformar. Ej: nombre_variable <-as.factor(nombre_variable).

6) String

Los strings son, en estricto rigor, variables character, pues están puestos en comillas. Sin embargo tienen una distinción interma importante pues con cadenas de texto complejas, que pueden ser frases cortas hasta laterales

ejemplo:

wyy <-"hola que tal, soy el chico de las poesías"

class(wyy)
## [1] "character"

Más adelante, cuando revisemos análisis de texto, tendremos que saber aplicar expresiones regulares que nos permitan cortar texto de modo que nos sea útil.


2.2.5 view()

Para ver toda la base de datos como una pestaña aparte del script en la parte superior izquierda, basta usar la función view().

view(cep)

Que se verá más o menos así:

Vista de base de datos con la función view()

Vista de base de datos con la función view()

Luego de explorar la base de datos, estamos en pie para poder manipularlos según lo que necesitemos realizar en nuestra investigación.


2.3 Manipulación de datos

A veces las bases de datos son demasiado grandes para trabajarlas en su totalidad (uno de los problemas que tiene R es que consume mucha memoria RAM), o simplemente por temas de limpieza de entorno, nos quedaremos sólo con los datos que necesitan.

En esta sección aprenderemos las funciones elementales para manipular datos: select(), filter(), los operadores lógicos necesarios para que nuestra selección y filtración de datos sea precisa, y además aprenderemos sobre la lógica de los “pipes” o tuberías que nos ayudarán que nuestro código sea más comprensible y efectivo.


2.3.1 select()

Antes de aplicar el comando, analizemos cuáles son las variables que utilizaremos en esta base de datos:

Codificación de variables seleccionadas:

Nombre variable Descripción Categorías
info_enc_30 En Chile, la ley reconoce diez pueblos
indígenas que están listados en la
siguiente tarjeta. ¿Pertenece Ud. o es descendiente
de alguno de ellos?
iden_pol_2 Identificación ideológica 1 - 10; 1 = Izquierda 10 = Derecha 88 = No sabe 99 = No contesta
constitucion_5_a ¿Fue Ud. a votar para las elecciones
del 15 y 16 de mayo para convencionales
constituyentes junto con las elecciones municipales
y de gobernadores regionales?
(1 = sí; 2 = No; 88 = No sabe; 89 = no contesta)
esp_94_b Y en su opinión, ¿Cuánto conflicto hay en Chile hoy
en día entre gente pobre y rica?
esp_111_d ¿Cómo ha sido su relación con Carabineros? 1 = Muy amable; 2= algo amable; 3= Poco amable; 4= Nada amable; 7= no amplica; 8=No sabe; 9= no contesta
sexo Sexo del encuestado 1 = Hombre;
2 = mujer
edad ¿Cuál es su edad? Edad exacta en años
interes_pol_2_c Sigue temas políticos en redes sociales
como Facebook
1 = Frecuentemente
2 = A veces
3 = Nunca
8 = No sabe
9 = No responde
gse Grupo socioeconómico 1 = ABC1
2 = C2
3 = C3
4 = D
5 = E

Aplicaremos entonces una función que nos genere un nuevo objeto, llamado “cep_cortada” y que tenga sólo estas variables:

cep_cortada <-dplyr::select(cep, info_enc_30, iden_pol_2,constitucion_5_a,
                            esp_94_b, esp_111_d, sexo, edad, bienestar_21, interes_pol_2_c,gse)


2.3.2 filter()

La función filter() nos permite seleccionar todo aquello que necesitamos, o por otro lado seleccionar todo lo que no queremos de la ase de datos para que sea descartado. Por ejemplo, esta encuesta en particular tiene un número de observaciones mayr a otras encuestas CEP porque hay un módulo especial para estudiar algunos aspectos del pueblo/nación mapuche y otras primeras naciones. Si sólo queremos, por ejemplo, analizar qué piensan los chilenos, podemos aplicar el operador lógico ==:

cep_chilenos <-dplyr::filter(cep_cortada, info_enc_30 == 88)

Como resultado, la base de datos se ha reducido a 1506 observaciones en las 15 columnas que seleccionamos. así tenemos el segundo paso de filtrado. Pero, hagamos algo más complejo: ¿Qué pasa si sólo quiero estudiar mujeres chilenas entre 18 a 40 años? para eso debemos aplicar operadores lógicos y operadores boomeanos, que corresponden a descripción de conjuntos.

cep_especifica <-dplyr::filter(cep_cortada,
                               info_enc_30 == 88 & sexo == 2 & (edad <= 18 | edad >=40 ))

La traducción de esto a lenguaje colocial sería crea una varianle llamada “cep_específica”, a partir de los datos del objeto cep_cortada, pero filtrando sólo a los que son chilenos y mujeres y tengan edad entre 18 a 40 años.


2.3.3 Operadores lógicos

Dejo acá el resumen de operadores lógicos más usados, provenientes de un gran libro: AnalizaR Datos Políticos de Francisco Urdinez:


Operador Descripcion
== “Es igual a”
!= “Es diferente a
> “Es mayor a”
< “Es menor que”
>= “Es mayor o igual a”
<= “Es menor o igual a”
& Intersección (como “y”)
| Unión (funciona como “o”)
%in% “Está contenida en…”

Esto nos permite hacer múltiples combinaciones de fltrado y manipulación de datos, así como creación de nuevas variables a partie de datos ya existentes que se integrarán no sólo a filter sino que a prácticamente todas las funciones en R.


2.4 mutate(), case_when() e ifelse()

Otro elemento fundamental antes de poder analizar datos es poder recodificar y reagrupar variables, que puede ir desde cambiar categorías, cambiar nombre de laa categoría o cambiar los nombres de las etiquetas. Por ejemplo en la variable de ideología política, es esperable que los números entre 1 a 10 sean transformados en categorías como “izquierda”, “Derecha”, “Centro” o “ninguna”. hagamos este ejercicio a partir de la función mutate.

2.4.1 mutate()

library(car)

cep_chilenos <-cep_chilenos%>%
  dplyr::mutate(ideologia = car::recode(as.numeric(cep_chilenos$iden_pol_2),
                                        "1:4 = 1; 5:6 = 2; 7:9 = 3; 10 = 3; 88 = 4; 99 = 4"))%>%
  dplyr::mutate(ideologia = dplyr::recode(ideologia,
                                          "1" = "Izquierda", "2" = "Centro",
                                          "3" = "Derecha", "4" = "Ninguno"))

En este código hemos ejecutado muchas cosas nuevas que iremos explicando paso a paso. La primera de ellas son las pipes, represenrtadas por su código %>%, que son básicamente “tuberías” con las cuales puedes ejecutar múltiples acciones en una sola linea argumental y sobre el mismo dataframe. Podemos leerla como si dijiera “y luego”, es decir, tiene un orden procedimental de actuar, y no funcionará si una de los pipes anteriores está malo. lo veremos muy seguido en nuestros códigos.

EN este caso este pipe encadena dos pasos: uno de agrupación de variables y otra de re-etiquetado. la primera es en base a la función mutate() que genera una variable nueva llamada “ideología, que se hará a partir del reagrupamiento de la original iden_pol_2. Así, por medio de la función”recode” del paquete car, hago que quienes respondieron entre 1 a 4 se reagrupen en “1”, los que respondieron entre 5 y 6 se reagrupen en “2”, los que respondieron entre 7 y 10 se reagrupen en “3” y quienes respondieron 88 y 99 (no sabe/no responde) se reagrupen como “4”. y luego asigno un nombre a cada una con la función dplyr::recode que eiqueta a los 1 como izquierda, 2 de centro, 3 de derecha y 4 como “ninguno”.

(¿Ven que es importante señalar de qué paquete viene la función? ¡ambos paquetes tienen una función que se llaman igual y hacen cosas diferentes!)

¿Podemos hacer esto de manera más eficiente? probemos con case_when() e ifelse().

2.4.2 case_when()

tomemos la variable interes_pol_2_c, sobre los niveles de seguimiento en redes sociales, pero la codificación original es poco intuitiva, los niveles de mayor frecuencia eran 1 mientras que quienes nunca siguen temas en redes sociales están catalogados como “3”. con etsa función recodificamos las variables:

cep_chilenos <-cep_chilenos%>%
  dplyr::mutate(rrss = case_when(
    interes_pol_2_c == "1" ~ 3,
    interes_pol_2_c == "2" ~ 2,
    interes_pol_2_c == "3" ~ 1,
    interes_pol_2_c == "8" ~ NA,
    interes_pol_2_c == "9" ~ NA))

Además, quienes estaban codificados como “8” o “9” que representan “no sabe” y “no responde” los agregamos como NA.

2.4.3 ifelse()

Uno de los comandos más antiguos en la historia de la computación. Su razonamiento es “Si esta condición de cumple, haz esto; sino, haz esto otro” hasta satisfacer todas las condiciones posibles. Usaremos como ejemplo la misma manipulación de datos que observamos en la función case_when()

cep_chilenos<-cep_chilenos%>%
  dplyr::mutate(rrss = ifelse(interes_pol_2_c == 1, 3,
                              ifelse(interes_pol_2_c == 2,2,
                                     ifelse(interes_pol_2_c == 3,1,NA))))

La traducción de este código es “crea una variable llamada rrss con los siguientes valores: Si en interes_pol_2_c es igual a 1, etiquetala como 3, si su valor es 2, conservala en 2; si es 3, etiquetala como 1. Para todas las demás condiciones aplica NA”.

Es importante notar que cada condición de ifelse está anidada de otro ifelse anterior, cuestión que hay que mirar con atención pues al comienzo es muy fácil perderse con los paréntesis.


3.Estadística descriptiva

La estadística descriptiva a veces es vista de manera peyorativa, pero es altamente relevante ya que nos entrega los primeros acercamientos para analizasr la naturaleza de los datos que estamos analizando. A veces la pura descripción de los datos puede entregarnos información lo suficientemente relevante para abrir preguntas de investigación relevantes.

En este caso analizaremos uno de los puntos más relevantes en el análisis económico, compartido también por sociólogos y trabajadores sociales: la distribución del ingreso.

Llamamos la base de datos de la encuesta CASEN en pandemia del año 2020:

casen <-readRDS("bbdd/casen_2020/casen.RData")

Luego creamos una nueva base de datos llamada casen_corta a partir de la selección de las variables ingreso total corregido, región y sexo

casen_corta<-casen%>%
  dplyr::select(region, id_vivienda,sexo, ytotcor)
options(scipen = 999)

3.1 Medidas de tendencia central: media, mediana y moda

La media se define como el la suma de todos los valores de una determinada variable, normalizada por el número de observaciones totales. Es una de las formas más clásicas para entender el punto central de una serie de datos.

Se puede obtener computando la función mean()

#Obtener media de ingresos totales corregidos

mean(casen_corta$ytotcor, na.rm = TRUE)
## [1] 415297.9

ya que no todas las filas tienen ingresos (porque no todas las personas encuestadas tienen ingresos) tendremos muchos valores NA en la variable que estamos calculando. cuando agregamos el argumento na.rm = TRUE le estamos diciendo que remueva todos los valores NA y sólo trabaje con las filas que tienen valores determinados.

Por otro lado, la mediana es una medida de tendencia central que corta exactamente a la mitad la distribución de observaciones. se computa a través de la función median():

median(casen_corta$ytotcor, na.rm = TRUE)
## [1] 274932

En una distyribución normal, la mediana y la media deberían ser el mismo valor, sin embargo vemos en estte caso que la media de ingresos totales es de $415298CLP, pero la mediana es de $274932CLP. Esto quiere decir que hay valores extremos que hacen “inflar” la medida de tendencia central hacia valores más altos que la mediana. observaremos más detalles de esto cuando grafiquemos.

3.2 Medidas de dispersión: desviación estandar y varianza

La desviación estandar la podemos definir como el promedio de las distancias de los valores puntuales respecto de la media de una variable determinada. en R se usa la función sd() para calcularla.

sd(casen_corta$ytotcor, na.rm = TRUE)
## [1] 782107.4

Esto nos indica quer la desviación estandar de ingresos totales es de 782107 pesos, según la encuesta CASEN en pandemia. ¡Esto es mucho más que el promedio! ¿Qué significa esto? significa que tenemos muchos valores extremos que hacen que los datos sean muy dispersos, y por lo tanto a la hora de calcular estimaciones como una regresion lineal, los errores estandar sean muy altos.

Por otro lado, la varianza que es la desviación estandar al cuadrado, se puede obtener a partir del comandovar() como se ve a continuación:

var(casen_corta$ytotcor, na.rm = TRUE)
## [1] 611692020694

Finalmente, un estadístico importante para la dispersión es el rango de los datos disponibles, que podemos obtener a partir del comando range() como se ve a continuación:

range(casen_corta$ytotcor, na.rm = TRUE)
## [1]       83 84700000

Podemos ver que el comando entrega el rango inferior y superior de los datos disponibles.

3.3 Medidas de posición: Cuartiles

En la estadística descriptiva los cuartiles son fundamentales para comprender cómo están distribuídos los valores de una serie, y nos permite entender un poco mejores la estructura general de los datos. Habitualmente los cuartiles que más se revisan con el 1 y el 3, que son las distribuciones acumuladas del 25% de la muestra, y del 75% de la muestra respectivamente. Si sumamos que la mediana es por definifición el cuartil 2 (el 50%) de la muestra, tenemos información bastante interesante de cómo se acumulan los datos.

para obtener cuartiles computamos la función quantile()

quantile(casen_corta$ytotcor, probs = 0.25, na.rm = TRUE)
##    25% 
## 109578

Esto nos dice que el 25% de la población que menos ingresos tienen, van desde 0 hasta $109578CLP.

3.3 Tablas y porcentajes en variables categóricas

También existe una cantidad importnatede variables categóricas, de las cuales vamos a querer saber cuántas observaciones hay por categoría, así como sus porcentajes. Para eso usaremos la categoría ideologia de la encuesta CEP 2022 que modificamos hace un momento.

Para tener un conteo general dela variable usamos la función table():

table(cep_chilenos$ideologia)
## 
##    Centro   Derecha Izquierda   Ninguno 
##       460       314       268       464

Sin embargo esto no nos da información porcentual de cada una de las variables. para ello usaremos la función prop.table() para obtener las proporciones:

prop.table(table(cep_chilenos$ideologia))
## 
##    Centro   Derecha Izquierda   Ninguno 
## 0.3054449 0.2084993 0.1779548 0.3081009

Las proporciones están en una escala de 0 a 1, por lo que agregaremos un multiplicador por 100 para transformarlo a porcentaje:

prop.table(table(cep_chilenos$ideologia))*100
## 
##    Centro   Derecha Izquierda   Ninguno 
##  30.54449  20.84993  17.79548  30.81009

Ahora klor poecentajes son muhco más legibles, sin embargo tenemos muchos decimales innecesarios en estadística social (¡en otras disciplinas se usan sobre los 6 decimales!), por lo que vamos a redondear a dos decimales con la función round(). agregando una coma con la cantidad de decimales que necesitamos al lado de la multiplicación por 100:

round(prop.table(table(cep_chilenos$ideologia))*100,2)
## 
##    Centro   Derecha Izquierda   Ninguno 
##     30.54     20.85     17.80     30.81

Ya hemos visto las principazles herramientas básicas para inspección de estadística descriptiva. Ahora veremos una forma de hacer tablas para resumir esta información:

3.4 group_by() y summarise() para medidas de tendencia central, dispersión y posición

Para obtener todos los descriptivos que señalabvamos anteriormente y tenerlos de manera ordenada y en una tabla podemos usar las funciones group_by() y summarise() concatenadas con las pies que explicamos anteriormente. La primera función agrupa la base de datos en torno a una o más variables, y la segunda es una funció que genera una tabla con los estadísticos que le indiquemos que use. En este caso aplicaremos todos los de tendencia central, la desviación estandar y el cuartil 1 y 3.

Haremos una primera prueba sólo con summarise() :

library(kableExtra)

tabla_ingresos <-casen_corta%>%
  dplyr::summarise(media = mean(ytotcor, na.rm = TRUE),
            mediana = median(ytotcor, na.rm = TRUE),
            Desv.std = sd(ytotcor, na.rm = TRUE),
            Q1 = quantile(ytotcor, probs = 0.25, na.rm = TRUE),
            Q3 = quantile(ytotcor, probs = 0.75, na.rm = TRUE))

ingreso1 <-knitr::kable(tabla_ingresos, align = "lccrr")

ingreso1%>%
  kable_styling(latex_options = "scale_down")
media mediana Desv.std Q1 Q3
415297.9 274932 782107.4 109578 464562

En este script he generado un nuevo objeto llamado tabla_ingresos, que es una tabla de una sola fila que incluye la media a la cual he puedo el nombre de columna “media”, “Desv.Std” con la desviación estandar. “Q1” con el primer cuartil y “Q3” con el tercer cuartil.

Pero ¿Qué pasa si queremos saber esta información, subdividida por sexo? es ahí donde entra la variable de agrupación:

library(kableExtra)

tabla_ingresos_sexo <-casen_corta%>%
  dplyr::group_by(sexo)%>%
  dplyr::summarise(media = mean(ytotcor, na.rm = TRUE),
            mediana = median(ytotcor, na.rm = TRUE),
            Desv.std = sd(ytotcor, na.rm = TRUE),
            Q1 = quantile(ytotcor, probs = 0.25, na.rm = TRUE),
            Q3 = quantile(ytotcor, probs = 0.75, na.rm = TRUE))

ingreso1 <-knitr::kable(tabla_ingresos_sexo, align = "lccrr")

ingreso1%>%
  kable_styling(latex_options = "scale_down")
sexo media mediana Desv.std Q1 Q3
Hombre 508670.2 318000 956365 174932 550000
Mujer 322685.6 201091 542217 104646 380000

EN este caso, la traducción del script sería algo así como crea una variable llamada tabla_ingresos_sexo, a partir de la base casen_corta, luego subdividela por sexo y luego estima todos estos descriptivos

Este tipo de tablas puede ser muy útil en caso de que necesitemos índices sumarios de muchas categorías distintas, como por ejemplo tener estos datos a nivel regional:

tabla_ingresos_region <-casen_corta%>%
  dplyr::group_by(region)%>%
  dplyr::summarise(media = mean(ytotcor, na.rm = TRUE),
            mediana = median(ytotcor, na.rm = TRUE),
            Desv.std = sd(ytotcor, na.rm = TRUE),
            Q1 = quantile(ytotcor, probs = 0.25, na.rm = TRUE),
            Q3 = quantile(ytotcor, probs = 0.75, na.rm = TRUE))

ingreso1 <-knitr::kable(tabla_ingresos_region, align = "lccrr")

ingreso1%>%
  kable_styling(latex_options = "scale_down")
region media mediana Desv.std Q1 Q3
Región de Tarapacá 457890.4 321528.0 555042.6 180000.0 540000.0
Región de Antofagasta 550742.5 400000.0 740176.9 171499.5 698815.0
Región de Atacama 423751.8 300000.0 493721.3 120000.0 540000.0
Región de Coquimbo 300380.4 240740.0 1096077.6 104646.0 371755.0
Región de Valparaíso 408222.1 280000.0 560426.6 125000.0 480000.0
Región del Libertador Gral. Bernardo O’Higgins 320905.7 270000.0 372124.1 109914.0 400000.0
Región del Maule 300135.6 228330.5 515394.2 104646.0 357500.0
Región del Biobío 333594.0 247470.5 648907.6 104646.0 400000.0
Región de La Araucanía 289688.8 200000.0 521626.4 83333.0 341375.5
Región de Los Lagos 325788.5 214627.5 689134.4 100000.0 394417.5
Región de Ayséndel Gral. Carlos Ibáñez del Campo 495643.5 301667.0 728804.8 110406.0 600000.0
Región de Magallanes y de la Antártica Chilena 587735.4 400000.0 879747.0 184000.0 700000.0
Región Metropolitana de Santiago 629199.6 350833.0 1215703.7 168000.0 626109.0
Región de Los Ríos 330206.4 233245.0 550786.0 104646.0 400000.0
Región de Arica y Parinacota 384351.5 280000.0 449263.6 120000.0 458333.0
Región de Ñuble 274919.9 200000.0 417800.8 104646.0 324125.2

De esta forma podríamos ver las diferencias regionales de ingresos y desigualdad social.

4. Tablas cruzadas

También llamadas tablas de contingencia con formas de mostrar información que combina otras variables que pueden ser de relevancia. Estas tablas pueden ser cruzadas entre dos variables categóricas y numéricas, dos categóricas, o más de dos variables.

library(crosstable)
library(flextable)

ct1 <-casen_corta%>%
  drop_na(ytotcor)%>%
  crosstable(ytotcor, by=sexo, total = "row", showNA = "no",percent_digits=0, funs=c(median, mean, "std dev"=sd),
             test=TRUE)%>%
  as_flextable(kee_id=TRUE)%>%
    colformat_num()

ct1

7. Graficar resultados. Nivel básico

El mundo de la visualización de datos es inmenso y hay académicos que han creado sus carreras completas en base a sus conocimientos de visualización de datos, los cuales combinan teoría de diseño junto con elementos estadísticos centrales para cada tipo de dato, donde cada tipo de visualización ilustra mejor o peor cierta información.

En este sentido, R tiene dos vías se generar visualizaciones: con R Base o a través del paquete ggplot2. R base es sencillo y se puede realizar una exploración básica y rápida de datos generales. Como estamos analizando el ingreso percápita, podemos hacer un histograma sencillo con R Base:

hist(casen_corta$ytotcor,breaks = 1000)

Como podemos observar, el histogramna nos da poca información aunque valiosa: vemos que en la distribución, la abrumadora mayoría de las personas tiene ingresos muy bajos y sólo unos pocos tiene ingresos más altos, acorde con todas las investigaciones sobre desigualdad social en Chile.

hist(log(casen_corta$ytotcor))

También simplemente ejecutando la función plot, que nos da un gráfico de puntos:

plot(casen_corta$ytotcor)

Pero, como podemos ver, son gráficos bastante feos. más allá de la exploración básica, no es recomendable utilizar mucho R base para reportar información con gráficos. Para esto se desarrolló ggplot2, el chiche del mundo de tidyverse.


Uso de ggplot2

La filosofía de la visualización de datos no debería ser tomada a la lijera y sin duda requiere una larga introducción para ser enseñada. Por el momento sólo diremos una cosa: Se debe saber bien qué es lo que se quiere ilustrar con un gráfico; por otro lado, también tenemos que saber la naturaleza de las variables con las que estamos trabajando: si son categóricas, ordinales, discretas o contínuas.

Entrando al paquete como tal, ggplot2 funciona con una filosofía de capas de información: voy progreisvamente dándole instrucciones para que realice lo que necesito.

Por ejemplo, debo indicarles cuáles son los datos y cuál es el mapeo estético (no de aesthetic) qué le daré a la información. por ejemplo la relación años de escolaridad e ingreso:

library(ggplot2)
ggplot(data = casen_corta,
       mapping = aes(x = sexo, y = ytotcor))

Si se fijan …. no hay nada. Por qué? porque hasta ahora le hemos dicho tres cosas a R que haga: que llame la función ggplot, indicarle cuál será nuestra base de datos, decirle cuál es nuestro eje x y nuestro eje y, pero hasta ahora no le hemos dicho cuál es la figura geométrica que queremos dibujar con esos datos.

Para realizarlo, haremos distintos objetos geométricos como forma de analizar la información. En este caso haremos un diagrama de caja o boxplot:

ggplot(data = casen_corta,
       mapping = aes(x = sexo, y = log(ytotcor)))+
  geom_boxplot()

ggplot(data = casen_corta,
       mapping = aes(x = sexo, y = log(ytotcor)))+
  geom_violin()

Esto funciona sólo para cuando la variable independiente es categórica u ordinal. ¿Qué pasa con las variables contínuas? podemos mostrarlo de otra forma. Por ejemplo, con un histograma:

ggplot(data = casen, mapping = aes(x = log(ytotcor))) +
  geom_histogram()

Si has mirado bien el código, notarás que la única información que hemos proporcionado es la base de datos, el eje x y la figura que tenemos. El paquete interpreta que al no haber y, y haciendo un histograma, implica que cada valor de y es la frecuencia del valor de x.

Lo mismo ocurre con un gráfico de densidad:

ggplot(data = casen_corta, mapping = aes(x = log(ytotcor))) +
  geom_density()

Pero veamos si podemos tener algo más de información: En esta ocación queremos ver la distribución de los ingresos según sexo. Para ello utilizaremos el argumento fill:

ggplot(data = casen_corta, mapping = aes(x = log(ytotcor), fill = sexo)) +
  geom_density()

Con esto podemos ver de manerta gráfica cómo el ingreso total tiene una distribución desigual entre hombres y mujeres, en donde los hombres tienen mayor ingreso, demostrado en que la parte derecha de la distribución es más abultada que en las mujeres.

Sin embargo, si queremos reportar esta información en un reporte, debemos hacer algunos ajustes estéticos. Usemos el argumento labs y themepara agregar título, subtítulo, cambiarle los nombres de los ejers y la fuente de la mesa, y configurar sus tamaños y tipo de letra.

ggplot(data = casen_corta, mapping = aes(x = log(ytotcor), fill = sexo)) +
  geom_density() +
  labs(title = "Distribución logarítmica de ingresos totales, dividida por sexo",
       x = "Logaritmo de ingreso total",
       y = "Densidad",
       caption = "Fuente: Encuesta CASEN en Pandemia, 2020")+
    theme(plot.title = element_text(hjust = .5, size = 14, face = "bold"),
        plot.caption = element_text(size = 8))

Vamos a avanzar un poco más. Hasta ahora tenemos dos variables interactuando gráficamente. ¿Cómo podríamos agregar una tercera? con la función facet_wrap() podremos ver una tercera variable. Haremos una nueva variable llamada “zona” que agrupa las regiones en “Norte”, “Centro”, “Sur”, “Austral”:

casen_corta <-casen_corta%>%
  dplyr::mutate(zona = dplyr::case_when(region %in% c("Región de Tarapacá", "Región de Antofagasta", "Región de Atacama", "Región de Coquimbo", "Región de Arica y Parinacota") ~ "Norte",
                                        region %in% c("Región de Valparaíso", "Región del Libertador Gral. Bernardo O’Higgins", "Región del Maule",
                                                      "Región Metropolitana de Santiago") ~ "Centro",
                                        region %in% c("Región del Biobío", "Región de La Araucanía", "Región de Ñuble", "Región de Los Lagos", "Región de Los Ríos") ~ "Sur",
                                        TRUE ~ "Austral"))

ggplot(data = casen_corta, mapping = aes(x = log(ytotcor), fill = sexo)) +
  geom_density() +
  labs(title = "Distribución logarítmica de ingresos totales, dividida por sexo y zona geográfica",
       x = "Logaritmo de ingreso total",
       y = "Densidad",
       caption = "Fuente: Encuesta CASEN en Pandemia, 2020")+
  facet_wrap("zona")+
    theme(plot.title = element_text(hjust = .5, size = 14, face = "bold"),
        plot.caption = element_text(size = 8))

Otra forma de mostrar los mismos gráficos es a través de la función facet_grid() en lugar de facet_wrap. Te invito a que la prubes y pienses cuál de las dos presentaciones es mejor para esta información.

Hasta ahora hemos avanzado con variables dependientes contínuas mezcladas con categóricas y contínuas. qué pasa sí sólo queremos comparar dos o tres variables categóricas? haremos algunos gráficos de barras con porcentajes incrustados, ideales para estadística descriptiva.

volveremos sobre el objeto llamado “cep_chilenos” donde analizaremos la relación entre sexo del encuestado e ideología. Comenzaremos por explorar descriptivamente la cantidad de personas por ideología

ggplot(data = cep_chilenos, mapping = aes(x = ideologia))+
  geom_bar()

Vamos hasta el momento sólo una frecuencia de cuántas personas existen en la base de datos por cada ideología, algo así como una forma visual de la función table(). Para trnasformar la escala a porcentajes debemos hacer algunas adaptaciones.

ggplot(cep_chilenos, mapping = (aes(ideologia)))+
  geom_bar(aes(y = (..count..)/sum(..count..)))+
  scale_y_continuous(labels = scales::percent)

Aún hay mucho que hacer. vamos a dividir la ideología por sexo con el argumento fill:

myplot <- ggplot(cep_chilenos, aes(ideologia, group = sexo)) + 
          geom_bar(aes(y = ..prop.., fill = factor(..x..)), stat="count") + 
          scale_y_continuous(labels=scales::percent) +
          ylab("relative frequencies") +
          facet_grid(~sexo)

myplot

Por lo que vemos en la información, vemos que pareciera que hay más hombres (1) que mujeres (2) en que no se identifican ideológicamente. Pero ¿Cuánto exactamente? vamos a agregar los porcentajes exactos de cada uno, y además sacaremos la leyenda de los factores que aparece en la derecha porque cada etiqueta ya está explicada en el eje x:

ggplot(cep_chilenos, aes(x= ideologia,  group=sexo)) + 
    geom_bar(aes(y = ..prop.., fill = factor(..x..)), stat="count") +
    geom_text(aes( label = scales::percent(..prop..),
                   y= ..prop.. ), stat= "count", vjust = -.5) +
    labs(y = "Porcentaje", fill="Identificación ideologica") +
    facet_grid(~sexo) +
    scale_y_continuous(labels = scales::percent)+
  guides(fill = FALSE)

final,emte, opr temas de lectura, lo invertimos:

ggplot(cep_chilenos, aes(x= ideologia,  group=sexo)) + 
    geom_bar(aes(y = ..prop.., fill = factor(..x..)), stat="count") +
    geom_text(aes( label = scales::percent(..prop..),
                   y= ..prop.. ), stat= "count", vjust = -.5) +
    labs(y = "Porcentaje", fill="Identificación ideologica") +
    facet_grid(~sexo) +
    scale_y_continuous(labels = scales::percent)+
  guides(fill = FALSE)

Con esto hemos terminado la parte básica de gráficos. Si quieres gráficos más avanzados, espera a que hagamos la nueva sección agregando distintas capas, utilizando paletas de colores específicas, nuevas geometrías, etc.

8. Introducción a la inferencia estadística y pruebas de hipótesis

8.1 Breve introducción a la estadística inferencial

8.2 Test t para una sola variable

t.test(casen_corta$ytotcor, mu = 0)
## 
##  One Sample t-test
## 
## data:  casen_corta$ytotcor
## t = 205.16, df = 149281, p-value < 0.00000000000000022
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  411330.5 419265.4
## sample estimates:
## mean of x 
##  415297.9

8.3 Tests t para dos variables

t.test(ytotcor ~ sexo, data = casen_corta)
## 
##  Welch Two Sample t-test
## 
## data:  ytotcor by sexo
## t = 46.17, df = 117449, p-value < 0.00000000000000022
## alternative hypothesis: true difference in means between group Hombre and group Mujer is not equal to 0
## 95 percent confidence interval:
##  178089.2 193879.9
## sample estimates:
## mean in group Hombre  mean in group Mujer 
##             508670.2             322685.6

8.4 ANOVA’s

8.5 ANCOVAS

8.6 MANOVAS

9. Introducción al modelo de regresión lineal


Una regresión lineal con una variable explicativa es un método para analizar cómo una variable X (independiente) genera un cambio en una vartiable Y (variable dependiente). El modelo general de regresiones se explica a continuación:



La notación puede variar en algunos libros: por ejemplo la constante a veces es escrita como \(\alpha\), u otras veces como \(\beta_1\); En el caso del error este también es escrito como \(\varepsilon_i\). Será deber del estudiante estar atento para identificar qué elemento es cada uno, pero la constante es fácil de identificar pues no va acompañada de una variable explicativa \(X_i\).


…pero falta aclarar algo importante en la imagen explicada


\(\beta_0\) y \(\beta_1\) son desconocidos. Son medidas poblacionales que debemos estimar a partir de la muestra que tenemos disponibles. Por lo tanto la notación de la pendiente estimada por la muuestra es nuestro amigo beta gorro: \(\hat{\beta}\).


9.1 Estimación de mínimos cuadrados ordinarios (MCO)


La característica principal los MCO es que elige los coeficientes de regresión de tal forma que la recta de regresión estimada se encuentre lo más cercana posible a los datos observados, y la cercanía está medida por la suma de los errores al cuadrado que se cometen con la predicción de Y dado X.

Sean \(b_0\) y \(b_1\) algunos de los estimadores de \(\beta_0\) y \(\beta_1\). La recta de regresión basada en esos estimadores es \(b_0 + b_1X\) por lo que el valor de \(Y_i\) previsto mediante esta esta es \(b_0 + b_1X_i\). Por lo tanto el error se puede calcular como \(u_i = Y_i -(b_0 + B-1X_i)\).

La suma de todos los errores al cuadrado para n predicciones es:

\[\sum_{i=1}^{n}(Y_i - b_0 - b_1X_i)^2\]

MCO tiene su propia notación. El estimador MCO de \(\beta_0\) es \(\hat\beta_0\), y el estrimador \(\beta_1\) es \(\hat\beta_1\). lOS RESIDUOS \(\hat u_i = Y_i - \hat Y_i\). En este sentido los gorros muestran que son homogos muestrales de \(\beta_0\) y \(\beta_1\).

Para obtener \(\hat \beta_1\) se computa:

\[\hat \beta_1 = \frac{\sum_{i=1}^n(x_i - \bar x)(y_i - \bar y)}{\sum_{i=1}^n(x_i - \bar x)^2} = \frac{S_{xy}}{S^2_x}\] Y para la constante:

\[\hat \beta_0 = \bar y - \hat \beta_1X_i\]


####9.1.1 Medidas de ajuste (\(R^2\) y Error estándar)


Las medidas de ajuste las podemos entender como mecanismos para observar en qué medida esta regresión lineal descibre correctamente. El \(R^2\) y el error estándar miden la bondad de ajuste de la recta de regresión MCO a los datos.

9.1.1 \(R^2\)

Se puede definir como la proporción de varianza muestral de \(Y_i\) explicada por (o predicha por) \(X_i\). Matemáticamente el \(R^2\) puede escribirse como el cociente entre la suma explicada (de cuadrados) y la suma total de cuadrados. La suma explicada es la suma de las desviaciones al cuasdrado de los valores prerdichos de \(Y_i\) (\(\bar Y_i\)), respecto de su media y la suma total es la suma de los cuadrados de las desviaciones de \(Y_i\) respecto de su media:

\[ SE = \sum_{i=1}^n(\hat Y_i - \bar Y)^2\]

\[ST = \sum_{i=1}^n(Y_i - \bar Y)^2\]

Por lo tanto:

\[R^2 = \frac{SE}{ST}\]


De manera alternativa, \(R^2\) puede ser expresado como el cociente entre la varianza \(Y_i\) no explicada por \(X_i\). Para eso podemos tomar la suma de cuadrados de residuos, o suma resicual, que es:

\[SR = \sum_{i=1}^n \hat u_i^2\]

Por lo tanto el \(R^2\) puede se reescrito como:

\[R² = 1 - \frac{SR}{ST}\]

El \(R^2\) toma valores entre 0 y 1, donde 0 es que el modelo no explica nada de la variación \(Y_i\) sobre \(X_i\) y 1 es que explica completamente dicha variación. Habitualmente los valores nunca son muy cercanos a 0 o 1, sino que están en un intermedio. Si un \(R^2\) de 0.8 implica que el modelo tiene un muy buen rendimiento de la variable explicativa sobre \(Y_i\).


9.1.2 Error estandar


El error estandar es un estimador de la desviación típica del error de regresión \(u_i\). Como \(u_i\) e \(Y_i\) tienen las mismas medidas, el ESR es una medida de dispersión de las observacionesen torno a una recta de regresión. Ya que los \(U_i\) no están disponibles por ser medidas poblacionales, se usan sus medidas muestrales \(\hat u_i\):

\[ESR = S_{\hat u}, donde s_{\hat u}^2 = \frac{1}{n - 2} \sum_{i=1}^n = \frac{SR}{n - 2}\] La razón de usar \(n - 2\) es que corrige una desvación a la baja introducido al estimar dos coeficientes de regresión. Esto se denomina Corección por grados de libertad.


Ejemplo: Ingreso y edad


Para ejemplificar todo lo que hemos expuesto hasta ahora, analizaremos un pequeño caso: La relación entre ingreso percapita (variable dependiente) en relación a los años de escolaridad (variable independiente). Para esto usaremos los datos de la encuesta CASEN 2017, y para que la base de datos sea manejable sólo haremos el ejemplo de la comuna de La Cisterna, Santiago de Chile.

Computamos la regresión y obtenemos los siguientes resultados:


ejemplo <-lm(ytotcor ~ I(Exp^2), data = casen_corta)

stargazer::stargazer(ejemplo, type = "html")
Dependent variable:
ytotcor
I(Exp2) -63.313***
(1.403)
Constant 538,541.100***
(2,954.985)
Observations 137,086
R2 0.015
Adjusted R2 0.015
Residual Std. Error 800,125.500 (df = 137084)
F Statistic 2,037.188*** (df = 1; 137084)
Note: p<0.1; p<0.05; p<0.01


Lo que nos está diciendo esta regresión es que el cambio marginal de la experiencia en una unidad hace que el ingreso total baje 8.494 pesos chilenos. Esto es … raro. La experiencia nos debería llevar a tener mejor sueldo, pero esto demuestra lo contrario. Si observamos la significancia, esta es significativa en p < 0.05, y el error estandar (que es el bajos que sale entre paréntesis debajo del coeficiente Exp es de 3.666.977), que es grande pero tampoco es gigante y major al mismo coeficiente.

De manera gráfica la regresión muestra lo siguiente:


library(ggplot2)
ggplot(data = casen_corta, aes(x = Exp, y = ytotcor)) +
  geom_point() +
  geom_smooth(method = "lm", se = TRUE, color = "firebrick") +
  theme_bw() + labs(x = "", y = "")


Cada punto del gráfico es el valor y en su respectiva x (puntos de experiencia). La línea roja marca la pendiente que el estimador MCO calcula con los datos y el sombreado muestra el error estandar de la regresión. Los puntos muy disparados hacia arriba se pueden considerar como outliers, Y el estimador de Mínimos cuadrados ordinarios es sensible a ellos.

¿Qué nos muestra esta regresión? que en las dos puntas la regresión aumenta sus errores estandar, implicando la presencia de valores que hacen variar mucho el coeficiente obtenido, y que en particular hay una gran cantidad de outliers en los valores x de menos experiencia (sobre todo entre 15 a 25 años de experiencia) que tienen ingresos muy altos. Es posible pensar que esos valores son los que hacen que la pendiente se vuelva negativa, pero aún queda mucho por explorar. ya seguiremos analizando este ejemplo.

9.2 ¿Por qué usar Mínimos cuadrados ordinarios?


Podemos resumir en las siguientes razones:

  1. Son el lenguaje común entre economistas, y es el método dominante en todas las ciencias sociales.

  2. Bajo los supuestos que veremos ahora, MCO es insesgado y consistente.

  3. En el marco de otros estimadores insesgados, MCO es uno de los más eficiente. Siempre y cuando se mantengan algunas condiciones.


9.3 Supuestos del modelo lineal


Cuando se hace una estimación por Mínimos cuadrados ordinarios, no sólo se buscan los valores de \(\hat \beta_0\) y \(\hat \beta_1\), sino que hacer inferencia a ver si \(\hat Y_i\) se acerca al valor real de Y, es decir \(E(Y | X_i)\). Esta inferencia se realiza bao ciertos supuestos de \(X_i\) y \(u_i\). Los supuestos son críticos para una interpretación válida de los resultados.

Según el libro de Gujaragit (2007) el modelo lineal tiene 10 supuestos:

  1. El modelo de regresión es lineal en los parámetros

\[Y_i = \beta_o + \beta_1X_i + u_i\]

  1. Los valores de X son fijos en un muestreo repetido

Esto quiere decir que los valores de X no son estocásticos. Recordar que es un análisis de regresión condicional a cierto valor x.

  1. El valor medio del error \(u_i = 0\)

Cada Y poblacional correspondiente a determinado X está distribuído alrededor de la media. Los valores por encima y debajo son los errores, y el promedio del vaor medio es cero (ya que los valores positivos y negativos se deben cancelar hasta llegar a cero)

  1. Las varianzas de \(u_i\) son iguales (Homocedasticidad)

Homocedástico se refiere a “Igual disperción”. La varianza de \(u_i\) para cada \(X_i\) es algún número positivo constante igual a \(\sigma^2\). En otras palabras:

\[var(u_i | X) = E[u_i - E(u_i) | X]^2\] \[ = E(u_i^2 | X )\] \[ = \sigma^2 \]

  1. No Existe correlación entre errores

Este es un supuesto de no correlación lineal. Si existen patrones en la distribución de errores, están autocorrelacionados. Si eso pasa, \(Y\) ya no sólo depende de X, sino también de \(u_i\).

  1. La varianza entre \(u_i\) y \(X_i\) es cero (\(E[U_iX_i] = 0\))

Para que la estimación por MCO esté correcta, los errores \(u_i\) y \(x_i\) no están correlacionados. Si lo está, no es posible determinar el efecto diferenciador entre \(u_i\) y \(x_i\).

De todas formas, buenas noticias: Este supuesto se cumple automáticamente si la variable X no es estocástica y se mantiene el supuesto 3.

  1. El número de observaciones n debe ser mayor al número de parámetros por estimar

Se necesitan al menos dos pares de observaciones por parámetro.

  1. Variables en valores de X

No todos los valores de X en una muesta dada deben ser iguales. Si todos on iguales implica que \(X = \bar X\), y la estimación de \(\beta_0\) y \(\beta_1\) sería imposible.

  1. El modelo de regresión está correctamente especificado

Con este supuesto no habría sesgo de especificación por error. Y la teoría econométrica asume que el modelo está especificado correctamente.

Sin embargo se puede testear a partir de algunas preguntas: ¿Cuáles variables están incluídas en el modelo? ¿Cuál es la forma funcional del modelo? ¿Es lineal envariables, en parámetros o ambos? ¿Cuáles son los supuestos probabilísticos considerados para \(Y_i\), \(X_i\) y \(u_i\) en el modelo?.

El sesgo consiste en escoger la forma funcional equivocada. En este sentido, la construcción de modelos econométricos es más un arte que una ciencia.

  1. No hay multicolinealidad perfecta

Quiere decir que no hay relaciones perfectamente lineales entre variables explicativas. En algunos casos también se busca la colinealidad imperfecta.

Si tienen relación pero no es lineal no importa para efectos de MCO.

Por el contrario, si hay colinealidad perfecta, los coeficientes son indeterminados y los errores son infinitos.

Si hay colinealidad pero no es perfecta, los coeficientes se pueden determinar pero los errores estandar serán altos.

¿Por qué puede haber multicolinealidad?

Puede ser por método de recolección de muestra (muestras con intervalos limitados), restricciones del modelo o en la población de muestra, errores de especificación del modelo o porque está sobredeterminado.


3. Testeo de supuestos de modelo lineal


3.1 Prueba de heterocedasticidad (White Test)

El test de White es una forma intuitiva y rápida de analizar si tenemos heterocedasticidad en nuestra regresión. Con el paquete lmtest y la función bptest lo analizaremos rápidamente:


bptest(ejemplo, ~ Exp + I(Exp^2), data = casen_corta)
## 
##  studentized Breusch-Pagan test
## 
## data:  ejemplo
## BP = 17.516, df = 2, p-value = 0.0001572


Vemos que el test estadístico \(X^2\) da 3.2018, los grados de libertad son 2 y el p-valor es de 0.2017. La forma de interpretar esto es la siguiente:

El test de White usa la siguiente forma: La hipótesis nula (\(H_0\)) es que la homocedasticidad está presente (lo que buscamos!), y la alternativa (\(H_A\)), es que la heterocedasticidad está presente. Como el p-valor no es menos a 0.05, fallamos al rechazar la hipótesis nula. Es decir: al tener valores mayores de 0.05 implica que no tenemos suficiente evidencia para decir que la heterocedasticidad está presente en el modelo de regresión, por lo tanto está correcta.

Si el modelo hubiese tenido heterocedasticidad ¿Qué podríamos hacer? podemos hacer la regresión lineal robusta con la función rlm.


3.2 Test de Ramsey para errores de especificación de Modelos


Comos señala la página oficial del paquete lmtest de R, el test Reset de Ramsey es un diagnóstico para las corrección de las formas funcionales de modelos de estimación. Su principal característica es observar si hay variables no estipuladas que afectan a mi variable dependiente, de modo de poder analizar la pertinencia del modelo.

El test de ramsey tiene como hipótesis nula que no hay errores de especificación en su modelo. La hipótesis alternativa es que sí tiene errores de específicación.


resettest(formula = ejemplo, power = 2:3, type = "regressor")
## 
##  RESET test
## 
## data:  ejemplo
## RESET = 233.59, df1 = 2, df2 = 137082, p-value < 0.00000000000000022


Al igual que el tetst de White, la Hipótesis nula es que no hay errores de especificación del modelo. Al realizarlo vemos que tenemos un p-valor de 0.513, lo que indica que no tenemos evidencia para creer que hay errores de especificación, por lo que el modelo sí está bien especificado.


3.3 Plot de diagnóstico para la regresión


par(mfrow = c(2,2))

plot(ejemplo)


¿Cómo interpretar esto?

  • Residuales vs ajustados: Se usa para chequear los supuestos de linearidad de la regresión. La linea horizontal, sin patrones cambios significativos es una indicación de una relación lineal, lo cual es bueno.

La eventual presencia de patrones de movimiento de la línea indicarían algún problema del modelo lineal.

  • Normal Q-Q: Usado para examinar si los residuos están normalmente distribuídos. Es bueno su los puntos de los residuos siguen la linea recta dibujada. En nuestro caso se comienza a levantar así que hay indicios de que los residuos no están normalmente distribuídos.

  • Scale-location:: Usado para chequear la homogeneidad de la varianza de los residuos (u homocedasticidad). La línea horizontal con dispersión de puntos equivalente es un buen indicio de homogeneidad de varianza.

En nuestro caso se ve relativamente bien pero tiene un paulatino levantamiento en la zona derecha que muestra que no es perfecta. Eso puede ser una señal de heterocedascitidad a pesar del test anterior.

Habitualmente una forma de arreglar esto es adecuar la escala de la variable dependiente, como por ejemplo transformarla a logaritmo raíz cuadrada.

Sólo por curiosidad, probamos esta técnica en nuestr modelo:


ejemplo2 <- lm(log(ytotcor) ~ Exp, data = casen_corta)

plot(ejemplo2, 3)


En nuestro caso pasarlo a logaritmo ha incrementado la diferencia en la medida que aumentaba la experiencia, dando mayores señales de heterocedasticidad.

  • Residuos vs Leverage: Usado para identificar casos influyentes o outliers. Son los valores extremos que están influyendo el resultado de la regresión.

Los outliers pueden ser identificados examinando los residuos estandarizados, los cuales son los residuos dividido por su error estandar estimado. Los residuos estandarizados pueden ser interpretados como el número de errores estandar fuera de la linea de regresión.

Por otra parte, los valores influyentes son valores que, en su inclusión o exclusión, pueden alterar los resultados del análisis de regresión. Ese valor está asociado a un residuo grande. En este sentido, es importante señalar que no todos los outliers son influyentes.

Para medir esto se ha desarrollado la distancia de Cook para determinar la influencia de un valor. Esta métrica define influencia como la combinación de apalancamiento (leverage) y tamaño de residuo.

Una forma de ver la influencia con la distancia de cook es que exceda \(\frac{4}{n - p - 1}\), donde \(n\) es el número de observaciones y \(p\) es el número de variables predictoras.

plot(ejemplo, 4)

plot(ejemplo, 5)


En el gráfico residuals vs leverage, los valores outliers que son influyentes se ubican en la esquina superior derecha y la esquina inferior derecha. En nuestro caso, casi no tenemos valores de ese tipo, salvo tres claramente marcados y uno en particular.


3.4 Regresión lineal multivariada y testeo de multicolinealidad

En este caso agregaremos otras variables que pueden estar explicando la variabilidad del ingreso sumando la edad y el sexo de la persona:


ingreso_multi <-lm(ytotcor ~ Exp + edad + SexDum , data = casen_corta)

stargazer::stargazer(ingreso_multi, type = "html")


Para terminar con los análisis de supuestos, analizaremos la multicolinealidad perfecta. Su aparición es compleja pues implicaría que no hay ortogonalidad en los regresores, lo que haría engañosa la interpretación de esta regresión.

Para testearla haremos una matriz de correlaciones entre las variables explicativas:

casen_matrix <-casen_corta%>%
  dplyr::select(Exp, edad, SexDum)

casen_matrix%>%
  cor(method = "pearson")%>%
  round(digits = 2) ->matcor

matcor


Como esta regresión es pequeña y sólo tiene 3 regresores es fácil de observar los problemas de colinealidad casi perfecta qe hay entre edad y experiencia (se entiende, pues experiencia fue creada a partir de esta variable). Pero cuando tenemos 5, 6 o 10 regresores vale la pena tener herramientas gráficas para observarla. las mostramos a continuación:


corrplot(matcor, type = "upper", order = "hclust", tl.col = "black")


De esta forma tenemos herramientas detalladas para analizar la multicolinealidad.

10. Regresiones con una variable dependiente Binaria (Logit y Probit)


Cuando se trata de una variable dependiente binaria, hay que interpretar la función de regresión como una predicción de probabilidad.

Si Y es una variable binaria 0 o 1, su valor esperado (o media) es la probabilidad de \(Y = 1\), osea:

\[E(Y) = 0 * Pr(Y = 0) + 1 * Pr(Y = 1) = Pr (Y = 1)\]

n el contexto de regresión, el valor esperado está condicionado al valores de los regresores, por lo tanto la probabilidad está condicionada a \(X\).

Por ejemplo, el modelo de probabilidad lineal (que no vimos en clases y no profundizaré más que por temas pedagógicos) está dado por:

\[Pr(Y = 1 | X_1, X_2,..., X_kn)= \beta_0 + \beta_1X_1 + \beta_2X_2 + ... \beta_kX_k\]

Donde el coeficiente \(\beta_1\) es la probabilidad de \(Y = 1\) cuando \(X_1\), ceteris paribus. Esos coeficientes se estiman por MCO ya que es una probabilidad lineal.

¿Cuál es el problema de esto? que raras veces las probabilidades son lineales, además que hace que valores muy bajos de \(X\) den números negativos y se supone que son entre 0 y 1. No tiene sentido.

Es por eso que se usan otros modelos de regresión, como el Logit y Probit.

Para esta sección usaremos la encuesta CEP de Diciembre de 2022, para analizar la probabilidad de aprobar el gobierno de Gabriel Boric.


4.1 Regresión Probit


Este es un modelo de regresión no-lineal para variables dependientes binarias, que se expresa en la siguiente fórmula:

\[Pr(Y = 1 | X) = \Phi (\beta_0 + \beta_1X)\] Done \(\Phi\) es una función de distribución de probabilidades acumulada normal estandar.

EN el caso de tener múltiples regresores siemplemente se agregan a la función de distribución de probabilidad:

\[Pr(Y = 1 | X_1, X_2) = \Phi(\beta_0, \beta_1X_1 + \beta_2X_2)\]

Puntualmente ¿Qué provca la varación de \(X\) en \(Y\)? Lo que provoca es un cambio en la esperanza condicional; es decir, en la probabilidad condicional de que \(Y = 1\).

Para ejemplificar este modelo, vamos a analizar la probabilidad de obtener el Ingreso ético familiar a pasar de la proporción de hijos dentro del número familiar. Esto lo haremos en base a la encuesta CASEN 2017:

el código resumido (con las variables ya construídas) es el siguiente:


CasenFiltra <-readRDS(file = "casenfiltrada1.RDS")

Asigna_probit <-glm(AsignaFam ~ partninos, family = binomial(link = "probit"), data = CasenFiltra)

stargazer::stargazer(Asigna_probit, type = "html")


Vemos que la regresión muestra que la variable elegida es significativa al 99%, y que el cambio de proporción de niños en el hogar en una unidad aumenta un 59% de unidades probit para obtener el Ingreso ético familiar. Suena raro eso de “Unidades probit” no? ya lo resolveremos cuando veamos efectos marginales.


4.2 Regresión Logit


Es una función similar a la probit, sólo que la función de distribución de probabilidad es logística estándar:

\[Pr(Y = 1 | X_1, X_2,..., X_k) = F(\beta_0 + \beta_1 + \beta_2X_2 + ... + \beta_kX_k) = \frac{1}{1 + e^{(\beta_0 + \beta_1X_1 + \beta_2X_2 + .. + \beta_kX_k)}}\]


Donde \(F\) Es la función de distribución de probabilidad logística. También se puede estimar por método de máxima verosimilitud.

Al igual que Probit, el Logit es más fácil de interpretar calculando las probabilidades estimadas y diferencias entre probabilidades estimadas.

Utilizando el mismo ejemplo del modelo Probit, para ver el cambio de probabilidad de obtener el Ingreso Ético familiar en base a la proporción de niños en el hogar.

AsignaLogit<- glm(AsignaFam ~ partninos, data = CasenFiltra, family = binomial(link = "logit"))

stargazer::stargazer(AsignaLogit, type = "html")


En esta regresion vemos que el cambio es mucho más acentuado que el probit. por cada unidad de cambio en la proporción de niños en el núcleo familiar aumenta 1.4 veces unidades logit la probabilidad de obtener el ingreso ético familiar, al 99% de confianza.


4.3 Regresión Probit y Logit multivariada y efectos marginales

Al igual que las regresiones lineales multivariadas, podemos agregas tantas variables explicativas deseamos considerando la cantidad de observaciones que tenemos.

Para tener resultados que sean interpretables es importante transformar estas regresiones en predicciones para valores específicos (como lo hace la función predict en R), pero también del cambio marginal promedio a partir del cálculo de efectos marginales.

dejamos el código de la regresión multivariada Probit y Logit donde buscamos observar si el Ingreso Percápita total, la escolaridad del jefe de familia, la condición de ruralidad, cantidad de adultos mayores en la familia, si el jefe del hogar es mujer, la cantidad de integrantes en el núcleo y la presencia de discapacitados afecta a la probabilidad de obtener el Ingreso ético familiar:


Asigna_probit_multi <-glm(AsignaFam ~ PercapTotal + escojefe + partninos + rural + partmujer + partadultmayor + jefemujermonoparental + jefemujer + intergrantesnucl + Disca, family = binomial(link = "probit"), data = CasenFiltra)


Asigna_logit_multi <- glm(AsignaFam ~ PercapTotal + escojefe + partninos + rural + partmujer + partadultmayor + jefemujermonoparental + jefemujer + intergrantesnucl + Disca, family = binomial(link = "logit"), data = CasenFiltra)

stargazer::stargazer(Asigna_probit_multi, type = "html")

stargazer::stargazer(Asigna_logit_multi, type = "html")


En estos resultados vemos algunas diferencias que son relevantes. En términos de significancia estadística, el modelo Probit destaca el Percapita total, la proporción de niños en núcleo familiar y la cantida de integrantes por núcleo familiar. En la magnitud del cambio el Ingreso percapita total tiende a cero, por lo que no hay mayor cambio, mientras que la concentración de niños lllega hasta 50% unidades probit más, y el aumento en un integrante más por núcleo lleva a 22% unidades Probit más de probabilidad de tener la asignación. Por otra parte el modelo Logit agrega que si el jefe de hogar es mujer aumenta considerablemente la probabilidad de obtener este Ingreso especial, así como los valores de magnitud tanto en la proporción de niños y el número de integrantes del núcleo familiar es mayor.

¿Cómo se puede justificar esta diferencia? Es imposrtante recordar que los modelos Probit, al distribuir con funciones de probabilidad acumulada estándar, son algo màs sensibles a los outliers, y quizás esa sea la razón. Sin embargo siempre es importante testear ambos modelos para observar la consistencia de la estimación y del modelo.

Ahora pasaremos a cómo interpretar esta información. Es muy importante poder traspasar estas regresiones probabilidades para poder interpretar los resultados.

A continuación dejamos los efectos marginales promedio de la regresión Probit:


test1 <-margins(Asigna_probit_multi)

test2 <-as_tibble(summary(test1))
test2 %>% dplyr::select(factor, AME, lower, upper,p) 


Esto nos entrega una tabla regumen con los efectos marginales promedios (AME) por cada variable explicativa, así como el límite inferior (lower) y el máximo (upper) de cada una de ellas.

Luego de eso creamos un gráfico con los efectos marginales de cada uno:


p1 <- ggplot(data = test2, aes(x = reorder(factor, AME),
                              y = AME, ymin = lower, ymax = upper))

p1 + geom_hline(yintercept = 0, color = "blue") +
  geom_pointrange() + coord_flip() +
  labs(x = NULL, y = "Average Marginal Effect", title = "Efectos Marginales Promedio para Asignación de Ingreso Ético Familiar  \n en base a modelo Probit") 


Así, tenemos una forma gráfica de ver qué tan distantes del 0 y en qué sentido se encuentra el cálculo de probabilidad promedio en cada una. Confirmamos entonces que por cada cambio unitario en el porcentaje de niños en el grupo familiar aumenta casi un 3% la probabilidad de asignación familiar, seguido por la cantida dde integrante del número, y por otro lado la cantidad de mujeres tiene un efecto negativo en la probabilidad de obtener el beneficio.

Veamos con el modelo Logit:


test3 <-margins(Asigna_logit_multi)

test4 <-as_tibble(summary(test3))
test4 %>% dplyr::select(factor, AME, lower, upper,p) 


p1 <- ggplot(data = test4, aes(x = reorder(factor, AME),
                              y = AME, ymin = lower, ymax = upper))

p1 + geom_hline(yintercept = 0, color = "blue") +
  geom_pointrange() + coord_flip() +
  labs(x = NULL, y = "Average Marginal Effect", title = "Efectos Marginales Promedio para Asignación de Ingreso Ético Familiar  \n en base a modelo Logit") 

Finalmente, vemos que las grandes diferencias que habíamos visto anteriormente entre los dos modelos no eran tal, y de hecho se comportan de forma muy fimilar una del otro.

4.4 Diferencias entre Logit, Probit y probabilidad lineal

**Las regresiones logit y probit son casi iguales. Se usa más la logit porque era más rápida de calcular a mano que la Probit. Luego del avance de capacidades computacionales su diferencia se volvió irrelevante.


Entonces: ¿Cuáles usar?


  1. Los tres son aproximaciones de funciones de regresión poblacional desconocidas. es decir \(E(Y | X) = Pr(Y = 1 | X)\).
  2. Modelos de probabilidad lineal es + fácil pero es malo, pues no capta la naturaleza no lineal de la verdadera función poblacional.
  3. Modelos Probit y Logit dan resultados muy similares.


4.4 Estimación por Máxima verosimilitud


La estimación por máxima verosimilitud es una de las varias formas de estimar modelos Logit y Probit; otro ejemplo es la estimación por Mínimos Cuadrados no lineales pero que no hablaremos acá. Lo fundamental es entender es que la estimación por máxima verosimilitud hace posible estimar una función Logit o Probit.

Primero se parte con una función de verosimilitud, que es una distribución de probabilidad conjunta de los datos considerada como una función de los coeficientes desconocifod. Por otro lado el estimador de máxima verosimilitud (EMV) de los coeficientes desconocidos está compuesto por los valore sde los coeficientes que maximizan la función de verosimilitud. En este sentido, el EMV son los valores de los parámetros que “más probablemente” hayan generado los datos.


4.5 Medidas de ajuste: Pseudo \(R^2\)


el Pseudo \(R^2\) mide el ajuste del modelo mediante la función de verosimilitud. Entonces lo que hace esta medida es medir la calidad del ajuste mediante la comparación del valor de la función de verosimilitud maximizada con todas las variables explicativas con el valor de la función de verosimilitud sin regresores.

Si quiero obtener el pseudo \(R^2\) de la regesión se realiza con el siguiente código:


# Carga de librerías y datos de ejemplo
library(pscl)

# Cálculo del Pseudo R-cuadrado y adición a la tabla
tabla <- summary(Asigna_probit_multi)$coef
tabla$Pseudo_R2 <- pR2(Asigna_probit_multi)

# Mostrar la tabla con el Pseudo R-cuadrado
tabla


Acá podemos ver seis tipos de cálculos de pseudo \(R^2\) y nos indican que el modelo se ajusta terriblemente mal. No explica nada.