Construyendo las bases para el análisis de datos en salud
Author
Agoralab
Published
Invalid Date
Fundamentos de R – Tipos de datos y operaciones básicas
Bienvenida y repaso
En la sesión anterior, nos familiarizamos con R, RStudio y Quarto. Hoy profundizaremos en los fundamentos del lenguaje R y aprenderemos sobre los diferentes tipos de datos y estructuras que utilizaremos constantemente en nuestros análisis de datos en ciencias de la salud.
Objetivos de la sesión
Al finalizar esta sesión, serás capaz de:
Comprender la sintaxis básica de R y el uso de la consola
Identificar y trabajar con los diferentes tipos de datos en R
Crear y manipular las estructuras fundamentales (vectores, matrices, data frames, listas)
Realizar operaciones básicas con datos en R
Utilizar la indexación para seleccionar elementos específicos
Manejar valores faltantes (NA) de forma adecuada
Conceptos básicos del lenguaje R
Sintaxis de R
R tiene una sintaxis particular que es importante comprender:
Code
# Comentarios: cualquier texto después de # es ignorado por R# Esto es útil para documentar tu código# Asignación de valores a variables# En R, usamos principalmente <- para asignar valores (aunque = también funciona)x <-10# asigna el valor 10 a la variable xy =20# hace lo mismo, pero <- es más común en R# Mostrar el valor de una variablex
[1] 10
Code
y
[1] 20
Code
# Funciones: nombre seguido de paréntesis con argumentos# Las funciones realizan operaciones y devuelven resultadossqrt(25) # raíz cuadrada
[1] 5
Code
log(10) # logaritmo natural
[1] 2.302585
Buenas prácticas de nomenclatura en R
En R, la convención para nombrar variables es usar nombres descriptivos con palabras separadas por guiones bajos (snake_case) o puntos. Por ejemplo: edad_paciente o edad.paciente.
Algunos consejos adicionales: - Usa nombres descriptivos (prefiere edad_promedio sobre e_p) - Evita usar nombres de funciones existentes (c, mean, data, etc.) - Mantén consistencia en tu estilo de nomenclatura a lo largo de todo tu código - Los nombres deben comenzar con una letra, no con números o símbolos
Operadores básicos
R incluye varios operadores para realizar operaciones:
Code
# Operadores aritméticos5+3# suma
[1] 8
Code
10-4# resta
[1] 6
Code
6*7# multiplicación
[1] 42
Code
9/3# división
[1] 3
Code
2^3# potencia (2 elevado al cubo)
[1] 8
Code
10%%3# módulo (resto de la división: 10/3 = 3 con resto 1)
[1] 1
Code
10%/%3# división entera (parte entera: 10/3 = 3)
[1] 3
Code
# Operadores de comparación5>3# mayor que
[1] TRUE
Code
7<2# menor que
[1] FALSE
Code
4>=4# mayor o igual que
[1] TRUE
Code
8<=10# menor o igual que
[1] TRUE
Code
5==5# igual a
[1] TRUE
Code
6!=8# diferente de
[1] TRUE
Code
# Operadores lógicosTRUE&FALSE# AND lógico (ambos deben ser TRUE)
[1] FALSE
Code
TRUE|FALSE# OR lógico (al menos uno debe ser TRUE)
[1] TRUE
Code
!TRUE# NOT lógico (invierte el valor)
[1] FALSE
Aplicación práctica en investigación sanitaria
Los operadores de comparación y lógicos son fundamentales en la investigación sanitaria para:
Filtrar pacientes según criterios de inclusión/exclusión (ej. edad >= 18 & !fumador)
# 2. Integer: números enteros (se indican con L)edad <-35L # La L indica que es un enteroclass(edad)
[1] "integer"
Code
typeof(edad)
[1] "integer"
Code
# 3. Character: texto (cadenas de caracteres)nombre <-"Paciente A"diagnostico <-'Hipertensión'# Tanto comillas simples como dobles funcionanclass(nombre)
[1] "character"
Code
typeof(nombre)
[1] "character"
Code
# 4. Logical: valores TRUE o FALSE (booleanos)tiene_diabetes <-TRUEes_fumador <-FALSEclass(tiene_diabetes)
[1] "logical"
Code
typeof(tiene_diabetes)
[1] "logical"
Code
# 5. Complex: números complejos (menos usado en análisis de datos de salud)num_complejo <-3+2iclass(num_complejo)
[1] "complex"
Code
typeof(num_complejo)
[1] "complex"
Cosas a tener en cuenta sobre los tipos de datos
Coerción automática: R a veces convierte automáticamente entre tipos de datos. Por ejemplo, si combinas números y caracteres en un vector, todos los elementos se convertirán a caracteres.
c(1, 2, "tres") # Resultado: "1" "2" "tres"
Precisión numérica: R tiene limitaciones en la precisión decimal. Para cálculos financieros o que requieren precisión exacta, considera paquetes especializados.
NA vs NULL: NA representa datos faltantes y tiene un tipo (NA_real_, NA_character_, etc.), mientras que NULL representa la ausencia de un valor y no tiene tipo.
Tipo especial: Factor
Los factores son fundamentales en investigación en salud para representar variables categóricas (como sexo, grupo de tratamiento, estadios de enfermedad):
# Comprobar si los valores son ordenadosis.ordered(severidad)
[1] TRUE
Code
# Comparaciones con factores ordenadosseveridad[1] < severidad[3] # ¿Es "Leve" menos severo que "Severo"?
[1] TRUE
¿Por qué son importantes los factores en estudios clínicos?
Los factores en R son cruciales para el análisis estadístico en investigación médica porque:
Preservan el orden significativo: En variables como “leve/moderado/severo”, el orden importa y los factores ordenados lo mantienen.
Control en modelos estadísticos: R trata automáticamente los factores de manera adecuada en regresiones y ANOVA, creando las variables dummy necesarias.
Referencia explícita: Puedes controlar cuál nivel sirve como referencia en modelos estadísticos (relevel()), lo que afecta la interpretación de coeficientes.
Eficiencia computacional: Internamente, los factores se almacenan como enteros con una tabla de búsqueda, ahorrando memoria para conjuntos de datos grandes.
Estructuras de datos en R
Las estructuras de datos permiten organizar y manipular conjuntos de información. Estas son las principales:
Vectores
Los vectores son la estructura más básica en R - una colección de elementos del mismo tipo:
Code
# Crear vectores con c() - concatenar valoresedades <-c(25, 42, 37, 29, 51)pacientes <-c("Juan", "María", "Carlos", "Ana", "Pedro")hipertension <-c(TRUE, FALSE, TRUE, FALSE, TRUE)# Longitud de un vectorlength(edades)
[1] 5
Code
# Operaciones con vectores (se aplican elemento a elemento)edades +5# Suma 5 a cada edad
[1] 30 47 42 34 56
Code
edades *2# Multiplica por 2 cada edad
[1] 50 84 74 58 102
Code
# Dos vectores de igual longitudpeso <-c(70, 65, 82, 58, 75)altura <-c(1.75, 1.62, 1.80, 1.58, 1.70)# Operación entre vectoresimc <- peso / (altura^2)imc
[1] 22.85714 24.76757 25.30864 23.23346 25.95156
Code
# Nombrar elementos de un vectornames(imc) <- pacientesimc
Juan María Carlos Ana Pedro
22.85714 24.76757 25.30864 23.23346 25.95156
Vectorización: La clave de la eficiencia en R
Una característica poderosa de R es la vectorización: las operaciones se aplican a todos los elementos de un vector sin necesidad de bucles explícitos. Esto hace que el código sea:
Más conciso y legible
Significativamente más rápido
Menos propenso a errores
Ejemplo: Calcular el IMC para 100 pacientes
# Forma vectorizada (rápida y concisa)imc <- peso / (altura^2)# Equivalente con bucle (lenta y verbosa)imc_bucle <-numeric(length(peso))for (i in1:length(peso)) { imc_bucle[i] <- peso[i] / (altura[i]^2)}
Siempre que sea posible, aprovecha la vectorización en R para obtener código más eficiente.
Matrices
Las matrices son arreglos bidimensionales (filas y columnas) que contienen datos del mismo tipo:
Los data frames son las estructuras más utilizadas para datos tabulares en análisis de datos en salud. A diferencia de las matrices, pueden contener diferentes tipos de datos en cada columna:
Code
# Crear un data framepacientes_df <-data.frame(nombre =c("Juan", "María", "Carlos", "Ana", "Pedro"),edad =c(25, 42, 37, 29, 51),peso =c(70, 65, 82, 58, 75),altura =c(1.75, 1.62, 1.80, 1.58, 1.70),hipertension =c(TRUE, FALSE, TRUE, FALSE, TRUE))# Ver el data framepacientes_df
Code
# Estructura del data framestr(pacientes_df)
'data.frame': 5 obs. of 5 variables:
$ nombre : chr "Juan" "María" "Carlos" "Ana" ...
$ edad : num 25 42 37 29 51
$ peso : num 70 65 82 58 75
$ altura : num 1.75 1.62 1.8 1.58 1.7
$ hipertension: logi TRUE FALSE TRUE FALSE TRUE
Code
# Resumen estadístico básicosummary(pacientes_df)
nombre edad peso altura hipertension
Length:5 Min. :25.0 Min. :58 Min. :1.58 Mode :logical
Class :character 1st Qu.:29.0 1st Qu.:65 1st Qu.:1.62 FALSE:2
Mode :character Median :37.0 Median :70 Median :1.70 TRUE :3
Mean :36.8 Mean :70 Mean :1.69
3rd Qu.:42.0 3rd Qu.:75 3rd Qu.:1.75
Max. :51.0 Max. :82 Max. :1.80
Code
# Acceder a una columna con $pacientes_df$edad
[1] 25 42 37 29 51
Code
# Crear una nueva columna (IMC)pacientes_df$imc <- pacientes_df$peso / (pacientes_df$altura^2)pacientes_df
Code
# Número de filas y columnasnrow(pacientes_df)
[1] 5
Code
ncol(pacientes_df)
[1] 6
Code
dim(pacientes_df)
[1] 5 6
Los data frames son fundamentales en análisis de datos epidemiológicos y clínicos, ya que permiten estructurar información de pacientes o casos de manera ordenada, con cada fila representando un individuo y cada columna una variable.
Listas
Las listas son estructuras más flexibles que pueden contener elementos de diferentes tipos, incluso otras listas o data frames:
Code
# Crear una listapaciente_info <-list(nombre ="Juan Pérez",edad =45,mediciones =c(120, 118, 122), # Vector de presiones sistólicaslabs =data.frame(parametro =c("Glucosa", "Colesterol", "Triglicéridos"),valor =c(95, 210, 180),unidad =c("mg/dL", "mg/dL", "mg/dL") ),fumador =FALSE)# Ver la listapaciente_info
# Acceder a un elemento de la listapaciente_info$nombre
[1] "Juan Pérez"
Code
paciente_info$mediciones
[1] 120 118 122
Code
# Otra forma de acceder a elementospaciente_info[[1]] # Primer elemento (nombre)
[1] "Juan Pérez"
Code
paciente_info[[3]] # Tercer elemento (mediciones)
[1] 120 118 122
Code
# Acceder a un data frame dentro de la listapaciente_info$labs
Code
# Acceder a un elemento específico dentro del data frame en la listapaciente_info$labs$valor[2] # Valor de colesterol
[1] 210
Las listas son útiles para almacenar resultados de análisis complejos, información heterogénea de pacientes o para agrupar varios objetos relacionados.
Indexación y selección de elementos
La indexación es crucial para extraer y manipular datos específicos. Hay varias formas de seleccionar datos:
Indexación de vectores
Code
# Vector de ejemplopresion_sistolica <-c(120, 135, 142, 118, 125, 131, 145)nombres <-c("Juan", "María", "Carlos", "Ana", "Pedro", "Laura", "Sergio")names(presion_sistolica) <- nombres# Seleccionar un elemento por su posiciónpresion_sistolica[3] # Tercer elemento
Carlos
142
Code
# Seleccionar múltiples elementospresion_sistolica[c(1, 3, 5)] # Elementos 1, 3 y 5
Juan Carlos Pedro
120 142 125
Code
# Seleccionar un rangopresion_sistolica[2:5] # Del segundo al quinto elemento
María Carlos Ana Pedro
135 142 118 125
Code
# Seleccionar por nombrepresion_sistolica["Pedro"]
Pedro
125
Code
# Excluir elementos (signos negativos)presion_sistolica[-2] # Todos excepto el segundo elemento
Juan Carlos Ana Pedro Laura Sergio
120 142 118 125 131 145
Code
# Seleccionar con condiciones lógicaspresion_sistolica[presion_sistolica >130] # Valores mayores a 130
María Carlos Laura Sergio
135 142 131 145
Indexación de matrices
Code
# Usando la matriz creada anteriormentematriz_datos
# Seleccionar con condiciones lógicaspacientes_df[pacientes_df$edad >35, ] # Pacientes mayores de 35 años
Code
pacientes_df[pacientes_df$hipertension ==TRUE, ] # Pacientes con hipertensión
Tip
En análisis epidemiológicos, la selección por condiciones lógicas es extremadamente útil para filtrar casos por criterios específicos, como rangos de edad, presencia de factores de riesgo o valores límite de indicadores clínicos.
Manejo de valores ausentes (NA)
En datos de salud es muy común encontrar valores faltantes. R representa estos valores con NA (Not Available):
Code
# Vector con valores NAglucosa <-c(95, 110, NA, 87, 122, NA, 105)# Verificar si hay NAis.na(glucosa)
[1] FALSE FALSE TRUE FALSE FALSE TRUE FALSE
Code
any(is.na(glucosa)) # ¿Hay algún NA?
[1] TRUE
Code
sum(is.na(glucosa)) # ¿Cuántos NA hay?
[1] 2
Code
# Calcular la media ignorando NAmean(glucosa) # Devuelve NA
# Reemplazar NA con un valor (por ejemplo, la media)glucosa_reemplazo <- glucosaglucosa_reemplazo[is.na(glucosa_reemplazo)] <-mean(glucosa, na.rm =TRUE)glucosa_reemplazo
[1] 95.0 110.0 103.8 87.0 122.0 103.8 105.0
El manejo de valores faltantes puede afectar tus conclusiones
El método que elijas para manejar los NA puede tener un impacto significativo en tus resultados:
Eliminar casos completos (na.omit()) puede:
Reducir drásticamente el tamaño de la muestra
Introducir sesgos si los datos no faltan completamente al azar
Afectar la representatividad de la muestra
Imputación simple (reemplazar con la media, mediana, etc.) puede:
Subestimar la variabilidad real
Distorsionar las relaciones entre variables
Dar una falsa sensación de precisión
Métodos avanzados como imputación múltiple o modelos específicos para datos faltantes suelen ser preferibles en investigación rigurosa.
Siempre documenta y justifica tu estrategia para manejar valores faltantes en cualquier análisis.
Ejercicio práctico: Análisis de datos de pacientes
Vamos a poner en práctica lo aprendido con un ejercicio sobre datos de pacientes:
Code
# Creamos un data frame con datos de pacientes hipotéticosset.seed(123) # Para reproducibilidaddatos_pacientes <-data.frame(id =1:20,edad =sample(18:80, 20, replace =TRUE),sexo =factor(sample(c("M", "F"), 20, replace =TRUE)),peso =round(rnorm(20, mean =70, sd =15), 1),altura =round(rnorm(20, mean =1.65, sd =0.1), 2),grupo_sanguineo =factor(sample(c("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"), 20, replace =TRUE)),presion_sistolica =sample(100:160, 20, replace =TRUE),presion_diastolica =sample(60:100, 20, replace =TRUE),glucosa =round(rnorm(20, mean =100, sd =20), 1),colesterol =round(rnorm(20, mean =200, sd =40), 1))# Añadimos algunos NA para practicardatos_pacientes$peso[c(3, 15)] <-NAdatos_pacientes$glucosa[c(7, 12, 18)] <-NA# Exploramos los datosdatos_pacientes
Ahora, analicemos estos datos con lo aprendido:
Code
# 1. ¿Cuántos pacientes hay de cada sexo?table(datos_pacientes$sexo)
F M
8 12
Code
# 2. Calculamos el IMC para cada pacientedatos_pacientes$imc <- datos_pacientes$peso / (datos_pacientes$altura^2)head(datos_pacientes) # Mostramos las primeras filas
# 4. Estadísticas básicas de presión arterialsummary(datos_pacientes[, c("presion_sistolica", "presion_diastolica")])
presion_sistolica presion_diastolica
Min. :106.0 Min. :64.00
1st Qu.:121.2 1st Qu.:69.50
Median :128.5 Median :81.50
Mean :130.9 Mean :80.35
3rd Qu.:145.0 3rd Qu.:91.00
Max. :153.0 Max. :98.00
Code
# 5. Creamos una columna de categoría de presióndatos_pacientes$categoria_presion <-ifelse( datos_pacientes$presion_sistolica >=140| datos_pacientes$presion_diastolica >=90,"Hipertensión","Normal")datos_pacientes$categoria_presion <-factor(datos_pacientes$categoria_presion)# 6. ¿Cuántos pacientes tienen hipertensión?table(datos_pacientes$categoria_presion)
Hipertensión Normal
10 10
Code
# 7. Seleccionamos los pacientes con hipertensiónpacientes_hipertension <- datos_pacientes[datos_pacientes$categoria_presion =="Hipertensión", ]pacientes_hipertension
Code
# 8. Edad promedio de los pacientes con hipertensiónmean(pacientes_hipertension$edad)
[1] 45.1
Code
# 9. ¿Hay alguna relación entre sexo e hipertensión?table(datos_pacientes$sexo, datos_pacientes$categoria_presion)
Hipertensión Normal
F 4 4
M 6 6
Ejercicio para practicar
A continuación, se propone un pequeño conjunto de ejercicios para practicar lo aprendido. Intenta resolverlos por tu cuenta y luego compara con las soluciones:
Crea un vector con los valores de glucosa y calcula la media, mediana y desviación estándar (ignorando los NA).
Selecciona todos los pacientes mujeres (F) con colesterol superior a 200.
Crea una nueva variable que clasifique el IMC en: “Bajo peso” (<18.5), “Normal” (18.5-24.9), “Sobrepeso” (25-29.9) y “Obesidad” (≥30).
¿Cuál es el grupo sanguíneo más común en tu dataset?
Calcula la proporción de pacientes con glucosa superior a 126 mg/dL (un criterio para diabetes).
Estrategias para resolver problemas con R
Divide y vencerás: Descompón problemas complejos en pasos más pequeños y resuelve cada uno por separado.
Usa la ayuda de R: Si no recuerdas cómo funciona una función, usa ?nombre_funcion para ver la documentación.
Comprueba tus resultados intermedios: Verifica los resultados de cada paso con head(), str() o summary() para detectar problemas temprano.
Aprovecha la comunidad: Sitios como Stack Overflow tienen respuestas a casi cualquier pregunta sobre R que puedas tener.
Code
# Soluciones (descubre primero por tu cuenta)# 1. Estadísticas de glucosaglucosa_stats <-c(Media =mean(datos_pacientes$glucosa, na.rm =TRUE),Mediana =median(datos_pacientes$glucosa, na.rm =TRUE),Desv_estandar =sd(datos_pacientes$glucosa, na.rm =TRUE))glucosa_stats
Media Mediana Desv_estandar
99.58824 95.30000 19.44209
En la próxima sesión aprenderemos sobre: - Importación de datos desde archivos CSV, Excel y otros formatos - Técnicas para explorar y limpiar datos - Manejo de problemas comunes en datos crudos - Introducción al concepto de datos “tidy”
Prepárate instalando los siguientes paquetes si aún no lo has hecho:
Aprendido sobre los diferentes tipos de datos (numéricos, caracteres, lógicos, factores)
Explorado las estructuras fundamentales (vectores, matrices, data frames, listas)
Practicado la indexación para seleccionar elementos específicos
Trabajado con valores NA
Aplicado estos conocimientos a un conjunto de datos de pacientes
Estos fundamentos son la base para todo análisis de datos en salud. En las próximas sesiones, construiremos sobre estos conocimientos para realizar análisis más complejos y relevantes para la investigación en ciencias de la salud.
¡Nos vemos en la próxima sesión!
Source Code
---title: "Semana 2: Fundamentos de R – Tipos de datos y operaciones básicas"subtitle: "Construyendo las bases para el análisis de datos en salud"author: "Agoralab"date: "12 de marzo, 2025"format: html: toc: true code-fold: show code-tools: true df-print: paged code-link: trueexecute: warning: false message: false---# Fundamentos de R – Tipos de datos y operaciones básicas## Bienvenida y repasoEn la sesión anterior, nos familiarizamos con R, RStudio y Quarto. Hoy profundizaremos en los fundamentos del lenguaje R y aprenderemos sobre los diferentes tipos de datos y estructuras que utilizaremos constantemente en nuestros análisis de datos en ciencias de la salud.## Objetivos de la sesiónAl finalizar esta sesión, serás capaz de:1. Comprender la sintaxis básica de R y el uso de la consola2. Identificar y trabajar con los diferentes tipos de datos en R3. Crear y manipular las estructuras fundamentales (vectores, matrices, data frames, listas)4. Realizar operaciones básicas con datos en R5. Utilizar la indexación para seleccionar elementos específicos6. Manejar valores faltantes (NA) de forma adecuada## Conceptos básicos del lenguaje R### Sintaxis de RR tiene una sintaxis particular que es importante comprender:```{r}# Comentarios: cualquier texto después de # es ignorado por R# Esto es útil para documentar tu código# Asignación de valores a variables# En R, usamos principalmente <- para asignar valores (aunque = también funciona)x <-10# asigna el valor 10 a la variable xy =20# hace lo mismo, pero <- es más común en R# Mostrar el valor de una variablexy# Funciones: nombre seguido de paréntesis con argumentos# Las funciones realizan operaciones y devuelven resultadossqrt(25) # raíz cuadradalog(10) # logaritmo natural```::: {.callout-tip}## Buenas prácticas de nomenclatura en REn R, la convención para nombrar variables es usar nombres descriptivos con palabras separadas por guiones bajos (snake_case) o puntos. Por ejemplo: `edad_paciente` o `edad.paciente`.Algunos consejos adicionales:- Usa nombres descriptivos (prefiere `edad_promedio` sobre `e_p`)- Evita usar nombres de funciones existentes (`c`, `mean`, `data`, etc.)- Mantén consistencia en tu estilo de nomenclatura a lo largo de todo tu código- Los nombres deben comenzar con una letra, no con números o símbolos:::### Operadores básicosR incluye varios operadores para realizar operaciones:```{r}# Operadores aritméticos5+3# suma10-4# resta6*7# multiplicación9/3# división2^3# potencia (2 elevado al cubo)10%%3# módulo (resto de la división: 10/3 = 3 con resto 1)10%/%3# división entera (parte entera: 10/3 = 3)# Operadores de comparación5>3# mayor que7<2# menor que4>=4# mayor o igual que8<=10# menor o igual que5==5# igual a6!=8# diferente de# Operadores lógicosTRUE&FALSE# AND lógico (ambos deben ser TRUE)TRUE|FALSE# OR lógico (al menos uno debe ser TRUE)!TRUE# NOT lógico (invierte el valor)```::: {.callout-note}## Aplicación práctica en investigación sanitariaLos operadores de comparación y lógicos son fundamentales en la investigación sanitaria para:- Filtrar pacientes según criterios de inclusión/exclusión (ej. `edad >= 18 & !fumador`)- Identificar valores anómalos (ej. `presion_sistolica > 180 | presion_sistolica < 90`)- Categorizar pacientes según criterios clínicos (ej. `if(imc >= 30) "Obesidad" else "No obesidad"`)- Validar datos (ej. `all(glucosa > 0)` para verificar que no hay valores negativos):::## Tipos de datos en RR tiene varios tipos de datos básicos que debes conocer:### Tipos atómicos de datos```{r}# 1. Numeric (double): números decimalespeso <-65.5class(peso)typeof(peso)# 2. Integer: números enteros (se indican con L)edad <-35L # La L indica que es un enteroclass(edad)typeof(edad)# 3. Character: texto (cadenas de caracteres)nombre <-"Paciente A"diagnostico <-'Hipertensión'# Tanto comillas simples como dobles funcionanclass(nombre)typeof(nombre)# 4. Logical: valores TRUE o FALSE (booleanos)tiene_diabetes <-TRUEes_fumador <-FALSEclass(tiene_diabetes)typeof(tiene_diabetes)# 5. Complex: números complejos (menos usado en análisis de datos de salud)num_complejo <-3+2iclass(num_complejo)typeof(num_complejo)```::: {.callout-important}## Cosas a tener en cuenta sobre los tipos de datos1. **Coerción automática**: R a veces convierte automáticamente entre tipos de datos. Por ejemplo, si combinas números y caracteres en un vector, todos los elementos se convertirán a caracteres.```rc(1, 2, "tres") # Resultado: "1" "2" "tres"```2. **Precisión numérica**: R tiene limitaciones en la precisión decimal. Para cálculos financieros o que requieren precisión exacta, considera paquetes especializados.3. **NA vs NULL**: `NA` representa datos faltantes y tiene un tipo (NA_real_, NA_character_, etc.), mientras que `NULL` representa la ausencia de un valor y no tiene tipo.:::### Tipo especial: FactorLos factores son fundamentales en investigación en salud para representar variables categóricas (como sexo, grupo de tratamiento, estadios de enfermedad):```{r}# Crear un factor (variable categórica)sexo <-factor(c("M", "F", "F", "M", "F", "M"))sexo# Ver los niveles del factorlevels(sexo)# Factores ordenados (útil para variables como severidad)severidad <-factor(c("Leve", "Moderado", "Severo", "Moderado", "Leve"),levels =c("Leve", "Moderado", "Severo"),ordered =TRUE)severidad# Comprobar si los valores son ordenadosis.ordered(severidad)# Comparaciones con factores ordenadosseveridad[1] < severidad[3] # ¿Es "Leve" menos severo que "Severo"?```::: {.callout-note}## ¿Por qué son importantes los factores en estudios clínicos?Los factores en R son cruciales para el análisis estadístico en investigación médica porque:1. **Preservan el orden significativo**: En variables como "leve/moderado/severo", el orden importa y los factores ordenados lo mantienen.2. **Control en modelos estadísticos**: R trata automáticamente los factores de manera adecuada en regresiones y ANOVA, creando las variables dummy necesarias.3. **Referencia explícita**: Puedes controlar cuál nivel sirve como referencia en modelos estadísticos (`relevel()`), lo que afecta la interpretación de coeficientes.4. **Eficiencia computacional**: Internamente, los factores se almacenan como enteros con una tabla de búsqueda, ahorrando memoria para conjuntos de datos grandes.:::## Estructuras de datos en RLas estructuras de datos permiten organizar y manipular conjuntos de información. Estas son las principales:### VectoresLos vectores son la estructura más básica en R - una colección de elementos del mismo tipo:```{r}# Crear vectores con c() - concatenar valoresedades <-c(25, 42, 37, 29, 51)pacientes <-c("Juan", "María", "Carlos", "Ana", "Pedro")hipertension <-c(TRUE, FALSE, TRUE, FALSE, TRUE)# Longitud de un vectorlength(edades)# Operaciones con vectores (se aplican elemento a elemento)edades +5# Suma 5 a cada edadedades *2# Multiplica por 2 cada edad# Dos vectores de igual longitudpeso <-c(70, 65, 82, 58, 75)altura <-c(1.75, 1.62, 1.80, 1.58, 1.70)# Operación entre vectoresimc <- peso / (altura^2)imc# Nombrar elementos de un vectornames(imc) <- pacientesimc```::: {.callout-tip}## Vectorización: La clave de la eficiencia en RUna característica poderosa de R es la **vectorización**: las operaciones se aplican a todos los elementos de un vector sin necesidad de bucles explícitos. Esto hace que el código sea:- Más conciso y legible- Significativamente más rápido- Menos propenso a errores**Ejemplo**: Calcular el IMC para 100 pacientes```r# Forma vectorizada (rápida y concisa)imc <- peso / (altura^2)# Equivalente con bucle (lenta y verbosa)imc_bucle <-numeric(length(peso))for (i in1:length(peso)) { imc_bucle[i] <- peso[i] / (altura[i]^2)}```Siempre que sea posible, aprovecha la vectorización en R para obtener código más eficiente.:::### MatricesLas matrices son arreglos bidimensionales (filas y columnas) que contienen datos del mismo tipo:```{r}# Crear una matrizmatriz_datos <-matrix(c(120, 130, 125, 140, 115, # Presión sistólica80, 85, 82, 95, 75), # Presión diastólicanrow =5, # 5 filas (pacientes)ncol =2, # 2 columnas (sistólica y diastólica)byrow =TRUE# Llenar por filas)matriz_datos# Asignar nombres a filas y columnasrownames(matriz_datos) <-c("Paciente 1", "Paciente 2", "Paciente 3", "Paciente 4", "Paciente 5")colnames(matriz_datos) <-c("Sistólica", "Diastólica")matriz_datos# Dimensiones de la matrizdim(matriz_datos)# Operaciones básicas con matricesmatriz_datos +5# Sumar 5 a cada elementomatriz_datos *0.9# Multiplicar cada elemento por 0.9```### Data framesLos data frames son las estructuras más utilizadas para datos tabulares en análisis de datos en salud. A diferencia de las matrices, pueden contener diferentes tipos de datos en cada columna:```{r}# Crear un data framepacientes_df <-data.frame(nombre =c("Juan", "María", "Carlos", "Ana", "Pedro"),edad =c(25, 42, 37, 29, 51),peso =c(70, 65, 82, 58, 75),altura =c(1.75, 1.62, 1.80, 1.58, 1.70),hipertension =c(TRUE, FALSE, TRUE, FALSE, TRUE))# Ver el data framepacientes_df# Estructura del data framestr(pacientes_df)# Resumen estadístico básicosummary(pacientes_df)# Acceder a una columna con $pacientes_df$edad# Crear una nueva columna (IMC)pacientes_df$imc <- pacientes_df$peso / (pacientes_df$altura^2)pacientes_df# Número de filas y columnasnrow(pacientes_df)ncol(pacientes_df)dim(pacientes_df)```Los data frames son fundamentales en análisis de datos epidemiológicos y clínicos, ya que permiten estructurar información de pacientes o casos de manera ordenada, con cada fila representando un individuo y cada columna una variable.### ListasLas listas son estructuras más flexibles que pueden contener elementos de diferentes tipos, incluso otras listas o data frames:```{r}# Crear una listapaciente_info <-list(nombre ="Juan Pérez",edad =45,mediciones =c(120, 118, 122), # Vector de presiones sistólicaslabs =data.frame(parametro =c("Glucosa", "Colesterol", "Triglicéridos"),valor =c(95, 210, 180),unidad =c("mg/dL", "mg/dL", "mg/dL") ),fumador =FALSE)# Ver la listapaciente_info# Acceder a un elemento de la listapaciente_info$nombrepaciente_info$mediciones# Otra forma de acceder a elementospaciente_info[[1]] # Primer elemento (nombre)paciente_info[[3]] # Tercer elemento (mediciones)# Acceder a un data frame dentro de la listapaciente_info$labs# Acceder a un elemento específico dentro del data frame en la listapaciente_info$labs$valor[2] # Valor de colesterol```Las listas son útiles para almacenar resultados de análisis complejos, información heterogénea de pacientes o para agrupar varios objetos relacionados.## Indexación y selección de elementosLa indexación es crucial para extraer y manipular datos específicos. Hay varias formas de seleccionar datos:### Indexación de vectores```{r}# Vector de ejemplopresion_sistolica <-c(120, 135, 142, 118, 125, 131, 145)nombres <-c("Juan", "María", "Carlos", "Ana", "Pedro", "Laura", "Sergio")names(presion_sistolica) <- nombres# Seleccionar un elemento por su posiciónpresion_sistolica[3] # Tercer elemento# Seleccionar múltiples elementospresion_sistolica[c(1, 3, 5)] # Elementos 1, 3 y 5# Seleccionar un rangopresion_sistolica[2:5] # Del segundo al quinto elemento# Seleccionar por nombrepresion_sistolica["Pedro"]# Excluir elementos (signos negativos)presion_sistolica[-2] # Todos excepto el segundo elemento# Seleccionar con condiciones lógicaspresion_sistolica[presion_sistolica >130] # Valores mayores a 130```### Indexación de matrices```{r}# Usando la matriz creada anteriormentematriz_datos# Seleccionar un elemento específico [fila, columna]matriz_datos[3, 2] # Fila 3, columna 2# Seleccionar una fila completamatriz_datos[2, ] # Segunda fila# Seleccionar una columna completamatriz_datos[, 1] # Primera columna# Seleccionar múltiples filas y columnasmatriz_datos[c(1, 3, 5), ] # Filas 1, 3 y 5matriz_datos[, c(1, 2)] # Ambas columnas (toda la matriz)# Seleccionar por nombresmatriz_datos["Paciente 4", "Sistólica"]```### Indexación de data frames```{r}# Usando el data frame creado anteriormentepacientes_df# Seleccionar una columna con $pacientes_df$edad# Seleccionar una filapacientes_df[3, ] # Tercera fila# Seleccionar una celda específicapacientes_df[2, 3] # Fila 2, columna 3# Seleccionar múltiples columnaspacientes_df[, c("nombre", "edad", "imc")]# Seleccionar con condiciones lógicaspacientes_df[pacientes_df$edad >35, ] # Pacientes mayores de 35 añospacientes_df[pacientes_df$hipertension ==TRUE, ] # Pacientes con hipertensión```::: {.callout-tip}En análisis epidemiológicos, la selección por condiciones lógicas es extremadamente útil para filtrar casos por criterios específicos, como rangos de edad, presencia de factores de riesgo o valores límite de indicadores clínicos.:::## Manejo de valores ausentes (NA)En datos de salud es muy común encontrar valores faltantes. R representa estos valores con `NA` (Not Available):```{r}# Vector con valores NAglucosa <-c(95, 110, NA, 87, 122, NA, 105)# Verificar si hay NAis.na(glucosa)any(is.na(glucosa)) # ¿Hay algún NA?sum(is.na(glucosa)) # ¿Cuántos NA hay?# Calcular la media ignorando NAmean(glucosa) # Devuelve NAmean(glucosa, na.rm =TRUE) # Ignora los NA# Eliminar valores NAglucosa_completos <-na.omit(glucosa)glucosa_completos# Reemplazar NA con un valor (por ejemplo, la media)glucosa_reemplazo <- glucosaglucosa_reemplazo[is.na(glucosa_reemplazo)] <-mean(glucosa, na.rm =TRUE)glucosa_reemplazo```::: {.callout-warning}## El manejo de valores faltantes puede afectar tus conclusionesEl método que elijas para manejar los NA puede tener un impacto significativo en tus resultados:1. **Eliminar casos completos** (`na.omit()`) puede: - Reducir drásticamente el tamaño de la muestra - Introducir sesgos si los datos no faltan completamente al azar - Afectar la representatividad de la muestra2. **Imputación simple** (reemplazar con la media, mediana, etc.) puede: - Subestimar la variabilidad real - Distorsionar las relaciones entre variables - Dar una falsa sensación de precisión3. **Métodos avanzados** como imputación múltiple o modelos específicos para datos faltantes suelen ser preferibles en investigación rigurosa.Siempre documenta y justifica tu estrategia para manejar valores faltantes en cualquier análisis.:::## Ejercicio práctico: Análisis de datos de pacientesVamos a poner en práctica lo aprendido con un ejercicio sobre datos de pacientes:```{r}# Creamos un data frame con datos de pacientes hipotéticosset.seed(123) # Para reproducibilidaddatos_pacientes <-data.frame(id =1:20,edad =sample(18:80, 20, replace =TRUE),sexo =factor(sample(c("M", "F"), 20, replace =TRUE)),peso =round(rnorm(20, mean =70, sd =15), 1),altura =round(rnorm(20, mean =1.65, sd =0.1), 2),grupo_sanguineo =factor(sample(c("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"), 20, replace =TRUE)),presion_sistolica =sample(100:160, 20, replace =TRUE),presion_diastolica =sample(60:100, 20, replace =TRUE),glucosa =round(rnorm(20, mean =100, sd =20), 1),colesterol =round(rnorm(20, mean =200, sd =40), 1))# Añadimos algunos NA para practicardatos_pacientes$peso[c(3, 15)] <-NAdatos_pacientes$glucosa[c(7, 12, 18)] <-NA# Exploramos los datosdatos_pacientes```Ahora, analicemos estos datos con lo aprendido:```{r}# 1. ¿Cuántos pacientes hay de cada sexo?table(datos_pacientes$sexo)# 2. Calculamos el IMC para cada pacientedatos_pacientes$imc <- datos_pacientes$peso / (datos_pacientes$altura^2)head(datos_pacientes) # Mostramos las primeras filas# 3. ¿Cuántos pacientes tienen sobrepeso (IMC > 25)?sum(datos_pacientes$imc >25, na.rm =TRUE)# 4. Estadísticas básicas de presión arterialsummary(datos_pacientes[, c("presion_sistolica", "presion_diastolica")])# 5. Creamos una columna de categoría de presióndatos_pacientes$categoria_presion <-ifelse( datos_pacientes$presion_sistolica >=140| datos_pacientes$presion_diastolica >=90,"Hipertensión","Normal")datos_pacientes$categoria_presion <-factor(datos_pacientes$categoria_presion)# 6. ¿Cuántos pacientes tienen hipertensión?table(datos_pacientes$categoria_presion)# 7. Seleccionamos los pacientes con hipertensiónpacientes_hipertension <- datos_pacientes[datos_pacientes$categoria_presion =="Hipertensión", ]pacientes_hipertension# 8. Edad promedio de los pacientes con hipertensiónmean(pacientes_hipertension$edad)# 9. ¿Hay alguna relación entre sexo e hipertensión?table(datos_pacientes$sexo, datos_pacientes$categoria_presion)```## Ejercicio para practicarA continuación, se propone un pequeño conjunto de ejercicios para practicar lo aprendido. Intenta resolverlos por tu cuenta y luego compara con las soluciones:1. Crea un vector con los valores de glucosa y calcula la media, mediana y desviación estándar (ignorando los NA).2. Selecciona todos los pacientes mujeres (F) con colesterol superior a 200.3. Crea una nueva variable que clasifique el IMC en: "Bajo peso" (<18.5), "Normal" (18.5-24.9), "Sobrepeso" (25-29.9) y "Obesidad" (≥30).4. ¿Cuál es el grupo sanguíneo más común en tu dataset?5. Calcula la proporción de pacientes con glucosa superior a 126 mg/dL (un criterio para diabetes).::: {.callout-tip}## Estrategias para resolver problemas con R1. **Divide y vencerás**: Descompón problemas complejos en pasos más pequeños y resuelve cada uno por separado.2. **Usa la ayuda de R**: Si no recuerdas cómo funciona una función, usa `?nombre_funcion` para ver la documentación.3. **Comprueba tus resultados intermedios**: Verifica los resultados de cada paso con `head()`, `str()` o `summary()` para detectar problemas temprano.4. **Aprovecha la comunidad**: Sitios como Stack Overflow tienen respuestas a casi cualquier pregunta sobre R que puedas tener.:::```{r}# Soluciones (descubre primero por tu cuenta)# 1. Estadísticas de glucosaglucosa_stats <-c(Media =mean(datos_pacientes$glucosa, na.rm =TRUE),Mediana =median(datos_pacientes$glucosa, na.rm =TRUE),Desv_estandar =sd(datos_pacientes$glucosa, na.rm =TRUE))glucosa_stats# 2. Mujeres con colesterol > 200mujeres_colesterol_alto <- datos_pacientes[datos_pacientes$sexo =="F"& datos_pacientes$colesterol >200, ]mujeres_colesterol_alto# 3. Clasificación de IMCdatos_pacientes$categoria_imc <-cut( datos_pacientes$imc,breaks =c(0, 18.5, 24.9, 29.9, Inf),labels =c("Bajo peso", "Normal", "Sobrepeso", "Obesidad"),right =TRUE)table(datos_pacientes$categoria_imc, useNA ="ifany")# 4. Grupo sanguíneo más comúntable(datos_pacientes$grupo_sanguineo)which.max(table(datos_pacientes$grupo_sanguineo))# 5. Proporción con glucosa > 126 mg/dLprop_diabetes <-mean(datos_pacientes$glucosa >126, na.rm =TRUE)prop_diabetescat("Proporción de pacientes con glucosa > 126 mg/dL:", prop_diabetes *100, "%\n")```## Recursos adicionalesPara profundizar en los temas vistos hoy:- [R for Data Science - Capítulo 3](https://r4ds.had.co.nz/data-visualisation.html) - Visualización de datos- [R para Ciencia de Datos - Capítulo 3](https://es.r4ds.hadley.nz/visualizaci%C3%B3n-de-datos.html) - Versión en español- [Introduction to R for Health Data Science Students](https://bookdown.org/martin_monkman/DataScienceResources_book/r-clinical-health-science.html) - Recursos específicos para ciencias de la salud## Para la próxima sesiónEn la próxima sesión aprenderemos sobre:- Importación de datos desde archivos CSV, Excel y otros formatos- Técnicas para explorar y limpiar datos- Manejo de problemas comunes en datos crudos- Introducción al concepto de datos "tidy"Prepárate instalando los siguientes paquetes si aún no lo has hecho:```{r, eval=FALSE, message=FALSE, warning=FALSE}install.packages(c("readr", "readxl", "janitor", "skimr"))```## ConclusionesEn esta sesión hemos:- Comprendido la sintaxis básica de R- Aprendido sobre los diferentes tipos de datos (numéricos, caracteres, lógicos, factores)- Explorado las estructuras fundamentales (vectores, matrices, data frames, listas)- Practicado la indexación para seleccionar elementos específicos- Trabajado con valores NA- Aplicado estos conocimientos a un conjunto de datos de pacientesEstos fundamentos son la base para todo análisis de datos en salud. En las próximas sesiones, construiremos sobre estos conocimientos para realizar análisis más complejos y relevantes para la investigación en ciencias de la salud.¡Nos vemos en la próxima sesión!