Esta clase introduce el entorno de trabajo que utilizaremos para programar, organizar, analizar y comunicar información económica y social con R. El objetivo no es memorizar comandos aislados, sino comenzar a construir una forma de trabajo reproducible: formular una pregunta, representar la información de manera adecuada, ejecutar transformaciones y documentar lo realizado.
Al finalizar este material deberías poder:
El curso avanza desde los fundamentos de programación y manipulación de datos hacia herramientas de análisis más amplias. El recorrido incluye organización y transformación de información, visualización, calidad de datos, construcción de indicadores, métodos estadísticos, aprendizaje automático, aplicaciones de inteligencia artificial y comunicación reproducible de resultados.
En esta primera clase nos concentraremos en los fundamentos necesarios para que los contenidos posteriores puedan construirse sobre una base de código clara y ordenada. No estimaremos modelos econométricos ni desarrollaremos algoritmos avanzados en este documento.
hogares.tidyverse y manipulación con
dplyr.Pista: piensa en la pregunta de investigación, la estructura de la base, la calidad de los datos, las transformaciones necesarias, el análisis y la comunicación.
Una secuencia razonable sería: definir la pregunta, identificar la unidad de observación, inspeccionar variables y valores faltantes, verificar consistencia, transformar variables cuando sea necesario, producir estadísticas o modelos coherentes con la pregunta y documentar cada decisión. La programación permite que ese flujo pueda repetirse y auditarse.
R es un lenguaje de programación y un entorno libre para computación estadística y gráficos. Puede ejecutar cálculos, manipular datos, estimar modelos, producir gráficos y automatizar tareas.
R puede utilizarse sin RStudio. El motor que evalúa instrucciones es R.
RStudio es un IDE (Integrated Development Environment): una aplicación que reúne editor de código, consola, archivos, gráficos, ayuda, paquetes y herramientas de proyecto en una misma interfaz.
Instalar RStudio no sustituye la instalación de R. Para el flujo habitual de este curso instalaremos primero R y luego RStudio.
Posit es la organización que desarrolla RStudio y otras herramientas de ciencia de datos y publicación técnica. Por eso es común encontrar documentación de RStudio alojada en dominios de Posit.
| Elemento | Función principal |
|---|---|
| R | Lenguaje y motor de cálculo. |
| RStudio | Interfaz de desarrollo para trabajar de forma más organizada con R. |
| Posit | Organización que desarrolla RStudio y otras herramientas. |
Fuentes oficiales:
La disposición exacta puede cambiar según la configuración, pero normalmente encontrarás varios paneles.
Aquí se abren archivos como:
.R, que guardan código;.Rmd, que combinan texto, código y
resultados;| Herramienta | Para qué sirve | Qué conviene recordar |
|---|---|---|
| Consola | Ejecutar instrucciones directamente. | Es útil para explorar, pero no sustituye un archivo de trabajo. |
Script .R |
Guardar y organizar código. | Conserva instrucciones para volver a ejecutarlas. |
Archivo .Rmd |
Integrar texto, código y resultados. | Permite construir documentos reproducibles. |
La consola ejecuta instrucciones. Es útil para probar comandos, pero lo escrito allí no constituye por sí mismo un registro organizado del análisis.
## [1] 4
Resultado esperado: R devuelve 4.
El panel Environment muestra objetos creados en la sesión de R: vectores, bases, matrices, listas y otros objetos.
Para consultar la ayuda de una función:
| Acción | Windows/Linux | macOS |
|---|---|---|
| Ejecutar línea o selección | Ctrl + Enter |
Cmd + Enter |
| Insertar chunk en R Markdown | Ctrl + Alt + I |
Cmd + Option + I |
| Renderizar/Knit | Ctrl + Shift + K |
Cmd + Shift + K |
Insertar <- |
Alt + - |
Option + - |
| Ir al editor | Ctrl + 1 |
Cmd + 1 |
| Ir a la consola | Ctrl + 2 |
Cmd + 2 |
Un proyecto de RStudio organiza archivos relacionados con un análisis dentro de una carpeta de proyecto. Esto facilita trabajar con rutas relativas y evita depender de carpetas particulares de un computador.
Una estructura sencilla podría ser:
mi_proyecto/
├── mi_proyecto.Rproj
├── datos/
├── salidas/
└── analisis.Rmd
Si analisis.Rmd está en la raíz del proyecto, una ruta
como:
se interpreta desde la carpeta del proyecto.
Buena práctica: evita escribir rutas personales
completas y evita depender de setwd() dentro de los
scripts. Los proyectos permiten que el análisis sea más portable.
Para crear un proyecto en RStudio puedes usar File > New Project… y elegir una carpeta nueva o existente.
R Markdown es un formato de autoría que integra en un mismo archivo:
Un archivo .Rmd puede convertirse, entre otros formatos,
en HTML, Word o PDF. En esta clase utilizamos HTML porque permite
navegación, código, tablas y soluciones desplegables de forma
cómoda.
Un análisis es reproducible cuando otra persona —o la misma persona en otro equipo— puede partir del archivo, los datos y las dependencias necesarias y reconstruir los resultados siguiendo el mismo procedimiento.
Reproducibilidad implica, entre otras cosas:
rmarkdown, knitr y Pandoc?De forma simplificada:
rmarkdown coordina el proceso de renderizado y el
formato de salida.knitr ejecuta los chunks y combina código, resultados y
texto.La idea puede representarse así:
archivo .Rmd
↓
knitr
↓
Markdown intermedio
↓
Pandoc
↓
HTML / Word / PDF / otros formatos
El YAML se encuentra entre dos líneas --- al inicio del
archivo. En este documento define título, autor, idioma y opciones de
salida.
---
title: "Clase 1: Introducción a R, RStudio y R Markdown"
subtitle: "Programación y análisis de datos económicos y sociales con R"
author: "Brayan David Castro Rodríguez"
date: "2026-09-10"
lang: es
output:
html_document:
toc: true
toc_depth: 3
toc_float: true
number_sections: true
theme: flatly
highlight: tango
self_contained: true
---La expresión 2026-09-10 inserta la fecha del sistema al
renderizar. self_contained: true busca producir un HTML que
incorpore sus recursos en el propio archivo de salida.
# Título principal
## Subtítulo
### Nivel siguiente
**negrita**
*cursiva*
`código en línea`
Resultado visual: negrita, cursiva y
código en línea.
- Elemento
- Elemento
1. Primer elemento
2. Segundo elemento
[Texto del enlace](https://www.r-project.org/)
La sintaxis general es:

La ruta debe apuntar a un archivo que realmente exista. Usar una ruta relativa al proyecto facilita compartir el análisis.
| Variable | Significado |
|---|---|
| ingreso | Recursos monetarios del hogar |
| gasto | Erogaciones del hogar |
| zona | Clasificación territorial |
| Variable | Significado |
|---|---|
| ingreso | Recursos monetarios del hogar |
| gasto | Erogaciones del hogar |
| zona | Clasificación territorial |
R Markdown permite insertar un resultado pequeño dentro de una frase. Por ejemplo, el valor de \(2^5\) es 32.
Una expresión en línea puede escribirse como \(A_i = Y_i - G_i\), donde \(A_i\) representa ahorro, \(Y_i\) ingreso y \(G_i\) gasto.
También podemos usar una ecuación centrada:
\[
\pi_t = 100\left(\frac{P_t-P_{t-1}}{P_{t-1}}\right),
\]
\[ \pi_t = 100\left(\frac{P_t-P_{t-1}}{P_{t-1}}\right), \]
que representa una tasa de variación porcentual de un índice de precios entre dos observaciones consecutivas.
Un chunk es un bloque ejecutable. En este mismo archivo cada bloque comienza con una cabecera de R, contiene instrucciones y termina con el cierre correspondiente.
Los chunks pueden tener un nombre único. Nombrarlos ayuda a identificar errores y organizar documentos extensos.
Dentro de un chunk, # inicia un comentario de R:
## [1] 2500
| Opción | Qué controla |
|---|---|
echo |
Si el código aparece en la salida. |
eval |
Si el código se ejecuta. |
include |
Si código y resultados se incorporan a la salida. |
results |
Cómo se muestran los resultados de texto. |
message |
Si se muestran mensajes generados por R o paquetes. |
warning |
Si se muestran advertencias. |
fig.width |
Ancho de figuras. |
fig.height |
Alto de figuras. |
fig.align |
Alineación de figuras. |
echo = FALSE: ejecuta, pero oculta el código en el
HTML## [1] 25
El resultado se muestra, aunque el código no aparece en el documento renderizado.
eval = FALSE: muestra el código, pero no lo ejecutaEs útil para enseñar una instrucción que no queremos ejecutar.
include = FALSE: ejecuta y oculta código y resultadosEl objeto valor_interno existe después del chunk, pero
el chunk no aparece en el HTML.
## [1] 56
results = "hide": ejecuta, muestra el código y oculta su
salida de textoEl cálculo sí ocurrió:
## [1] 12
message y warningmessage("Mensaje de demostración")
warning("Advertencia de demostración")
"El resultado ordinario sí permanece visible"## [1] "El resultado ordinario sí permanece visible"
Estas opciones ayudan a evitar que mensajes técnicos secundarios recarguen un informe. No deben utilizarse para ignorar problemas que deberían corregirse.
## [1] 15
## [1] 5
## [1] 50
## [1] 2
## [1] 16
## [1] 5
Funciones matemáticas frecuentes:
## [1] 9
## [1] 2.302585
## [1] 2.718282
## [1] 3.33
## [1] 2
## [1] 3
%% devuelve el residuo de una división.%/% devuelve la parte entera del cociente.Enunciado. Un hogar tiene ingreso mensual de 3.200.000 y gasto mensual de 2.450.000. Calcula el ahorro y la proporción del ingreso destinada al gasto.
Pista. Ahorro = ingreso − gasto. La proporción de gasto se obtiene dividiendo gasto entre ingreso.
ingreso_ejercicio <- 3200000
gasto_ejercicio <- 2450000
ahorro_ejercicio <- ingreso_ejercicio - gasto_ejercicio
proporcion_gasto <- gasto_ejercicio / ingreso_ejercicio
ahorro_ejercicio## [1] 750000
## [1] 0.766
Explicación. Primero se guardan ingreso y gasto en objetos. Después se construyen dos resultados derivados.
Interpretación. El ahorro calculado es una identidad contable para este ejemplo. La proporción de gasto describe cuánto representa el gasto frente al ingreso; no explica por qué el hogar gasta esa proporción.
Un objeto permite guardar un valor para
reutilizarlo. En R utilizaremos principalmente <- para
asignar.
salario_mensual <- 2800000
tasa_ahorro <- 0.12
ahorro_estimado <- salario_mensual * tasa_ahorro
ahorro_estimado## [1] 336000
Un objeto puede recibir un valor nuevo:
## [1] 3000000
## [1] 2500000
## [1] 2700000
ingreso e Ingreso son objetos
distintos.
snake_casePreferiremos nombres como:
ingreso_mensual
gasto_total
numero_personas
tasa_desempleo
Evita nombres ambiguos y evita crear objetos con nombres de funciones
fundamentales como c, mean, data,
matrix o list.
## [1] "ahorro_ejercicio" "ahorro_estimado" "gasto_ejercicio"
## [4] "ingreso" "Ingreso" "ingreso_ejercicio"
## [7] "proporcion_gasto" "resultado_echo" "resultado_guardado"
## [10] "salario_mensual" "tasa_ahorro" "valor_ejemplo"
## [13] "valor_interno"
ls() muestra los nombres de objetos existentes.
rm() elimina objetos. Conviene usarlo de manera
deliberada, no como sustituto de una organización adecuada.
## [1] FALSE
El panel Environment permite observar estos cambios de forma gráfica.
double e
integerEn R, un número escrito como 3 normalmente es de tipo
double. Para crear explícitamente un entero se utiliza el
sufijo L.
## [1] "double"
## [1] "integer"
## [1] "numeric"
## [1] "integer"
character, logical y Datemunicipio_ejemplo <- "Cali"
recibe_apoyo <- TRUE
fecha_registro <- as.Date("2026-09-01")
class(municipio_ejemplo)## [1] "character"
## [1] "logical"
## [1] "Date"
## [1] TRUE
## [1] TRUE
## [1] TRUE
NANA representa un valor faltante. No debe confundirse con
cero, con una cadena vacía ni con la palabra "NA".
## [1] FALSE FALSE TRUE FALSE
## [1] NA
## [1] 2700000
Sin na.rm = TRUE, muchas funciones devuelven
NA si encuentran faltantes.
Técnicamente, NA puede adoptar un tipo compatible con el
vector que lo contiene. R también dispone de formas tipadas como
NA_real_ o NA_character_.
Los vectores atómicos almacenan elementos de un tipo compatible. Si mezclamos números y texto, R puede convertir todo a texto.
## [1] "1" "2" "3"
## [1] "character"
"2500" es texto;
2500 es numérico.
Enunciado. Crea un vector con cuatro tasas de
desempleo simuladas: 9.2, 10.1, un valor
faltante y 8.7. Identifica los faltantes y calcula el
promedio ignorándolos.
Pista. Usa c(), is.na() y
mean(..., na.rm = TRUE).
## [1] FALSE FALSE TRUE FALSE
## [1] 9.333333
Explicación. is.na() produce un vector
lógico que marca la posición faltante. na.rm = TRUE indica
que el resumen se calcule con los valores disponibles.
Interpretación. El promedio describe únicamente las observaciones no faltantes. Antes de interpretar una base real habría que estudiar por qué faltan datos; en esta clase no realizaremos imputación.
## [1] TRUE
## [1] TRUE
## [1] TRUE
## [1] TRUE
Una función recibe uno o más argumentos, realiza una
operación y devuelve un resultado. Su forma general puede pensarse como
nombre_funcion(argumentos).
## [1] 13
## [1] 13
## [1] 4
Los argumentos pueden pasarse por posición o por nombre. Escribir
nombres como digits = 1 o na.rm = TRUE suele
mejorar la legibilidad cuando el significado del argumento no es
evidente.
Para aprender una función, combina tres preguntas: ¿qué recibe?, ¿qué devuelve? y ¿qué argumentos cambian su comportamiento? La ayuda oficial disponible dentro de R es una referencia habitual.
Un vector es una estructura unidimensional. En un vector atómico, sus elementos comparten un tipo compatible.
salarios <- c(1900000, 2400000, 3100000, 2750000)
secuencia_simple <- 1:5
secuencia_pares <- seq(2, 10, by = 2)
zonas_repetidas <- rep(c("Urbana", "Rural"), each = 2)
salarios## [1] 1900000 2400000 3100000 2750000
## [1] 1 2 3 4 5
## [1] 2 4 6 8 10
## [1] "Urbana" "Urbana" "Rural" "Rural"
R comienza a indexar en 1.
## [1] 4
## [1] 1900000
## [1] 1900000 3100000
## [1] 1900000 3100000 2750000
## [1] 3100000 2750000
## [1] 1995000 2520000 3255000 2887500
## [1] 1400000 1900000 2600000 2250000
R aplica la operación a cada elemento sin requerir un ciclo explícito.
## [1] 110 220 310 420
R reutiliza c(10, 20) hasta alcanzar la longitud del
vector mayor. El reciclaje puede ser útil, pero también producir
resultados no deseados si las longitudes no corresponden a la lógica del
problema.
## [1] 11850000
## [1] 2962500
## [1] 2775000
## [1] 2200000
## [1] 4100000
## [1] 811762.5
Enunciado. Con el vector
gastos <- c(1500000, 2100000, 1950000, 2800000, 2300000),
obtén: el tercer valor, todos los valores mayores a 2.000.000 y el gasto
mediano.
Pista. Usa [ ], una condición lógica y
median().
## [1] 1950000
## [1] 2100000 2800000 2300000
## [1] 2100000
Explicación. La indexación puede basarse en una
posición concreta o en una condición. median() resume el
centro de la distribución y es menos sensible a valores extremos que la
media.
Interpretación. Estas operaciones describen el conjunto de gastos proporcionado; no permiten inferir por sí solas patrones de una población más amplia.
Los factores representan variables categóricas con un conjunto definido de niveles.
condicion_laboral <- factor(
c("Ocupado", "Desocupado", "Ocupado", "Inactivo", "Ocupado")
)
condicion_laboral## [1] Ocupado Desocupado Ocupado Inactivo Ocupado
## Levels: Desocupado Inactivo Ocupado
## [1] "Desocupado" "Inactivo" "Ocupado"
## Desocupado Inactivo Ocupado
## 1 1 3
En una variable nominal no asumimos un orden natural entre categorías.
nivel_educativo <- factor(
c("Secundaria", "Universitaria", "Primaria", "Posgrado", "Universitaria"),
levels = c("Primaria", "Secundaria", "Universitaria", "Posgrado"),
ordered = TRUE
)
nivel_educativo## [1] Secundaria Universitaria Primaria Posgrado Universitaria
## Levels: Primaria < Secundaria < Universitaria < Posgrado
## [1] "Primaria" "Secundaria" "Universitaria" "Posgrado"
## Primaria Secundaria Universitaria Posgrado
## 1 1 2 1
Aquí los niveles sí siguen un orden conceptual definido explícitamente.
Una matriz es una estructura bidimensional homogénea: todos sus elementos deben ser de un tipo compatible.
matriz_indicadores <- matrix(
c(12, 8, 15, 10, 9, 11),
nrow = 3,
byrow = TRUE
)
rownames(matriz_indicadores) <- c("Municipio A", "Municipio B", "Municipio C")
colnames(matriz_indicadores) <- c("Indicador 1", "Indicador 2")
matriz_indicadores## Indicador 1 Indicador 2
## Municipio A 12 8
## Municipio B 15 10
## Municipio C 9 11
## [1] 3
## [1] 2
## [1] 3 2
La sintaxis general es [fila, columna].
## [1] 8
## Indicador 1 Indicador 2
## 15 10
## Municipio A Municipio B Municipio C
## 12 15 9
*
frente a %*%matriz_a <- matrix(c(1, 2, 3, 4), nrow = 2, byrow = TRUE)
matriz_b <- matrix(c(5, 6, 7, 8), nrow = 2, byrow = TRUE)
matriz_a * matriz_b## [,1] [,2]
## [1,] 5 12
## [2,] 21 32
## [,1] [,2]
## [1,] 19 22
## [2,] 43 50
* multiplica elemento a elemento.%*% realiza multiplicación matricial.En Econometría, las matrices permiten representar de forma compacta variables explicativas, parámetros y operaciones algebraicas. Aquí solo necesitamos reconocer su estructura; la estimación de modelos se abordará después.
Una lista puede almacenar objetos de tipos y tamaños diferentes.
resultado_ejemplo <- list(
nombre = "Resumen social",
valores = c(12.4, 15.1, 13.8),
aprobado = TRUE
)
resultado_ejemplo## $nombre
## [1] "Resumen social"
##
## $valores
## [1] 12.4 15.1 13.8
##
## $aprobado
## [1] TRUE
[ ],
[[ ]] y $## $nombre
## [1] "Resumen social"
## [1] "Resumen social"
## [1] 12.4 15.1 13.8
[1] devuelve una sublista.[[1]] extrae el contenido del primer elemento.$nombre extrae un elemento nombrado.Muchos resultados de funciones y modelos en R se almacenan internamente como listas. Por eso esta estructura será importante más adelante.
Un data frame es una estructura tabular donde:
hogares_base <- data.frame(
id_hogar = 1:3,
municipio = c("Cali", "Palmira", "Yumbo"),
ingreso_mensual = c(2500000, 3300000, 2200000)
)
hogares_base## id_hogar municipio ingreso_mensual
## 1 1 Cali 2500000
## 2 2 Palmira 3300000
## 3 3 Yumbo 2200000
## 'data.frame': 3 obs. of 3 variables:
## $ id_hogar : int 1 2 3
## $ municipio : chr "Cali" "Palmira" "Yumbo"
## $ ingreso_mensual: num 2500000 3300000 2200000
R incorpora muchas funciones, pero su ecosistema se amplía con paquetes.
La instalación se realiza normalmente una sola vez en cada instalación de R:
La carga se realiza en las sesiones en las que necesitamos sus funciones:
Si R indica que tidyverse no está instalado, ejecuta una
sola vez el comando de instalación mostrado en el bloque anterior y
vuelve a renderizar el documento.
El tidyverse es un ecosistema de paquetes para
ciencia de datos. En esta clase usaremos principalmente herramientas de
tibble, dplyr y readr, cargadas
mediante library(tidyverse).
install.packages()
dentro de un documento que se renderiza repetidamente. Instalar y cargar
son acciones distintas.
Un tibble es una variante moderna de data frame. Mantiene la lógica tabular, pero su impresión y algunos comportamientos están diseñados para facilitar flujos de ciencia de datos.
hogares_tibble_demo <- tibble(
id_hogar = 1:3,
municipio = c("Cali", "Palmira", "Yumbo"),
ingreso_mensual = c(2500000, 3300000, 2200000)
)
hogares_tibble_demo## # A tibble: 3 × 3
## id_hogar municipio ingreso_mensual
## <int> <chr> <dbl>
## 1 1 Cali 2500000
## 2 2 Palmira 3300000
## 3 3 Yumbo 2200000
hogaresA partir de este punto utilizaremos una única base llamada
hogares.
Advertencia pedagógica: todos los datos son simulados y fueron construidos exclusivamente para aprender R. No corresponden a estadísticas reales de Cali, Palmira, Buenaventura, Yumbo o Jamundí y no deben utilizarse para caracterizar esos municipios.
hogares <- tibble(
id_hogar = 1:12,
municipio = c(
"Cali", "Cali", "Palmira", "Palmira", "Buenaventura", "Buenaventura",
"Yumbo", "Yumbo", "Jamundí", "Jamundí", "Cali", "Palmira"
),
ingreso_mensual = c(
2500000, 3900000, 2300000, NA, 2100000, 2950000,
3600000, 2750000, 4200000, 2450000, 5100000, 3250000
),
gasto_mensual = c(
2050000, 3150000, 1950000, 2600000, 1850000, NA,
2850000, 2400000, 3300000, 2250000, 4000000, 2700000
),
numero_personas = c(3L, 4L, 2L, 5L, 4L, 3L, 2L, 5L, 3L, 4L, 5L, 2L),
zona = factor(
c("Urbana", "Urbana", "Urbana", "Rural", "Urbana", "Rural",
"Urbana", "Rural", "Urbana", "Rural", "Urbana", "Urbana"),
levels = c("Urbana", "Rural")
),
recibe_subsidio = factor(
c("No", "No", "Sí", "Sí", "Sí", NA, "No", "Sí", "No", "Sí", "No", "Sí"),
levels = c("No", "Sí")
)
)
hogares## # A tibble: 12 × 7
## id_hogar municipio ingreso_mensual gasto_mensual numero_personas zona
## <int> <chr> <dbl> <dbl> <int> <fct>
## 1 1 Cali 2500000 2050000 3 Urbana
## 2 2 Cali 3900000 3150000 4 Urbana
## 3 3 Palmira 2300000 1950000 2 Urbana
## 4 4 Palmira NA 2600000 5 Rural
## 5 5 Buenaventura 2100000 1850000 4 Urbana
## 6 6 Buenaventura 2950000 NA 3 Rural
## 7 7 Yumbo 3600000 2850000 2 Urbana
## 8 8 Yumbo 2750000 2400000 5 Rural
## 9 9 Jamundí 4200000 3300000 3 Urbana
## 10 10 Jamundí 2450000 2250000 4 Rural
## 11 11 Cali 5100000 4000000 5 Urbana
## 12 12 Palmira 3250000 2700000 2 Urbana
## # ℹ 1 more variable: recibe_subsidio <fct>
id_hogar: identificador.municipio: variable categórica almacenada como
texto.ingreso_mensual y gasto_mensual: variables
numéricas.numero_personas: variable entera.zona y recibe_subsidio: variables
categóricas representadas como factores.## # A tibble: 6 × 7
## id_hogar municipio ingreso_mensual gasto_mensual numero_personas zona
## <int> <chr> <dbl> <dbl> <int> <fct>
## 1 1 Cali 2500000 2050000 3 Urbana
## 2 2 Cali 3900000 3150000 4 Urbana
## 3 3 Palmira 2300000 1950000 2 Urbana
## 4 4 Palmira NA 2600000 5 Rural
## 5 5 Buenaventura 2100000 1850000 4 Urbana
## 6 6 Buenaventura 2950000 NA 3 Rural
## # ℹ 1 more variable: recibe_subsidio <fct>
## # A tibble: 6 × 7
## id_hogar municipio ingreso_mensual gasto_mensual numero_personas zona
## <int> <chr> <dbl> <dbl> <int> <fct>
## 1 7 Yumbo 3600000 2850000 2 Urbana
## 2 8 Yumbo 2750000 2400000 5 Rural
## 3 9 Jamundí 4200000 3300000 3 Urbana
## 4 10 Jamundí 2450000 2250000 4 Rural
## 5 11 Cali 5100000 4000000 5 Urbana
## 6 12 Palmira 3250000 2700000 2 Urbana
## # ℹ 1 more variable: recibe_subsidio <fct>
## [1] "id_hogar" "municipio" "ingreso_mensual" "gasto_mensual"
## [5] "numero_personas" "zona" "recibe_subsidio"
## [1] 12 7
## [1] 12
## [1] 7
## tibble [12 × 7] (S3: tbl_df/tbl/data.frame)
## $ id_hogar : int [1:12] 1 2 3 4 5 6 7 8 9 10 ...
## $ municipio : chr [1:12] "Cali" "Cali" "Palmira" "Palmira" ...
## $ ingreso_mensual: num [1:12] 2500000 3900000 2300000 NA 2100000 2950000 3600000 2750000 4200000 2450000 ...
## $ gasto_mensual : num [1:12] 2050000 3150000 1950000 2600000 1850000 NA 2850000 2400000 3300000 2250000 ...
## $ numero_personas: int [1:12] 3 4 2 5 4 3 2 5 3 4 ...
## $ zona : Factor w/ 2 levels "Urbana","Rural": 1 1 1 2 1 2 1 2 1 2 ...
## $ recibe_subsidio: Factor w/ 2 levels "No","Sí": 1 1 2 2 2 NA 1 2 1 2 ...
## id_hogar municipio ingreso_mensual gasto_mensual
## Min. : 1.00 Length:12 Min. :2100000 Min. :1850000
## 1st Qu.: 3.75 Class :character 1st Qu.:2475000 1st Qu.:2150000
## Median : 6.50 Mode :character Median :2950000 Median :2600000
## Mean : 6.50 Mean :3190909 Mean :2645455
## 3rd Qu.: 9.25 3rd Qu.:3750000 3rd Qu.:3000000
## Max. :12.00 Max. :5100000 Max. :4000000
## NA's :1 NA's :1
## numero_personas zona recibe_subsidio
## Min. :2.00 Urbana:8 No :5
## 1st Qu.:2.75 Rural :4 Sí :6
## Median :3.50 NA's:1
## Mean :3.50
## 3rd Qu.:4.25
## Max. :5.00
##
En RStudio, View() abre una vista tabular interactiva.
No la ejecutamos al renderizar porque pertenece al flujo interactivo del
IDE.
$ y [fila, columna]## [1] "Cali" "Cali" "Palmira" "Palmira" "Buenaventura"
## [6] "Buenaventura" "Yumbo" "Yumbo" "Jamundí" "Jamundí"
## [11] "Cali" "Palmira"
## # A tibble: 1 × 1
## ingreso_mensual
## <dbl>
## 1 2500000
## # A tibble: 4 × 2
## municipio ingreso_mensual
## <chr> <dbl>
## 1 Cali 2500000
## 2 Cali 3900000
## 3 Palmira 2300000
## 4 Palmira NA
## [1] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [1] 1
## [1] 1
## [1] 1
No imputaremos valores en esta clase. Primero aprendemos a reconocerlos y a controlar cómo afectan los cálculos.
dplyr:
seleccionar, filtrar y transformardplyr organiza muchas tareas frecuentes mediante verbos.
Utilizaremos el pipe nativo |> para leer una secuencia
de izquierda a derecha.
|>La expresión:
objeto |> funcion()
puede leerse como: “toma objeto y pásalo a la siguiente
operación”.
El operador %>%, popularizado por
magrittr y usado ampliamente en código tidyverse, también
está disponible al cargar tidyverse.
## # A tibble: 3 × 7
## id_hogar municipio ingreso_mensual gasto_mensual numero_personas zona
## <int> <chr> <dbl> <dbl> <int> <fct>
## 1 1 Cali 2500000 2050000 3 Urbana
## 2 2 Cali 3900000 3150000 4 Urbana
## 3 3 Palmira 2300000 1950000 2 Urbana
## # ℹ 1 more variable: recibe_subsidio <fct>
## # A tibble: 3 × 7
## id_hogar municipio ingreso_mensual gasto_mensual numero_personas zona
## <int> <chr> <dbl> <dbl> <int> <fct>
## 1 1 Cali 2500000 2050000 3 Urbana
## 2 2 Cali 3900000 3150000 4 Urbana
## 3 3 Palmira 2300000 1950000 2 Urbana
## # ℹ 1 more variable: recibe_subsidio <fct>
En esta clase priorizaremos |> y reconoceremos
%>% para poder leer código existente.
select(): seleccionar columnasCon R base:
## # A tibble: 12 × 3
## municipio ingreso_mensual gasto_mensual
## <chr> <dbl> <dbl>
## 1 Cali 2500000 2050000
## 2 Cali 3900000 3150000
## 3 Palmira 2300000 1950000
## 4 Palmira NA 2600000
## 5 Buenaventura 2100000 1850000
## 6 Buenaventura 2950000 NA
## 7 Yumbo 3600000 2850000
## 8 Yumbo 2750000 2400000
## 9 Jamundí 4200000 3300000
## 10 Jamundí 2450000 2250000
## 11 Cali 5100000 4000000
## 12 Palmira 3250000 2700000
Con dplyr:
## # A tibble: 12 × 3
## municipio ingreso_mensual gasto_mensual
## <chr> <dbl> <dbl>
## 1 Cali 2500000 2050000
## 2 Cali 3900000 3150000
## 3 Palmira 2300000 1950000
## 4 Palmira NA 2600000
## 5 Buenaventura 2100000 1850000
## 6 Buenaventura 2950000 NA
## 7 Yumbo 3600000 2850000
## 8 Yumbo 2750000 2400000
## 9 Jamundí 4200000 3300000
## 10 Jamundí 2450000 2250000
## 11 Cali 5100000 4000000
## 12 Palmira 3250000 2700000
filter(): filtrar filasSeleccionemos hogares con ingreso observado y superior a 3.000.000.
Con R base:
## # A tibble: 5 × 7
## id_hogar municipio ingreso_mensual gasto_mensual numero_personas zona
## <int> <chr> <dbl> <dbl> <int> <fct>
## 1 2 Cali 3900000 3150000 4 Urbana
## 2 7 Yumbo 3600000 2850000 2 Urbana
## 3 9 Jamundí 4200000 3300000 3 Urbana
## 4 11 Cali 5100000 4000000 5 Urbana
## 5 12 Palmira 3250000 2700000 2 Urbana
## # ℹ 1 more variable: recibe_subsidio <fct>
Con dplyr:
## # A tibble: 5 × 7
## id_hogar municipio ingreso_mensual gasto_mensual numero_personas zona
## <int> <chr> <dbl> <dbl> <int> <fct>
## 1 2 Cali 3900000 3150000 4 Urbana
## 2 7 Yumbo 3600000 2850000 2 Urbana
## 3 9 Jamundí 4200000 3300000 3 Urbana
## 4 11 Cali 5100000 4000000 5 Urbana
## 5 12 Palmira 3250000 2700000 2 Urbana
## # ℹ 1 more variable: recibe_subsidio <fct>
mutate(): crear o transformar variablesCrearemos dos variables:
\[ \text{ahorro mensual} = \text{ingreso mensual} - \text{gasto mensual} \]
\[ \text{ingreso per cápita} = \frac{\text{ingreso mensual}}{\text{número de personas}} \]
hogares_analisis <- hogares |>
mutate(
ahorro_mensual = ingreso_mensual - gasto_mensual,
ingreso_per_capita = ingreso_mensual / numero_personas
)
hogares_analisis |>
select(
id_hogar, municipio, ingreso_mensual, gasto_mensual,
ahorro_mensual, ingreso_per_capita
)## # A tibble: 12 × 6
## id_hogar municipio ingreso_mensual gasto_mensual ahorro_mensual
## <int> <chr> <dbl> <dbl> <dbl>
## 1 1 Cali 2500000 2050000 450000
## 2 2 Cali 3900000 3150000 750000
## 3 3 Palmira 2300000 1950000 350000
## 4 4 Palmira NA 2600000 NA
## 5 5 Buenaventura 2100000 1850000 250000
## 6 6 Buenaventura 2950000 NA NA
## 7 7 Yumbo 3600000 2850000 750000
## 8 8 Yumbo 2750000 2400000 350000
## 9 9 Jamundí 4200000 3300000 900000
## 10 10 Jamundí 2450000 2250000 200000
## 11 11 Cali 5100000 4000000 1100000
## 12 12 Palmira 3250000 2700000 550000
## # ℹ 1 more variable: ingreso_per_capita <dbl>
Los NA se propagan cuando una operación depende de un
dato faltante.
arrange(): ordenar observacioneshogares_analisis |>
arrange(desc(ingreso_per_capita)) |>
select(id_hogar, municipio, ingreso_per_capita)## # A tibble: 12 × 3
## id_hogar municipio ingreso_per_capita
## <int> <chr> <dbl>
## 1 7 Yumbo 1800000
## 2 12 Palmira 1625000
## 3 9 Jamundí 1400000
## 4 3 Palmira 1150000
## 5 11 Cali 1020000
## 6 6 Buenaventura 983333.
## 7 2 Cali 975000
## 8 1 Cali 833333.
## 9 10 Jamundí 612500
## 10 8 Yumbo 550000
## 11 5 Buenaventura 525000
## 12 4 Palmira NA
group_by() y summarise(): agregaciónresumen_zona <- hogares_analisis |>
group_by(zona) |>
summarise(
hogares_observados = n(),
ingreso_promedio = mean(ingreso_mensual, na.rm = TRUE),
gasto_promedio = mean(gasto_mensual, na.rm = TRUE),
ahorro_promedio = mean(ahorro_mensual, na.rm = TRUE),
.groups = "drop"
)
resumen_zona## # A tibble: 2 × 5
## zona hogares_observados ingreso_promedio gasto_promedio ahorro_promedio
## <fct> <int> <dbl> <dbl> <dbl>
## 1 Urbana 8 3368750 2731250 637500
## 2 Rural 4 2716667. 2416667. 275000
Interpretación correcta: en estos datos simulados, los promedios resumen las observaciones disponibles de cada zona.
Interpretación incorrecta: afirmar que vivir en una zona “causa” un mayor ingreso o ahorro a partir de esta tabla. La comparación es descriptiva.
knitr::kable(
resumen_zona,
digits = 0,
caption = "Resumen descriptivo por zona — datos simulados"
)| zona | hogares_observados | ingreso_promedio | gasto_promedio | ahorro_promedio |
|---|---|---|---|---|
| Urbana | 8 | 3368750 | 2731250 | 637500 |
| Rural | 4 | 2716667 | 2416667 | 275000 |
hogaresEnunciado. A partir de
hogares_analisis:
municipio, zona,
ingreso_mensual e ingreso_per_capita;Pista. Encadena select(),
filter() y arrange(desc(...)) con
|>.
hogares_analisis |>
select(municipio, zona, ingreso_mensual, ingreso_per_capita) |>
filter(!is.na(ingreso_mensual)) |>
arrange(desc(ingreso_per_capita))## # A tibble: 11 × 4
## municipio zona ingreso_mensual ingreso_per_capita
## <chr> <fct> <dbl> <dbl>
## 1 Yumbo Urbana 3600000 1800000
## 2 Palmira Urbana 3250000 1625000
## 3 Jamundí Urbana 4200000 1400000
## 4 Palmira Urbana 2300000 1150000
## 5 Cali Urbana 5100000 1020000
## 6 Buenaventura Rural 2950000 983333.
## 7 Cali Urbana 3900000 975000
## 8 Cali Urbana 2500000 833333.
## 9 Jamundí Rural 2450000 612500
## 10 Yumbo Rural 2750000 550000
## 11 Buenaventura Urbana 2100000 525000
Explicación. La secuencia reduce columnas, elimina del resultado las filas cuyo ingreso no está observado y ordena las observaciones restantes según una variable derivada.
Interpretación. El ordenamiento permite comparar posiciones dentro de esta base simulada. No constituye una clasificación oficial de hogares o municipios.
En proyectos reales, una base suele estar distribuida en varias tablas. Un join combina información utilizando una o más variables llave.
Crearemos una tabla pequeña con información territorial también simulada.
info_municipios <- tibble(
municipio = c("Cali", "Palmira", "Buenaventura", "Yumbo", "Jamundí"),
grupo_territorial = c("A", "B", "C", "B", "A")
)
info_municipios## # A tibble: 5 × 2
## municipio grupo_territorial
## <chr> <chr>
## 1 Cali A
## 2 Palmira B
## 3 Buenaventura C
## 4 Yumbo B
## 5 Jamundí A
La variable grupo_territorial es ficticia y solo existe
para ilustrar la unión.
left_join()hogares_unidos <- hogares_analisis |>
left_join(info_municipios, by = "municipio")
hogares_unidos |>
select(id_hogar, municipio, grupo_territorial, ingreso_mensual)## # A tibble: 12 × 4
## id_hogar municipio grupo_territorial ingreso_mensual
## <int> <chr> <chr> <dbl>
## 1 1 Cali A 2500000
## 2 2 Cali A 3900000
## 3 3 Palmira B 2300000
## 4 4 Palmira B NA
## 5 5 Buenaventura C 2100000
## 6 6 Buenaventura C 2950000
## 7 7 Yumbo B 3600000
## 8 8 Yumbo B 2750000
## 9 9 Jamundí A 4200000
## 10 10 Jamundí A 2450000
## 11 11 Cali A 5100000
## 12 12 Palmira B 3250000
left_join() conserva todas las filas de la tabla de la
izquierda y añade columnas coincidentes de la tabla de la derecha.
Enunciado. Crea una tabla
etiquetas_zona con dos filas: Urbana y
Rural, y una columna codigo_zona con valores
1L y 2L. Únela a hogares_analisis
mediante left_join().
Pista. La llave común debe llamarse
zona en ambas tablas.
etiquetas_zona <- tibble(
zona = factor(c("Urbana", "Rural"), levels = c("Urbana", "Rural")),
codigo_zona = c(1L, 2L)
)
hogares_analisis |>
left_join(etiquetas_zona, by = "zona") |>
select(id_hogar, zona, codigo_zona)## # A tibble: 12 × 3
## id_hogar zona codigo_zona
## <int> <fct> <int>
## 1 1 Urbana 1
## 2 2 Urbana 1
## 3 3 Urbana 1
## 4 4 Rural 2
## 5 5 Urbana 1
## 6 6 Rural 2
## 7 7 Urbana 1
## 8 8 Rural 2
## 9 9 Urbana 1
## 10 10 Rural 2
## 11 11 Urbana 1
## 12 12 Urbana 1
Explicación. left_join() busca
coincidencias en zona y añade codigo_zona a
cada hogar.
Interpretación. El código solo etiqueta categorías. No añade información sustantiva nueva sobre el comportamiento económico de los hogares.
En esta sección los comandos se muestran, pero no se ejecutan, porque el documento no depende de archivos externos.
readrreadxl y writexlhavenencuesta_stata <- haven::read_dta("datos/encuesta.dta")
haven::write_dta(hogares, "salidas/hogares.dta")Si estos paquetes aún no están instalados, su instalación se hace fuera del flujo de renderizado. Por ejemplo:
Si el proyecto contiene las carpetas datos/ y
salidas/, las rutas anteriores funcionan de forma portable
siempre que la estructura se conserve.
Evita rutas como:
C:/Users/NombrePersonal/Escritorio/mi_archivo.csv
Una ruta relativa como datos/encuesta.csv comunica dónde
está el archivo dentro del proyecto, no dónde se
encuentra el proyecto en un computador particular.
Trabaja con hogares_analisis, que ya contiene
ahorro_mensual e ingreso_per_capita.
Enunciado. Construye una tabla por
municipio que contenga:
Después, ordena la tabla de mayor a menor según ingreso per cápita promedio.
Pista. Utiliza group_by(),
summarise(), n(),
mean(..., na.rm = TRUE) y arrange(desc(...)).
Para la proporción puedes promediar la expresión lógica
recibe_subsidio == "Sí".
resumen_municipio <- hogares_analisis |>
group_by(municipio) |>
summarise(
numero_hogares = n(),
ingreso_promedio = mean(ingreso_mensual, na.rm = TRUE),
gasto_promedio = mean(gasto_mensual, na.rm = TRUE),
ingreso_per_capita_promedio = mean(ingreso_per_capita, na.rm = TRUE),
proporcion_subsidio = mean(recibe_subsidio == "Sí", na.rm = TRUE),
.groups = "drop"
) |>
arrange(desc(ingreso_per_capita_promedio))
resumen_municipio## # A tibble: 5 × 6
## municipio numero_hogares ingreso_promedio gasto_promedio
## <chr> <int> <dbl> <dbl>
## 1 Palmira 3 2775000 2416667.
## 2 Yumbo 2 3175000 2625000
## 3 Jamundí 2 3325000 2775000
## 4 Cali 3 3833333. 3066667.
## 5 Buenaventura 2 2525000 1850000
## # ℹ 2 more variables: ingreso_per_capita_promedio <dbl>,
## # proporcion_subsidio <dbl>
Explicación. group_by(municipio) define
los grupos y summarise() reduce cada grupo a una fila de
estadísticas. Una comparación lógica como
recibe_subsidio == "Sí" produce TRUE y
FALSE; al calcular su media, R trata TRUE como
1 y FALSE como 0, por lo que se obtiene una proporción
entre respuestas observadas.
Interpretación. La tabla resume una base pequeña y simulada. Las diferencias entre municipios no deben presentarse como estadísticas reales ni como efectos causales. En una investigación real también habría que considerar diseño de muestra, calidad de medición, cobertura y otros factores relevantes.
Enunciado. Con hogares_analisis,
identifica los hogares que cumplen simultáneamente estas
condiciones:
"Urbana".Muestra únicamente id_hogar, municipio,
ingreso_mensual, gasto_mensual y
ahorro_mensual. Ordena el resultado de mayor a menor
ahorro.
Pista. Usa filter() con varias
condiciones, luego select() y
arrange(desc(...)).
hogares_analisis |>
filter(
!is.na(ingreso_mensual),
!is.na(gasto_mensual),
ahorro_mensual > 0,
zona == "Urbana"
) |>
select(
id_hogar, municipio, ingreso_mensual,
gasto_mensual, ahorro_mensual
) |>
arrange(desc(ahorro_mensual))## # A tibble: 8 × 5
## id_hogar municipio ingreso_mensual gasto_mensual ahorro_mensual
## <int> <chr> <dbl> <dbl> <dbl>
## 1 11 Cali 5100000 4000000 1100000
## 2 9 Jamundí 4200000 3300000 900000
## 3 2 Cali 3900000 3150000 750000
## 4 7 Yumbo 3600000 2850000 750000
## 5 12 Palmira 3250000 2700000 550000
## 6 1 Cali 2500000 2050000 450000
## 7 3 Palmira 2300000 1950000 350000
## 8 5 Buenaventura 2100000 1850000 250000
Explicación. filter() puede recibir
varias condiciones separadas por comas; dplyr exige que
todas se cumplan. Luego se conservan las columnas necesarias y se ordena
el resultado.
Interpretación. El resultado identifica hogares simulados que cumplen una regla definida. No establece que la zona explique el ahorro ni que esos patrones representen a una población real.
Enunciado. Construye una tabla por zona
que muestre:
Usa na.rm = TRUE donde sea necesario.
Pista. La lógica es similar a
resumen_zona, cambiando las funciones de resumen.
hogares_analisis |>
group_by(zona) |>
summarise(
numero_hogares = n(),
mediana_ingreso = median(ingreso_mensual, na.rm = TRUE),
mediana_gasto = median(gasto_mensual, na.rm = TRUE),
mediana_ahorro = median(ahorro_mensual, na.rm = TRUE),
minimo_ingreso_per_capita = min(ingreso_per_capita, na.rm = TRUE),
maximo_ingreso_per_capita = max(ingreso_per_capita, na.rm = TRUE),
.groups = "drop"
)## # A tibble: 2 × 7
## zona numero_hogares mediana_ingreso mediana_gasto mediana_ahorro
## <fct> <int> <dbl> <dbl> <dbl>
## 1 Urbana 8 3425000 2775000 650000
## 2 Rural 4 2750000 2400000 275000
## # ℹ 2 more variables: minimo_ingreso_per_capita <dbl>,
## # maximo_ingreso_per_capita <dbl>
Explicación. summarise() admite
múltiples estadísticas por grupo. La mediana es una medida de posición
central y min()/max() describen el rango
observado.
Interpretación. Estas cifras siguen siendo descriptivas y pertenecen exclusivamente al conjunto simulado.
view() en lugar de View().= o <- con ==
dentro de una comparación.NA sin definir cómo
tratar los faltantes.