En este último encuentro, abordaremos herramientas fundamentales del análisis estadístico básico: la construcción e interpretación de tablas de frecuencia para variables cualitativas y cuantitativas, el cálculo de medidas de resumen, y la estimación de coeficientes de asociación que nos permiten cuantificar relaciones entre variables.

Repasemos un poco lo que vimos en los encuentros anteriores:

Carga y exploración inicial de los datos

Seteo el directorio y cargo los datos

Es una buena práctica setear el directorio de trabajo antes de comenzar a trabajar, ya sea con la función setwd("ruta") o desde SessionSet Working DirectoryChoose Directory….

setwd("~/CursoR_docentes")

Importamos los datos_excel utilizando la función read_excel() del paquete readxl., o bien desde FileImport DatasetFrom Excel, seleccionamos el archivo y si la vista previa es correcta damos clic en Import.

library(readxl)
datos_excel <- read_excel("datos_excel.xlsx", #Ruta del archivo
                          sheet = 1)    #Puedo elegir una hoja específica

Carga de paquetes

Cargamos los paquetes que vamos a utilizar usando la función library() (recordar que previamente tenemos que tener el paquete instalado).

library(tidyverse) 
library(janitor)

Exploramos la estructura de los datos

class(datos_excel) # para ver qué estructura tienen los datos
## [1] "tbl_df"     "tbl"        "data.frame"
dim(datos_excel) # para ver cuántas filas (observaciones) y columnas (variables) tiene el data set
## [1] 25  6
head(datos_excel) # para mirar los primeros registros
## # A tibble: 6 × 6
##   Nombre_Fondo         Tipo_Fondo Activos_Netos Rentabilidad_5_Años Ratio_Gastos
##   <chr>                <chr>              <dbl>               <dbl>        <dbl>
## 1 American Century In… Capital i…          14.4               30.5          1.41
## 2 American Century Ta… Renta fija          10.7                3.34         0.49
## 3 American Century Ul… Capital n…          24.9               10.9          0.99
## 4 Artisan Small Cap    Capital n…          16.9               15.7          1.18
## 5 Brown Cap Small      Capital n…          35.7               15.8          1.2 
## 6 DFA U.S. Micro Cap   Capital n…          13.5               17.2          0.53
## # ℹ 1 more variable: Ranking_Morningstar <chr>
names(datos_excel) # para ver el nombre de las variables
## [1] "Nombre_Fondo"        "Tipo_Fondo"          "Activos_Netos"      
## [4] "Rentabilidad_5_Años" "Ratio_Gastos"        "Ranking_Morningstar"
str(datos_excel) # para obtener un resumen general de un conjunto de datos
## tibble [25 × 6] (S3: tbl_df/tbl/data.frame)
##  $ Nombre_Fondo       : chr [1:25] "American Century Intl. Disc" "American Century Tax-Free Bond" "American Century Ultra" "Artisan Small Cap" ...
##  $ Tipo_Fondo         : chr [1:25] "Capital internacional" "Renta fija" "Capital nacional" "Capital nacional" ...
##  $ Activos_Netos      : num [1:25] 14.4 10.7 24.9 16.9 35.7 ...
##  $ Rentabilidad_5_Años: num [1:25] 30.53 3.34 10.88 15.67 15.85 ...
##  $ Ratio_Gastos       : num [1:25] 1.41 0.49 0.99 1.18 1.2 0.53 0.89 0.9 0.89 0.45 ...
##  $ Ranking_Morningstar: chr [1:25] "3-star" "4-star" "3-star" "3-star" ...

Visualización y tratamiento de valores faltantes

Antes de comenzar cualquier análisis es importante, además de observar la estructura de los datos, controlar si no tenemos valores faltantes:

colSums(is.na(datos_excel))
##        Nombre_Fondo          Tipo_Fondo       Activos_Netos Rentabilidad_5_Años 
##                   0                   0                   1                   0 
##        Ratio_Gastos Ranking_Morningstar 
##                   0                   0

Recordemos que algunas estrategias para el tratamiento de valores faltantes que vimos eran:

  • Omitir las filas con NA.
  • Reemplazar por un valor definido (por ejemplo, 0 o “Sin dato”).
  • Reemplazar por la media (en una variable numérica).

Reemplacemos el valor faltante por el promedio de la variable:

media_AN=mean(datos_excel$Activos_Netos, na.rm=T)
# Reemplazar NA por la media
datos_nvos <- datos_excel %>%
  mutate(Activos_Netos = replace_na(Activos_Netos, media_AN))
#chequeamos si hay NA
colSums(is.na(datos_nvos))
##        Nombre_Fondo          Tipo_Fondo       Activos_Netos Rentabilidad_5_Años 
##                   0                   0                   0                   0 
##        Ratio_Gastos Ranking_Morningstar 
##                   0                   0

Transformación de datos con dplyr

Juguemos un poco con algunas de las funciones de transformación de datos con dplyr que comentamos:

1- Seleccionemos las variables Tipo_Fondo y Rentabilidad_5_Años:

dos_variables <- datos_excel %>%
  select(Tipo_Fondo, Rentabilidad_5_Años)

2- Transformemos la variable Tipo de Fondo en Renta Variable y Renta Fija:

dos_variables <- dos_variables %>%
  mutate(Tipo_Fondo = case_when(
    Tipo_Fondo == "Capital internacional" ~ "Renta variable",
    Tipo_Fondo == "Capital nacional" ~ "Renta variable",
    TRUE ~ Tipo_Fondo # el resto de los fondos se consideran Renta fija
  ))

3- Construyamos la variable categórica Rentabilidad según el siguiente esquema:

  • Poco rentable: ≤ 13.41
  • Rentable: > 13.41 y ≤ 17.01
  • Muy rentable: > 17.01
dos_variables <- dos_variables %>%
  mutate(rentabilidad_cat = case_when(
    Rentabilidad_5_Años <= 13.41 ~ "Poco rentable",
    Rentabilidad_5_Años > 13.41 & Rentabilidad_5_Años <= 17.01 ~ "Rentable",
    Rentabilidad_5_Años > 17.01 ~ "Muy rentable"
  ))

Gráficas con ggplot2

Realicemos algunos gráficos básicos:

# Gráfico de barras
ggplot(data = dos_variables, aes(x = rentabilidad_cat)) +
  geom_bar() +
  labs(title = "Gráfico de barra", x = "Rentabilidad categorizada", y = "Frecuencia")

# Histograma
ggplot(data = dos_variables, aes(x = Rentabilidad_5_Años)) +
  geom_histogram(bins = 8, color = "white", boundary = 0) +
  labs(title = "Histograma", x = "Rentabilidad de los últimos 5 años", y = "Frecuencia")

# Boxplot
ggplot(data = dos_variables, aes(y = Rentabilidad_5_Años, x=Tipo_Fondo)) +
  geom_boxplot() +
  labs(title = "Boxplot", x = "", y = "Rentabilidad de los últimos 5 años")

Tablas de frecuencia

Las tablas de frecuencia permiten organizar y resumir datos tanto de variables cualitativas como cuantitativas.

Para una variable cualitativa

Podemos construir la frecuencia absoluta usando la función count():

tabla_RM <- datos_excel %>% 
  count(Ranking_Morningstar) %>% # para contar
  rename(Frecuencia=n) %>% # para renombrar la variable "n" que hicimos en la capa anterior
  adorn_totals() # para agregarle el Total

tabla_RM 
##  Ranking_Morningstar Frecuencia
##               2-star          1
##               3-star         12
##               4-star         10
##               5-star          2
##                Total         25

Podemos agregarle la frecuencia relativa porcentual:

tabla_RM <- datos_excel %>% 
  count(Ranking_Morningstar) %>% # para contar
  rename(Frecuencia=n) %>% # para renombrar la variable "n" que hicimos en la capa anterior
  mutate(`Frecuencia porcentual`=round(Frecuencia/sum(Frecuencia)*100)) %>% # para calcular la frecuencia relativa porcentual
  adorn_totals() # para agregarle el Total

tabla_RM
##  Ranking_Morningstar Frecuencia Frecuencia porcentual
##               2-star          1                     4
##               3-star         12                    48
##               4-star         10                    40
##               5-star          2                     8
##                Total         25                   100

Para una variable cuantitativa

En el caso de las variables cuantitativas discretas, en general podemos repetir el procedimiento visto para las variables cualitativas: contar cuántas veces aparece cada uno de sus posibles valores en nuestros datos. Pero cuando la variable es cuantitativa continua, debemos primero armar intervalos para agrupar los distintos valores.

Esto lo hacemos con la función cut(), en la cual ponemos como argumento la variable a categorizar y la cantidad de intervalos o categorías, y categoriza la variable según la cantidad de puntos de cortes que le ingresamos.

Si bien hay varias fórmulas para calcular la cantidad de intervalos a construir para la distribución de una variable cuantitativa continua, una muy conocida es la de Sturges. En R podemos usar la función nclass.Sturges() para aplicar esa fórmula y obtener cuántos intervalos debería haber.

cant_clases=nclass.Sturges(datos_excel$Rentabilidad_5_Años)
cant_clases
## [1] 6
tabla_Rent <- datos_excel %>%
  mutate(intervalo = cut(Rentabilidad_5_Años, cant_clases)) %>% 
  count(intervalo, .drop = FALSE) %>% # el argumento  .drop = FALSE permite conservar los intervalos aunque tengan frecuencia 0
  rename(Frecuencia = n) %>% 
  mutate(`Frecuencia porcentual`=round(Frecuencia/sum(Frecuencia)*100)) %>%
  adorn_totals()

tabla_Rent
##    intervalo Frecuencia Frecuencia porcentual
##  (2.32,10.5]          5                    20
##  (10.5,18.6]         15                    60
##  (18.6,26.7]          2                     8
##  (26.7,34.9]          2                     8
##    (34.9,43]          0                     0
##    (43,51.1]          1                     4
##        Total         25                   100

Para dos variables cualitativas

Las tablas de doble entrada o tablas de contingencia permiten resumir la relación entre dos variables cualitativas. Se pueden construir fácilmente con la función tabyl(), indicando como argumentos las dos variables: la primera se organiza por filas y la segunda por columnas.

tabla_dos <- dos_variables %>%
  tabyl(Tipo_Fondo , rentabilidad_cat) %>% 
  adorn_totals("both") # con el argumento "both" agrega totales por filas y por columnas

tabla_dos
##      Tipo_Fondo Muy rentable Poco rentable Rentable Total
##      Renta fija            0             4        1     5
##  Renta variable            7             3       10    20
##           Total            7             7       11    25

Medidas de resumen

Las medidas de resumen describen características centrales y de dispersión de las variables numéricas.

dos_variables %>%
  summarise(
    media = mean(Rentabilidad_5_Años),
    mediana = median(Rentabilidad_5_Años),
    desv_std = sd(Rentabilidad_5_Años),
    min = min(Rentabilidad_5_Años),
    max = max(Rentabilidad_5_Años),
    Q1 = quantile(Rentabilidad_5_Años, 0.25),
    Q3 = quantile(Rentabilidad_5_Años, 0.75)
  )
## # A tibble: 1 × 7
##   media mediana desv_std   min   max    Q1    Q3
##   <dbl>   <dbl>    <dbl> <dbl> <dbl> <dbl> <dbl>
## 1  16.5    15.5     10.4  2.37  51.1  13.4  17.2

Desagregadas por Tipo de Fondo:

dos_variables %>%
  group_by(Tipo_Fondo) %>%
  summarise(media = mean(Rentabilidad_5_Años),
            mediana = median(Rentabilidad_5_Años),
            desv = sd(Rentabilidad_5_Años),
            n = n())
## # A tibble: 2 × 5
##   Tipo_Fondo     media mediana  desv     n
##   <chr>          <dbl>   <dbl> <dbl> <int>
## 1 Renta fija      5.27    3.34  4.70     5
## 2 Renta variable 19.3    16.3   9.50    20

Medidas de asociación

Las medidas de asociación permiten cuantificar el grado de relación entre dos variables. El tipo de medida a utilizar depende del tipo de variables involucradas. En la tabla que sigue presentamos las más utilizadas:

Tipo de variable Medida Función en R Uso
Dos cuantitativas Coeficiente de correlación de Pearson cor(x, y, method = 'pearson') Su valor varía entre -1 y 1.
Dos cualitativas nominales Coeficiente V de Cramer DescTools::CramerV(tabla) Su valor varía entre 0 y 1.
Dos cualitativas ordinales Coeficiente de correlación de Spearman cor(x, y, method = 'spearman') Su valor varía entre -1 y 1.

Calculemos algunas para nuestras variables:

cor(datos_excel$Rentabilidad_5_Años, datos_excel$Ratio_Gastos, method = "pearson")
## [1] 0.4926285
# Usamos la función CramerV del paquete DescTools sin cargar todo el paquete con library(). Igualmente primero debe instalarse el paquete!
DescTools::CramerV(table(dos_variables$Tipo_Fondo, dos_variables$rentabilidad_cat))
## [1] 0.586648

Práctica con EPH

Para cerrar el curso trabajemos con alguna de las bases de la Encuesta Permanente de Hogares. Carguemos el paquete eph e importemos la base de datos individual del 4to trimestre de 2024:

library(eph)
base <- get_microdata(year = 2024, trimester = 4, type='individual', vars ="all")

Miremos la dimensión y el nombre de las variables:

dim(base)
## [1] 46860   235
names(base)
##   [1] "CODUSU"     "ANO4"       "TRIMESTRE"  "NRO_HOGAR"  "COMPONENTE"
##   [6] "H15"        "REGION"     "MAS_500"    "AGLOMERADO" "PONDERA"   
##  [11] "CH03"       "CH04"       "CH05"       "CH06"       "CH07"      
##  [16] "CH08"       "CH09"       "CH10"       "CH11"       "CH12"      
##  [21] "CH13"       "CH14"       "CH15"       "CH15_COD"   "CH16"      
##  [26] "CH16_COD"   "NIVEL_ED"   "ESTADO"     "CAT_OCUP"   "CAT_INAC"  
##  [31] "IMPUTA"     "PP02C1"     "PP02C2"     "PP02C3"     "PP02C4"    
##  [36] "PP02C5"     "PP02C6"     "PP02C7"     "PP02C8"     "PP02E"     
##  [41] "PP02H"      "PP02I"      "PP03C"      "PP03D"      "PP3E_TOT"  
##  [46] "PP3F_TOT"   "PP03G"      "PP03H"      "PP03I"      "PP03J"     
##  [51] "INTENSI"    "PP04A"      "PP04B_COD"  "PP04B1"     "PP04B2"    
##  [56] "PP04B3_MES" "PP04B3_ANO" "PP04B3_DIA" "PP04C"      "PP04C99"   
##  [61] "PP04D_COD"  "PP04G"      "PP05B2_MES" "PP05B2_ANO" "PP05B2_DIA"
##  [66] "PP05C_1"    "PP05C_2"    "PP05C_3"    "PP05E"      "PP05F"     
##  [71] "PP05H"      "PP06A"      "PP06C"      "PP06D"      "PP06E"     
##  [76] "PP06H"      "PP07A"      "PP07C"      "PP07D"      "PP07E"     
##  [81] "PP07F1"     "PP07F2"     "PP07F3"     "PP07F4"     "PP07F5"    
##  [86] "PP07G1"     "PP07G2"     "PP07G3"     "PP07G4"     "PP07G_59"  
##  [91] "PP07H"      "PP07I"      "PP07J"      "PP07K"      "PP08D1"    
##  [96] "PP08D4"     "PP08F1"     "PP08F2"     "PP08J1"     "PP08J2"    
## [101] "PP08J3"     "PP09A"      "PP09A_ESP"  "PP09B"      "PP09C"     
## [106] "PP09C_ESP"  "PP10A"      "PP10C"      "PP10D"      "PP10E"     
## [111] "PP11A"      "PP11B_COD"  "PP11B1"     "PP11B2_MES" "PP11B2_ANO"
## [116] "PP11B2_DIA" "PP11C"      "PP11C99"    "PP11D_COD"  "PP11G_ANO" 
## [121] "PP11G_MES"  "PP11G_DIA"  "PP11L"      "PP11L1"     "PP11M"     
## [126] "PP11N"      "PP11O"      "PP11P"      "PP11Q"      "PP11R"     
## [131] "PP11S"      "PP11T"      "P21"        "DECOCUR"    "IDECOCUR"  
## [136] "RDECOCUR"   "GDECOCUR"   "PDECOCUR"   "ADECOCUR"   "PONDIIO"   
## [141] "TOT_P12"    "P47T"       "DECINDR"    "IDECINDR"   "RDECINDR"  
## [146] "GDECINDR"   "PDECINDR"   "ADECINDR"   "PONDII"     "V3_M"      
## [151] "V4_M"       "V8_M"       "V9_M"       "V10_M"      "V12_M"     
## [156] "V18_M"      "V19_AM"     "T_VI"       "ITF"        "DECIFR"    
## [161] "IDECIFR"    "RDECIFR"    "GDECIFR"    "PDECIFR"    "ADECIFR"   
## [166] "IPCF"       "DECCFR"     "IDECCFR"    "RDECCFR"    "GDECCFR"   
## [171] "PDECCFR"    "ADECCFR"    "PONDIH"     "V2_02_M"    "V2_03_M"   
## [176] "V5_03_M"    "V11_02_M"   "PP07B1_01"  "EMPLEO"     "SECTOR"    
## [181] "PP02A"      "PP02B"      "PP02D"      "PP02F"      "PP02G"     
## [186] "PP03K"      "PP04A1"     "PP05B3"     "PP05I"      "PP05J"     
## [191] "PP05K"      "PP06E1"     "PP06K"      "PP06K_SEM"  "PP06K_MES" 
## [196] "PP06L"      "PP07F1_1"   "PP07F1_2"   "PP07F1_3"   "PP07I2"    
## [201] "PP07I3"     "PP07I4"     "PP07L"      "PP07M"      "PP08G"     
## [206] "PP08G_DSEM" "PP08G_DMES" "PP08H"      "PP10B1"     "PP10B2"    
## [211] "PP10B3"     "PP10B4"     "PP10B5"     "PP10B6"     "PP10B7"    
## [216] "PP10B8"     "PP10B9"     "PP10B10"    "PP11L2"     "V2_01_M"   
## [221] "V5_01_M"    "V5_02_M"    "V11_01_M"   "V21_01_M"   "V21_02_M"  
## [226] "V21_03_M"   "V22_01_M"   "V22_02_M"   "V22_03_M"   "P_DECCF"   
## [231] "P_RDECCF"   "P_GDECCF"   "P_PDECCF"   "P_IDECCF"   "P_ADECCF"

Para ver qué mide cada una podemos consultar el Diseño de registros y estructura para las bases preliminares Hogar y Personas.

Vamos a trabajar con los datos del aglomerado Gran Paraná. Para ello debemos filtrar el AGLOMERADO 6:

parana <- base %>% 
  filter(AGLOMERADO==6)

Trabajemos con la variable sexo (CH04) y edad (CH06). Realicemos las transformaciones necesarias y construyamos tablas, gráficos y medidas de resumen:

# Recodificamos sexo y la renombramos
parana <- parana %>% 
  mutate(CH04=case_when( CH04 == 1 ~ "Varon",
                         CH04 == 2 ~ "Mujer")) %>% 
  rename(Sexo=CH04)

# Chequeamos si hay valores faltantes en sexo
sum(is.na(parana$Sexo))
## [1] 0
# Gráfico de barras
ggplot(parana, aes(x=Sexo, fill=Sexo))+
  geom_bar()

# Tabla de frecuencias
tabla_sexo <- parana %>% 
  count(Sexo) %>% 
  rename(Frecuencia=n) %>% 
  mutate(`Frecuencia porcentual`=round(Frecuencia/sum(Frecuencia)*100)) %>% 
  adorn_totals()

tabla_sexo
##   Sexo Frecuencia Frecuencia porcentual
##  Mujer        752                    53
##  Varon        674                    47
##  Total       1426                   100
# Renombrarmos edad
parana <- parana %>% 
  rename(Edad=CH06)

# Chequeamos si hay valores faltantes en edad
sum(is.na(parana$Edad))
## [1] 0
# Para ver en cuántos intervalos deberíamos categorizarla
cant_int_edad = nclass.Sturges(parana$Edad)
cant_int_edad
## [1] 12
# Gráficos: histograma y boxplot
ggplot(parana, aes(x=Edad))+
  geom_histogram(bins=12, col="white")

ggplot(parana, aes(x=Edad))+
  geom_boxplot()

# Tabla de frecuencias
tabla_Edad <- parana %>% 
  mutate(intervalos=cut(Edad, cant_int_edad)) %>% 
  count(intervalos) %>% 
  rename(Frecuencia=n) %>% 
  mutate(`Frecuencia porcentual`=round(Frecuencia/sum(Frecuencia)*100)) %>% 
  adorn_totals()

tabla_Edad
##  intervalos Frecuencia Frecuencia porcentual
##    (-1.1,7]        117                     8
##      (7,15]        179                    13
##     (15,23]        163                    11
##     (23,31]        174                    12
##     (31,39]        146                    10
##     (39,47]        159                    11
##     (47,55]        130                     9
##     (55,63]        113                     8
##     (63,71]        116                     8
##     (71,79]         81                     6
##     (79,87]         37                     3
##   (87,95.1]         11                     1
##       Total       1426                   100
# Medidas de resumen
medidas <- parana %>% 
  summarise(Media=mean(Edad),
            Mediana=median(Edad),
            Desvio=sd(Edad),
            Minimo=min(Edad),
            Maximo=max(Edad))

medidas
## # A tibble: 1 × 5
##   Media Mediana Desvio Minimo Maximo
##   <dbl>   <dbl>  <dbl>  <int>  <int>
## 1  38.0      36   22.8     -1     95
# Análisis de la edad según sexo
# Gráficos
ggplot(parana, aes(x=Edad, fill=Sexo))+
  geom_histogram(bins=12, col="white")+
  facet_grid(~Sexo)

ggplot(parana, aes(x=Sexo, y=Edad, fill=Sexo))+
  geom_boxplot()

# Medidas de resumen
medidas_porSexo <- parana %>% 
  group_by(Sexo) %>% 
  summarise(Media=mean(Edad),
            Mediana=median(Edad),
            Desvio=sd(Edad),
            Minimo=min(Edad),
            Maximo=max(Edad))

medidas_porSexo
## # A tibble: 2 × 6
##   Sexo  Media Mediana Desvio Minimo Maximo
##   <chr> <dbl>   <dbl>  <dbl>  <int>  <int>
## 1 Mujer  39.9    38     23.2     -1     95
## 2 Varon  35.8    33.5   22.3     -1     88