Esta página web ofrece una introducción al programa R y al entorno de trabajo RStudio. Se incluyen algunos de los comandos más relevantes de R para un manejo eficiente y completo de los datos, la elaboración de gráficas básicas y algunas de las pruebas estadísticas más comunes.
Citando este recurso: Leis A, Mayer MA. Introducción al Programa R y RStudio. Estadística en Ciencias de la Salud. 2025 [Internet]. Disponible en: http://rpubs.com/mmayerp/curso_R.
R es un lenguaje de programación de distribución libre que permite la realización de análisis estadísticos y su representación gráfica. R fue creado en 1992 en Nueva Zelanda por Ros Ihaka y Robert Gentleman.
R permite el análisis de gran diversidad de datos y por tanto es aplicable en múltiples disciplinas.
Existen versiones del programa disponibles para Windows, Mac y Linux. El programa R consta de dos partes, una que llamaríamos “base”, que incluye un conjunto de funcionalidades básicas y que es la que obtenemos tras su instalación, y otra parte, que está constituida por módulos o librerías que se pueden instalar según las necesidades estadísticas que tengamos en cada momento.
En primer lugar, debemos instalar el programa estadístico R. Para ello debemos acceder a la web:
Una vez instalado R, debemos proceder a la instalación de RStudio. Para ello accedemos a la web:
RStudio es un interfaz que permite trabajar con R de manera sencilla, ofreciendo diversas opciones que facilitan un uso más amigable de R.
En la figura 1 podemos ver la pantalla de inicio de RStudio. La disposición de las pantallas y de los apartados se pueden muestran, pueden personalizarse en el menú Tools/Global Options.
A. En la zona superior izquierda pueden abrirse y editarse diversos ficheros que contienen comandos de R (editor de R). Aquí es donde trabajaremos con los archivos ejecutables o scripts en los que podemos ir guardando comandos y comentarios para ejecutarlos en cualquier momento. Los scripts de R tienen la extensión .r, por ejemplo “miprimerscript.r”.
B. En la zona inferior izquierda se encuentra la consola de RStudio en la que pueden ejecutarse los comandos de R y que se corresponde con la ventana que se mostraría si utilizáramos R sólo sin RStudio.
Tras el mensaje de apertura de R que aparece en esta consola, podemos ver el prompt, que es el símbolo “>”. Las expresiones en R se escriben a continuación del prompt y se presiona la tecla “intro” cada vez que queremos ejecutar una orden o comando.
Para recuperar comandos anteriores que hayamos realizado en una sesión de trabajo, los podemos recuperar desde la pestaña “History” de la zona superior derecha. Situados en la consola, con las teclas “hacia arriba” y “hacia abajo” de nuestro teclado, podemos movernos entre los comandos que hemos realizado en la sesión de trabajo.
C. La zona superior derecha tiene tres pestañas:
○ Environment: donde aparece la lista de los objetos creados en memoria (más adelante se indica lo que son los objetos en R).
○ History: que contiene el histórico de las líneas de código o comandos que hemos idos ejecutando en diversas sesiones de R. De una forma muy sencilla podemos incorporar los comandos seleccionados (simplemente clickando sobre un comando concreto), tanto a la ventana superior I (donde puede haber un script) clickando en “To Source”, como en la Consola con “To Console”. Para seleccionar varios comandos a la vez mientras los vamos seleccionando, debemos mantener la tecla “shift” oprimida.
○ Files: que da acceso al árbol de directorios y ficheros de nuestro ordenador.
D. La zona inferior derecha dispone de cuatro pestañas:
○ Plots: donde aparecen los gráficos que se generan desde la consola.
○ Packages: que facilita la gestión de los paquetes o librerías (packages) de R instalados en nuestro programa R.
○ Help: en el que se abren las páginas de ayuda.
○ Viewer: permite ver algunas aplicaciones de R que necesitan mostrarse vía web.
Accediendo al menú Tools/Global Options… y en el apartado Pane Layout podemos reorganizar a nuestro gusto las disposición y contenidos de las 4 ventanas que conforman RStudio.
Accediendo al menú Tools/Global Options… y en el apartado Pane Layout podemos reorganizar a nuestro gusto las disposición y contenidos de las 4 ventanas que conforman RStudio.
En primer lugar, debemos definir el directorio de trabajo de R y los archivos de los que disponemos en este directorio de trabajo. Se trata pues de la carpeta en la que por defecto estamos RStudio para a buscar los archivos con los que estaremos trabajando.
Para conocer en qué directorio por defecto nos encontramos debemos utilizar el comando:
getwd()
En RStudio podemos cambiar el directorio de trabajo clickando en el menú Tools/Global options… y en el apartado “General” que aparece en la ventana emergente, en “Browse…” podemos seleccionar la carpeta que será el nuevo directorio de trabajo de RStudio.
Otra forma muy rápida y fácil es dirigirnos a la ventana inferior D (por defecto), en la que podemos ver la pestaña “Files”. Esta pestaña abre el directorio de nuestro ordenador y de esta forma recorrer las carpetas hasta localizar la que nos interesa para ser el directorio de trabajo. Una vez escogida la carpeta, en la opción “More”, seleccionamos la opción “Set as Working Directory”, tal como muestra la figura 2:
En cualquier momento podemos seleccionar otro directorio de trabajo. Igualmente es posible ver el contenido del directorio de trabajo, es decir todos los archivos, scripts, etc., sin necesidad de salir de RStudio. Clickando en esta opción en la misma ventana inferior D se muestran todos los archivos.
Con la utilización del siguiente comando podemos también definir un Directorio de trabajo determinado donde se pueden situar los archivos de trabajo:
setwd("~/CursoR_Web")
# setwd("~/Library/Mobile Documents/com~apple~CloudDocs/Documents_Mac_Laptop_2017/Mayer/Curso_R_Web")
Las variables son las características de un sujeto y estas variables presentan determinados valores. Existen diversos tipos de variables:
Variables cuantitativas: los valores son numéricos, por ejemplo la edad, el peso, los valores de TA o los niveles de colesterol. Sin embargo podemos encontrar números que son etiquetas, por ejemplo código de visita.
Las variables cuantitativas discretas son por ejemplo el número de hijos, y cuantitativas continuas son por ejemplo, niveles de glucemia o la temperatura ya que siempre podemos encontrar valores intermedios.
Variables cualitativas: la escala de valores es nominal y su valor categórico viene definido por una cualidad y no por una cantidad. Por ejemplo, género, casado/a, presencia o ausencia de un efecto secundario. Las variables categóricas ordinales serían del tipo alto, medio y bajo por ejemplo para la variable clase social.
Variable independiente, normalmente representada por x, es aquella que determina o influye sobre el valor de otras variables, las llamadas variables dependientes.
Para comprender mejor cómo funciona R respecto a las TIPOLOGÍAS de datos debemos distinguir en primer lugar diversos “modos” de datos:
Lógico: que puede ser verdadero o falso.
Numérico: números reales (por ejemplo, 5 hijos).
Complejo: números complejos (para entendernos son aquellos que contienen decimales como por ejemplo peso de 80.6 kg).
Carácter: caracteres separados por comillas (como por ejemplo el nombre con el que denominamos una variable como ‘Género’ o “Género”).
Debemos distinguir también diversas clases o tipos de datos:
glucemia <- c(120, 110, 230, 149, 138)
Listas: que puede contener diversos modos diversos de datos.
Matrices: conjunto de datos del mismo modo, pero como se trata de una matriz de datos puede tener filas y columnas de datos, a modo de tabla para entendernos.
Factores: se trata de un vector pero sus elementos son categorías, sería en realidad un vector no numérico, como por ejemplo el género de los pacientes, que podríamos designar con las letras ‘H’ y ‘M’.
Data frame: conceptualmente se correspondería a una hoja de cálculo en la que existen diversos columnas (variables), que serían en realidad los vectores y los factores de R agrupados en un conjunto de datos. Por ejemplo, una columna o variable podría ser los niveles de glucemia y otra columna el género de dicho paciente. Las filas se corresponden con los casos. Es la estructura de datos que vamos a utilizar fundamentalmente en esta introducción a R.
¿Cómo nombrar una variable o un objecto en R? R distingue entre minúsculas y mayúsculas por lo que Diabetes y diabetes son dos variables diferentes. Para nombrar variables, vectores, etc. en R podemos utilizar letras, números, guiones bajos y puntos. Los nombres no deben comenzar sin embargo por números o un punto seguido de número.
Es recomendable para nombrar una variables no utilizar nombres que coincidean con comandos de R tales como head, mean, getwd, etc.
Los nombres siguienes serían válidos: diabetes, Diabetes, diabetes_2, diabetes.2, diabetes.hta, .diabetes.
No serían nombres de variable válidos: 3diabetes, diabetes-hta, 3.diabetes, .3diabetes.
Entre las medidas de tendencia o posición central más populares nos encontramos con la media, mediana y la moda.
# Creamos el vector edad (más adelante se explica con detalle el concepto
# y la creación de un "vector" y de un "data.frame" en R)
# con todos los datos
edad <- c(34,23,23,45,18,24,55,46,33,76)
# con todos los datos incluyendo un dato perdido (NA)
edadconNA <- c(34,23,23,45,18,24,55,NA,33,76)
# Calculamos las diferentes medidas de tendencia central
# Es recomendable utilizar el parámetro na.rm para excluir los datos perdidos "NA"
# en el cálculo ya que sino el resultado sería NA, veamos un ejemplo
mean(edad) # media
## [1] 37.7
median(edad) # mediana
## [1] 33.5
mean(edadconNA) # nos da error al contener datos perdidos NA
## [1] NA
mean(edadconNA, na.rm=TRUE) # evita el error al usar el parámetro na.rm
## [1] 36.77778
#
# Para el cálculo de la moda deberíamos instalar el package (o librería) "modeest"
# install.packages('modeest') # para el cálculo de la moda
# library('modeest') # para activar la librería (también marcándola en la pestaña "Packages")
# mfv(edad) # la moda se calcula con el comando mfv
#
# con na.omit(misdatos) se eliminarían todos los NA de un data.frame
# así por ejemplo si creamos el siguiente data.frame con diversos NA:
a <- c(2,3,5,2,3,NA,6)
b <- c(6,NA,5,8,NA,6,7)
c <- data.frame(a,b)
c
## a b
## 1 2 6
## 2 3 NA
## 3 5 5
## 4 2 8
## 5 3 NA
## 6 NA 6
## 7 6 7
# eliminamos todos los datos perdidos o NA y creamos un nuevo vector
c.sinNA <- na.omit(c)
c.sinNA
## a b
## 1 2 6
## 3 5 5
## 4 2 8
## 7 6 7
Entre las medidas de dispersión destacamos el rango, la varianza, la desviación estándar y el rango intercuartil y los cuantiles.
rango = max(edad) - min(edad) # creamos una variable llamada rango
rango # llamamos a la variable rango para mostrarla
## [1] 58
var(edad) # varianza
## [1] 325.7889
sd(edad) # desviación estándar
## [1] 18.04962
IQR(edad) # rango intercuartil (diferencia entre el primer y tercer cuartil)
## [1] 22.5
quantile(edad) # muestra todos los cuantiles
## 0% 25% 50% 75% 100%
## 18.00 23.25 33.50 45.75 76.00
# Otro comando de interés es range(), que nos muestra el valor mínimo y el valor máximo
range(edad)
## [1] 18 76
El concepto fundamental que debemos conocer en R, son los llamados “objetos”. Un objeto es cualquier elemento de trabajo que hayamos creado o introducido en una sesión de trabajo de R. Por tanto, un objeto puede ser una variable, un conjunto de datos, una función o incluso los resultados de un análisis.
Lo que escribamos precedido del signo #, R lo ignora y lo utilizamos para incluir comentarios que facilitan la comprensión de las órdenes que estamos ejecutando.
De momento nos centraremos en los “objetos” como tipo de variable, conjunto de datos y algunas funciones:
2 # es un dato, en este caso un número
## [1] 2
peso <- c(68, 45, 75, 63, 59) # un conjunto de datos numéricos en este caso es un "vector"
sum(peso) # función que suma todos los valores de los datos contenidos en "peso""
## [1] 310
Debemos conocer diversos comandos generales que nos van a permitir gestionar los datos que introduzcamos en RStudio. Para comenzar podemos destacar los siguientes:
getwd() # nos indicará cuál es el directorio de trabajo de R en nuestro ordenador
ls() # nos mostrará los objetos activos en la sesión de trabajo actual
dir() # nos mostrará los archivos que se encuentran en el directorio de trabajo de R
En esta sección vamos a realizar diversos comandos relacionados con el introducción de datos de dos variables creando dos objetos: genero, edad.
Imaginemos que tenemos un conjunto de sujetos de los que conocemos su género y su edad y queremos crear un conjunto de datos (llamado data.frame en R). Para entendernos un data.frame sería la típica hoja de cálculo de Excel que contiene las variables en las columnas y las filas son cada unos de los casos o sujetos.
Para la creación de una variable con un conjunto de datos procedemos de la siguiente forma:
# Debemos tener en cuenta que las variables categóricas (cualitativas) se introducen entre comillas.
# creamos la variable genero (en este caso de tipo cualitativa)
# utilizando el signo <- de asignación y la letra c() que es común para la creación de vectores.
genero <- c("h","m","m","h","m","h","h","m")
# creamos otra variable edad (cuantitativa) en años que llamaremos edad.v2.
edad.v2 <- c(23,45,34,39,60,52,44,76)
# creamos la variable colesterol (cuantitativa) en mg/dl
colesterol <- c(130, 189, 145, 201, 242, 220, 194, 245)
Una vez tenemos las variables con sus datos introducidos y creados, podemos generar el data.frame que incluya todas las variables tal como vemos a continuación.
Además, podemos utilizar diversos comandos que nos ofrecerán información completa del dataframe que hemos creado. Es recomendable explorar los datos antes de proceder a su análisis:
# creamos el data.frame con las variables genero, edad y colesterol
misdatos <- data.frame(genero, edad.v2, colesterol)
misdatos # llamamos al dataframe para visualizarlo en pantalla todos los datos que contiene
## genero edad.v2 colesterol
## 1 h 23 130
## 2 m 45 189
## 3 m 34 145
## 4 h 39 201
## 5 m 60 242
## 6 h 52 220
## 7 h 44 194
## 8 m 76 245
dim(misdatos) # nos permite ver el número de casos y el número de variables
## [1] 8 3
str(misdatos) # nos muestra el tipo de datos que tenemos
## 'data.frame': 8 obs. of 3 variables:
## $ genero : chr "h" "m" "m" "h" ...
## $ edad.v2 : num 23 45 34 39 60 52 44 76
## $ colesterol: num 130 189 145 201 242 220 194 245
names(misdatos) # nos muestra el nombre de las varibles que contiene el data.frame
## [1] "genero" "edad.v2" "colesterol"
nrow(misdatos) # nos indica el número de filas
## [1] 8
Con los siguientes comando podemos acceder a los diferentes datos de un data.frame (datos concretos, columnas, filas, etc.):
misdatos
## genero edad.v2 colesterol
## 1 h 23 130
## 2 m 45 189
## 3 m 34 145
## 4 h 39 201
## 5 m 60 242
## 6 h 52 220
## 7 h 44 194
## 8 m 76 245
head(misdatos) # muestra sólo los primeros 6 casos (en este caso son todos)
## genero edad.v2 colesterol
## 1 h 23 130
## 2 m 45 189
## 3 m 34 145
## 4 h 39 201
## 5 m 60 242
## 6 h 52 220
tail(misdatos) # muestra los últimos 6 casos (son todos en este caso)
## genero edad.v2 colesterol
## 3 m 34 145
## 4 h 39 201
## 5 m 60 242
## 6 h 52 220
## 7 h 44 194
## 8 m 76 245
misdatos[,1] # muestra la primera columna de datos
## [1] "h" "m" "m" "h" "m" "h" "h" "m"
misdatos[3,] # muestra los datos de las tres columnas del sujeto en posición 3
## genero edad.v2 colesterol
## 3 m 34 145
misdatos[2,3] # tercera columna segundo caso
## [1] 189
misdatos[2,c(1,3)] # columnas 1 y 3 del segundo caso
## genero colesterol
## 2 m 189
misdatos[2,c(1:3)] # columnas de 1 a 3 del segundo caso
## genero edad.v2 colesterol
## 2 m 45 189
misdatos[c(2:4),c(1:3)] # columnas de 1 a 3 de los casos 2 al 4
## genero edad.v2 colesterol
## 2 m 45 189
## 3 m 34 145
## 4 h 39 201
misdatos[,"colesterol"] # muestra los datos de la columna "colesterol"
## [1] 130 189 145 201 242 220 194 245
misdatos[order(misdatos$colesterol),] # ordernar los datos según colesterol
## genero edad.v2 colesterol
## 1 h 23 130
## 3 m 34 145
## 2 m 45 189
## 7 h 44 194
## 4 h 39 201
## 6 h 52 220
## 5 m 60 242
## 8 m 76 245
En ocasiones puede ser muy útil la creación de una tabla de datos en la que introducimos el total de casos para cada variable. Creamos unos datos de pacientes obesos y no obesos y su género. Para ello utilizamos el comando “matrix()” de la siguiente forma:
datos <- c(6,26,18,44) # total de casos para la tabla de 2x2
mitabla <- matrix(datos, # el nombre del vector que contiene las cantidades a introducir
nrow=2, # número de filas de la tabla
ncol=2, # número de columnas de la tabla de datos
dimnames=list(c("Obesos","No Obesos"), c("hombres","mujeres"))) # nombres de las variables
mitabla # mostramos el resultado
## hombres mujeres
## Obesos 6 18
## No Obesos 26 44
# mostramos los nombres de las variables
names(misdatos)
## [1] "genero" "edad.v2" "colesterol"
# cambiamos el nombre de la segunda columna (edad.v2) o variable a Edad
names(misdatos)[2] <- "Edad"
# cambiamos el nombre de la tercera columna (colesterol) a Colesterol
# Debemos tener en cuenta que las minúsculas o mayúsculas se interpreta como otra variable
names(misdatos)[3] <- "Colesterol"
misdatos
## genero Edad Colesterol
## 1 h 23 130
## 2 m 45 189
## 3 m 34 145
## 4 h 39 201
## 5 m 60 242
## 6 h 52 220
## 7 h 44 194
## 8 m 76 245
# también podemos utilizar el package plyr para renombrar variables
# install.packages('plyr')
# library(plyr)
# misdatos <- rename(misdatos, c(Edad="EDAD"))
# creamos la variable obesidad que añadimos al data.frame llamado misdatos
# para ello simplemente añadimos al nombre del data.frame el signo "$" y el nombre de la
# nueva variable a la que la asignamos los valores que contiene como en cualquier vector
# al tratarse de un factor (etiqueta de texto), cada caso debe ir entre comillas
misdatos$obesidad <- c("no","no","si","si","si","si","si","no")
misdatos
## genero Edad Colesterol obesidad
## 1 h 23 130 no
## 2 m 45 189 no
## 3 m 34 145 si
## 4 h 39 201 si
## 5 m 60 242 si
## 6 h 52 220 si
## 7 h 44 194 si
## 8 m 76 245 no
# eliminamos la nueva variable (se encuentra en la 4a posición) creando un nuevo data.frame
misdatossin <- misdatos[c(-4)]
misdatossin
## genero Edad Colesterol
## 1 h 23 130
## 2 m 45 189
## 3 m 34 145
## 4 h 39 201
## 5 m 60 242
## 6 h 52 220
## 7 h 44 194
## 8 m 76 245
# ahora añadimos otra nueva variable con fechas con la función as.Date() ya que sino R interpretaría
# que se trata de datos de texto. El formato de fecha que reconoce directamente es YYYY-MM-DD
misdatos$fecha.analis<- as.Date(c("2017-08-11", "2017-12-12", "2017-12-23",
"2017-08-11", "2017-12-12", "2017-12-23", "2017-08-11", "2017-12-23"))
# en ocasiones hay que adaptar el formato de fecha al formato de R. Por ejemplo,
# si el formato es 10/01/2012 debería convertirse a 2012-01-10 de la siguiente forma:
# fecha <- as.Date(fecha, format='%d/%m/%Y')
# podemos añadir otra variable, colesterol en mmol/l, como variable calculada, es decir a partir de los
# datos de otras variables del mismo data.frame. En este caso transformamos colesterol de mg/dl a mmol/l
# con la función round() y el argumento digits=1, le indicamos que el resultado contenga únicamente un decimal. Recordemos que ahora la variable es Colesterol, no colesterol
misdatos$col.mmol <- round(misdatos$Colesterol/38.4615, digits=1)
misdatos
## genero Edad Colesterol obesidad fecha.analis col.mmol
## 1 h 23 130 no 2017-08-11 3.4
## 2 m 45 189 no 2017-12-12 4.9
## 3 m 34 145 si 2017-12-23 3.8
## 4 h 39 201 si 2017-08-11 5.2
## 5 m 60 242 si 2017-12-12 6.3
## 6 h 52 220 si 2017-12-23 5.7
## 7 h 44 194 si 2017-08-11 5.0
## 8 m 76 245 no 2017-12-23 6.4
# añadimos 4 nuevos casos al data.frame pacientes
# mostramos el nombre de las variables del data.frame anterior
names(misdatos)
## [1] "genero" "Edad" "Colesterol" "obesidad" "fecha.analis"
## [6] "col.mmol"
# nuevos datos para cada variable, en este caso 4 nuevos casos
genero <- c("h", "m", "m", "h")
Edad <- c(23,35,36,39) # recordemos que es Edad y no edad.v2
Colesterol <- c(135, 149, 201, 242)
obesidad <- c("no","no","si","si")
fecha.analis <- as.Date(c("2017-08-11", "2017-12-12", "2017-12-23","2017-08-11"))
maspacientes <- data.frame(genero,Edad,Colesterol,obesidad,fecha.analis)
maspacientes$col.mmol <- round(maspacientes$Colesterol/38.4615, digits=1)
# unimos ambos data.frames con el comando "rbind" y ahora tenemos 10 casos
misdatos10 <- rbind(misdatos,maspacientes)
misdatos10
## genero Edad Colesterol obesidad fecha.analis col.mmol
## 1 h 23 130 no 2017-08-11 3.4
## 2 m 45 189 no 2017-12-12 4.9
## 3 m 34 145 si 2017-12-23 3.8
## 4 h 39 201 si 2017-08-11 5.2
## 5 m 60 242 si 2017-12-12 6.3
## 6 h 52 220 si 2017-12-23 5.7
## 7 h 44 194 si 2017-08-11 5.0
## 8 m 76 245 no 2017-12-23 6.4
## 9 h 23 135 no 2017-08-11 3.5
## 10 m 35 149 no 2017-12-12 3.9
## 11 m 36 201 si 2017-12-23 5.2
## 12 h 39 242 si 2017-08-11 6.3
# eliminando una fila concreta
misdatos10.sincaso3 <- misdatos10[-3,] # elimina toda la fila 3 de datos
head(misdatos10.sincaso3,4) # mostramos las 4 primeras filas y ya no aparece la fila 3
## genero Edad Colesterol obesidad fecha.analis col.mmol
## 1 h 23 130 no 2017-08-11 3.4
## 2 m 45 189 no 2017-12-12 4.9
## 4 h 39 201 si 2017-08-11 5.2
## 5 m 60 242 si 2017-12-12 6.3
Para importar los datos de un archivo en formato txt no es necesario instalar ninguna librería adicional.
# Podemos importar los datos de un archivo llamado "pacientes.txt" directamente
# a un data.frame que llamaremos pacientes si el archivo se encuentra en el directorio de trabajo:
pacientes <- read.table("pacientes.txt")
# si el archivo dispone de los nombres de las columnas o variables en la primera fila,
# algo que es habitual, es conveniente utilizar el siguiente comando:
pacientes <- read.table("pacientes.txt", header =TRUE) # TRUE se puede escribir como T
# a veces también necesitamos el argumento sep="", para indicar que la separación de columnas
# en el archivo original están separadas por:
# - tabuladores en la forma sep="\t"
# - comas sep=","
# - puntos y comas sep=";"
# por ejemplo: pacientes <- read.table("pacientes.txt", header=TRUE, sep="\t")
# Vemos la estructura del data.frame
dim(pacientes)
## [1] 30 7
str(pacientes)
## 'data.frame': 30 obs. of 7 variables:
## $ Edad : int 56 49 66 78 50 53 64 62 71 75 ...
## $ Genero : chr "H" "M" "H" "H" ...
## $ Diabetes : chr "No" "No" "Si" "Si" ...
## $ Glucemia : int 116 105 134 140 90 95 114 105 150 145 ...
## $ Colesterol: int 210 180 190 280 165 186 210 198 238 266 ...
## $ IAM : chr "No" "No" "No" "Si" ...
## $ Trat : chr "Si" "Si" "No" "Si" ...
Debemos instalar una librería específica para el manejo de archivos en formato Excel. Un librería en R es el conjunto de funcionalidades específicas para determinados análisis o acciones sobre los datos. En este caso nos permite importar un archivo en formato Excel de una forma adecuada.
Podemos realizar esta acción desde el menú principal de RStudio, en File/Import Dataset/From Excel… y seguir los pasos que nos va indicando RStudio.
# install.packages('openxlsx') # instala la librería openxlsx
# library('openxlsx') # carga en la sesión de trabajo la librería openxlsx
# si disponemos de un archivo llamado pacientes.xslx:
# pacientes <- read.xlsx('pacientes.xlsx')
Debemos instalar con librerías específicas (foreign o Hmisc) para el manejo de archivos en formato SPSS. Al igual que en el caso anterior podemos importar estos datos utilizando el menú principal de RStudio.
# install.packages('foreign') # instala la librería foreign
# install.packages('Hmisc') # instala la librería Hmisc
# library('Hmisc') # por ej. si cargamos esta librería en la sesión de trabajo
# y disponemos de un archivo llamado mispacientes.sav para importarlo en R:
# pacientes <- spss.get("mispacientes.sav")
Para importar un archivo en formato csv no es necesario instalar una librería adicional. Podemos utilizar read.csv o read.csv2.
# pacientes <- read.csv2('pacientes.csv')
# si creamos un data.frame podemos guardar su contenido
# en otro archivo csv que llamaremos p.ej. pacientes2.csv
# dicho archivo se grabará en nuestro ordenador en el directorio de trabajo
write.table(pacientes, # nombre del data.frame
file="pacientes2.csv", # nombre del archivo csv
sep="\t", # indicamos que las columnas de datos están
# separados por espacio
row.names=FALSE) # indicamos que no incluya nombres de filas
Los archivos .csv separan los datos que forman sus columans o variables de diversas formas, dependiendo de cómo lo hemos guardado en Excel u otros programas. Las opciones que nos muestran Excel o LibreOffice u OpenOffice cuando guardamos un csv son p.ej., csv separado con comas o separados por espacios. Para importar o exportar adecuadamente estos archivos, debemos utilizar el argumento: sep=““.
sep=“” tiene diversas opciones como: sep”,” para comas y sep” para espacios. A veces cuando están separados por comas, debemos utilizar en realidad el punto y coma y entonces debemos escribir sep=“;”.
En esta sección vamos a repasar algunos de los comandos mencionados anteriormente y que nos permitirán explorar un conjunto de datos. Utilizaremos el archivo “pacientes.txt” que se puede obtener de la siguiente URL (para ver el contenido del archivo, clickar en el enlace con el botón contrario del ratón y abrir en un nueva pestaña o ventana): “https://raw.githubusercontent.com/mmayerp/cursoR/master/pacientes.txt”. Podemos grabar este archivo desde el navegador (Chrome por ejemplo) mediante el menú File/Save Page As…
Para importar el archivo directamente a R desde Internet, utilizaremos los siguientes comandos, creando la variable url que contiene la URL del archivo pacientes.txt y asignándolo al objeto “pacientes”. Para ello visitamos la URL siguiente y al abrirse la página guardamos dicha página en nuestro PC en formato .txt
url <- "https://raw.githubusercontent.com/mmayerp/cursoR/master/pacientes.txt"
# la misma url reducida con t2mio.com:
url <- "https://t2m.io/HN3qxXt5"
# utilizamos la función read.csv para importar el archivo txt que contiene la variable "url"
pacientes <- read.csv(url, sep="\t")
# podemos importar el mismo documento también en fomato Excel pacientes.xlsx
# para ello debemos instalar y llamar al package 'openxlsx'
url.xl <- "https://t2m.io/d8UpmiXn"
Pacientes <- read.xlsx(url.xl) # le llamamos Pacientes con P mayúscula
Utilizamos los comandos str, dim y names para describir el dataframe pacientes y table para frecuencias de variables categóricas, head para ver los primeros 6 casos y summary para una descripción general
str(pacientes) # nos indica el tipo de variables que contiene el dataframe
## 'data.frame': 30 obs. of 7 variables:
## $ Edad : int 56 49 66 78 50 53 64 62 71 75 ...
## $ Genero : chr "H" "M" "H" "H" ...
## $ Diabetes : chr "No" "No" "Si" "Si" ...
## $ Glucemia : int 116 105 134 140 90 95 114 105 150 145 ...
## $ Colesterol: int 210 180 190 280 165 186 210 198 238 266 ...
## $ IAM : chr "No" "No" "No" "Si" ...
## $ Trat : chr "Si" "Si" "No" "Si" ...
dim(pacientes) # el número de casos y variables
## [1] 30 7
names(pacientes) # nos muestra el nombre de las variables
## [1] "Edad" "Genero" "Diabetes" "Glucemia" "Colesterol"
## [6] "IAM" "Trat"
head(pacientes, 10) # muestra los primeros 10 casos
## Edad Genero Diabetes Glucemia Colesterol IAM Trat
## 1 56 H No 116 210 No Si
## 2 49 M No 105 180 No Si
## 3 66 H Si 134 190 No No
## 4 78 H Si 140 280 Si Si
## 5 50 M No 90 165 No No
## 6 53 M No 95 186 No No
## 7 64 H No 114 210 No Si
## 8 62 M No 105 198 No Si
## 9 71 H Si 150 238 No Si
## 10 75 M Si 145 266 Si Si
summary(pacientes) # realiza una descripción numérica general de todas las variables que contiene el dataframe
## Edad Genero Diabetes Glucemia
## Min. :34.0 Length:30 Length:30 Min. : 86.0
## 1st Qu.:50.5 Class :character Class :character 1st Qu.: 98.5
## Median :63.0 Mode :character Mode :character Median :113.0
## Mean :61.1 Mean :119.4
## 3rd Qu.:72.5 3rd Qu.:140.0
## Max. :81.0 Max. :167.0
## Colesterol IAM Trat
## Min. :138.0 Length:30 Length:30
## 1st Qu.:187.8 Class :character Class :character
## Median :215.0 Mode :character Mode :character
## Mean :221.7
## 3rd Qu.:262.0
## Max. :300.0
table(pacientes$Genero) # tabla de frecuencias absolutas de Genero
##
## H M
## 16 14
(table(pacientes$Genero)/30)* 100 # tabla de frecuencias relativas de Genero
##
## H M
## 53.33333 46.66667
round((table(pacientes$Genero)/30)* 100, 2) # redondeando con dos decimales
##
## H M
## 53.33 46.67
# tabla de frecuencias con dos variables categóricas (Genero e IAM)
table(pacientes$Genero, pacientes$IAM)
##
## No Si
## H 10 6
## M 11 3
# muestra los primeros 6 casos (utilizamos el package kableExtra) para mostrar la tabla
library(kableExtra)
library(knitr)
kable(head(pacientes)) %>%
kable_styling(bootstrap_options = "striped", full_width = F, position="left")
Edad | Genero | Diabetes | Glucemia | Colesterol | IAM | Trat |
---|---|---|---|---|---|---|
56 | H | No | 116 | 210 | No | Si |
49 | M | No | 105 | 180 | No | Si |
66 | H | Si | 134 | 190 | No | No |
78 | H | Si | 140 | 280 | Si | Si |
50 | M | No | 90 | 165 | No | No |
53 | M | No | 95 | 186 | No | No |
summary(pacientes$Edad) # resumen información general del dataframe edad
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 34.0 50.5 63.0 61.1 72.5 81.0
min(pacientes$Edad) # el valor mínimo
## [1] 34
max(pacientes$Edad) # el valor máximo
## [1] 81
which.max(pacientes$Edad) # índice o posición del valor máximo
## [1] 15
# con el comando attach(pacientes) indicamos a R que trabaje sólo con el dataframe
# pacientes, por lo para hacer referencia a las variables no es necesario utiliar ..$nombrevariable
attach(pacientes)
## The following objects are masked _by_ .GlobalEnv:
##
## Colesterol, Edad
rango = max(Edad) - min(Edad)
order(Edad) # ordena los valores mostrando la posición que ocupan
## [1] 1 2 3 4
sort(Edad) # ordena de menor a mayor mostrando los valores
## [1] 23 35 36 39
mean(Edad) # calcula la media
## [1] 33.25
var(Edad) # calcula la varianza
## [1] 49.58333
sd(Edad) # calcula la desviación estándar
## [1] 7.041543
detach(pacientes) # indicamos de nuevo a R que no trabaje sólo con el dataframe pacientes
# podemos comparar las medias de una variable numérica en función de las
# categorías de otra variable factor de dos formas diferentes:
aggregate(pacientes$Edad,by=list(pacientes$Genero),mean) # función aggregate() para por ejemplo edad y género
## Group.1 x
## 1 H 65.87500
## 2 M 55.64286
by(pacientes$Glucemia, pacientes$Genero, mean) # función by() para por ejemplo glucemia y género
## pacientes$Genero: H
## [1] 128.6875
## ------------------------------------------------------------
## pacientes$Genero: M
## [1] 108.8571
# con "subset" podemos seleccionar un grupo de pacientes según
# un valor determinado de una variable cuantitativa, por ejemplo, pacientes con valores
# de coleterol mayor o igual a 230:
colesterol230 <- subset(pacientes, Colesterol >= 230, # valores 230 o más
select=c(Genero, Colesterol)) # variables a mostrar
colesterol230
## Genero Colesterol
## 4 H 280
## 9 H 238
## 10 M 266
## 12 H 295
## 15 M 275
## 18 H 269
## 19 H 249
## 20 M 290
## 21 H 235
## 22 H 250
## 24 H 280
## 28 H 300
Una forma muy útil de realizar una exploración general de las variables de un dataset, tanto de las categóricas como de las numéricas, es mediante la libreria “funModeling”. Mediante el comando freq() podemos obtener un resumen de los datos y la representación gráfica de las variables categóricas, y con el comando profiling_num() y plot_num() el resumen y representación de las variables numéricas respectivamente.
# instalar el packages: install.packages('funModeling')
library('funModeling')
# datos categóricos (se muestra únicamente género pero se aplicaría
# a todas las variables categóricas utilizando en comando freq(pacientes)
freq(pacientes$Genero)
## var frequency percentage cumulative_perc
## 1 H 16 53.33 53.33
## 2 M 14 46.67 100.00
# datos numéricos
profiling_num(pacientes)
## variable mean std_dev variation_coef p_01 p_05 p_25 p_50 p_75
## 1 Edad 61.1000 13.58079 0.2222716 34.87 39.70 50.50 63 72.5
## 2 Glucemia 119.4333 24.10420 0.2018214 86.87 89.45 98.50 113 140.0
## 3 Colesterol 221.7333 45.09372 0.2033692 144.38 162.25 187.75 215 262.0
## p_95 p_99 skewness kurtosis iqr range_98 range_80
## 1 79.55 80.71 -0.2453930 1.996786 22.00 [34.87, 80.71] [43, 78.1]
## 2 158.20 164.97 0.3928345 1.787801 41.50 [86.87, 164.97] [94.5, 150.6]
## 3 292.75 298.55 0.1718075 1.951743 74.25 [144.38, 298.55] [166.8, 281]
plot_num(pacientes)
La representación gráfica de los datos constituye una herramienta fundamental para la visualización de los mismos y nos permite ofrecer un primer contacto con las características de los datos.
Para representar los datos cualitativos utilizando el diagrama de barras o el de sectores en R, debemos disponer del contaje de casos de las variables a representar. Para ello, como hemos visto anteriormente, debemos utilizar el comando table.
barplot(table(pacientes$Genero))
# Añadimos diversos parámetros para mejorar el aspecto y su presentación
barplot(table(pacientes$Genero), # datos género
main="Distribución género", # título
col=c("red","blue"), # damos color a las barras
ylab="Frecuencia") # etiqueta de las ordenadas
En la siguiente URL disponemos del listado de colores en R y cómo hacer referencia a cada color numéricamente: http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf
En el diagrama de sectores disponemos de diversas opciones gráficas.
# representación básica
pie(table(pacientes$Genero))
# indicamos que se muestren en paralelo los dos siguientes gráficos
par(mfrow=c(1,2))
# completamos diversos datos y aplicamos colores
pie(table(pacientes$Genero),
main="Distribución por género", # título
col=c("red","blue"), # damos color a los sectores
labels=c("Hombre", "Mujer"))
# otra representación con tantos por ciento
piepercent <- round(prop.table(table(pacientes$Genero))*100,2)
pie(table(pacientes$Genero),
main="Distribución por género", # título
col=c("red","blue"), # damos color a los sectores
labels=piepercent)
legend("topright", c("Hombre","Mujer"), cex=0.8, fill=c(2,4)) # añadimos la leyenda al gráfico
Para la representación de variables cuantitativas disponemos de diversas opciones gráficas.
par(mfrow=c(1,2)) # indica que ambos gráficos se muestren en una misma imagen
hist(pacientes$Colesterol, col=c("Orange"), # color de las columnas
main="Niveles de Colesterol", # título principal
xlab="Colesterol (en mg/dl)", # etiqueta (label) del eje x
ylab="Frecuencia") # etiqueta del eje y
hist(pacientes$Glucemia,
col=c("Blue"),
main="Niveles de Glucemia",
xlab="Glucemia (en mg/dl)",
ylab="Frecuencia",
breaks=10) # indicamos el número de intervalos de los datos aunque también
# podemos simplemente añadir la cifra 10 o la que nos interese sin incluir
# el argumento "breaks" ya que lo interpreta igualmente
El boxplot nos muestra de forma gráfica la distribución de una variable cuantitativa con el formato de caja.
# Distribución de la edad
boxplot(edad)
par(mfrow=c(2,2)) # con par(mfrow=c()) podemos indicar el número de figuras que se muestran
# en este caso cuatro imágenes dispuestas 2x2
# Comparación de la edad en ambos sexos (variable edad en función sexo):
boxplot(pacientes$Edad ~ pacientes$Genero)
# Otra forma sería separar el grupo en dos subgrupos en función de una variable determinada
# utilizando el comando split: boxplot(split(pacientes$Edad, pacientes$Genero))
# Ahora añadimos información diversa
boxplot(pacientes$Edad ~ pacientes$Genero, main="Edad y género")
boxplot(pacientes$Edad ~ pacientes$Genero, main="Edad y género", ylab="Años")
# En esta última versión incluimos colores y etiquetas diversas
boxplot(pacientes$Edad ~ pacientes$Genero,
main="Distribución Edad según Género", # incluimos el título
xlab="Años", ylab="Género", # etiquetas de x e y
names=c("H", "M"), # indica cada grupo de género
horizontal=TRUE, # dispone en horizontal los boxplots
col=c("red","yellow")) # colorea los boxplots
stem(pacientes$Edad) # diagrama en ramas y hojas (stem-and-leaf)
##
## The decimal point is 1 digit(s) to the right of the |
##
## 3 | 4
## 3 | 7
## 4 | 33
## 4 | 589
## 5 | 023
## 5 | 569
## 6 | 0244
## 6 | 567
## 7 | 113
## 7 | 55889
## 8 | 01
Utilizamos el dataset pacientes
pacientes
## Edad Genero Diabetes Glucemia Colesterol IAM Trat
## 1 56 H No 116 210 No Si
## 2 49 M No 105 180 No Si
## 3 66 H Si 134 190 No No
## 4 78 H Si 140 280 Si Si
## 5 50 M No 90 165 No No
## 6 53 M No 95 186 No No
## 7 64 H No 114 210 No Si
## 8 62 M No 105 198 No Si
## 9 71 H Si 150 238 No Si
## 10 75 M Si 145 266 Si Si
## 11 45 M No 100 174 No No
## 12 55 H No 116 295 Si No
## 13 43 M No 98 190 No Si
## 14 78 H Si 160 220 Si No
## 15 81 M Si 140 275 Si No
## 16 67 H Si 156 220 No Si
## 17 48 M No 112 138 No No
## 18 64 H No 97 269 No Si
## 19 59 H Si 167 249 Si No
## 20 79 M No 105 290 Si No
## 21 80 H Si 136 235 No Si
## 22 71 H Si 145 250 No Si
## 23 52 M No 98 220 No No
## 24 73 H Si 136 280 Si No
## 25 34 M No 86 160 No Si
## 26 60 H No 106 210 No Si
## 27 37 H No 89 167 No Si
## 28 75 H No 97 300 Si No
## 29 65 M No 100 200 No Si
## 30 43 M Si 145 187 No Si
# Tabla de datos de Género
table(pacientes$Genero) # en números absolutos
##
## H M
## 16 14
table(pacientes$Genero, pacientes$IAM) # tabla de 2x2 entre Genero e IAM
##
## No Si
## H 10 6
## M 11 3
round(prop.table(table(pacientes$Genero, pacientes$IAM))*100, 2) # en frecuencia relativa con la función prop.table() y redondeado con round() y dos decimales
##
## No Si
## H 33.33 20.00
## M 36.67 10.00
# Otras tablas de datos que pueden ser intersantes para conocer la frecuencia de datos cualitativos
table(pacientes$IAM)
##
## No Si
## 21 9
table(pacientes$Trat)
##
## No Si
## 13 17
Variables cuantitativas:
Resumen numérico básico de variables cuantitativas. En este ejemplo mostramos la forma de crear subgrupos de datos en un dataframe sobre una variable determinada. Esto es muy útil para separar los subgrupos existentes según los niveles de una variable cualitativa y poder comparar las variables cuantitativas entre ambos grupos. Por ejemplo, en la variable IAM tenemos un subgrupo de pacientes con infarto en el que el valor de IAM es “Si” y el subgrupo sin IAM cuyo valor de la variable es “No”. Creamos dos vectores con los valores de colesterol de cada grupo según la variable IAM.
# Debemos crear un subgrupo de datos (subsetting): con la función "which"
iamNo <- pacientes[which(pacientes$IAM == "No"), "Colesterol"]
iamSi <- pacientes[which(pacientes$IAM == "Si"), "Colesterol"]
###### representación para comparar los valores de colesterol entre pacientes
###### con IAM y sin IAM
# creación de colores transparentes
mycol2 <- rgb(255,255,0, max=255, alpha=125) # color amarillo
mycol <- rgb(0,0,255, max=255, alpha=125) # color azul
Histogramas
# histogramas representados como gráficos en paralelo en la misma imagen
par(mfrow=c(1,2))
# un histograma para cada subgrupo
hist(iamNo,
main="Niveles colesterol con IAM", # título del gráfico
col="blue", # color de las barras
xlab="Pacientes sin IAM", ylab="Colesterol", # etiquetas de los ejes x e y
xlim=c(100,300), # indicamos los límites del eje x
ylim=c(0,5), # indicamos los límites del eje y
breaks=5) # este parámetro establece el número de intervalos de datos
hist(iamSi,
main="Niveles colesterol con IAM", # título del gráfico
col="gold", # color de las barras
xlab="Pacientes con IAM", ylab="Colesterol", # etiquetas de los ejes x e y
xlim=c(100,300), # indicamos los límites del eje x
ylim=c(0,5), # indicamos los límites del eje y
breaks=5) # este parámetro establece el número de intervalos de datos
Boxplots
# comparación mediante boxplot
boxplot(Colesterol ~ IAM,
data=pacientes,
main="Colesterol en pacientes sin IAM y con IAM",
ylab="Nivel de Colesterol (mg/dl)",
xlab="Infarto Agudo de Miocardio")
# otra forma de comparar boxplots de dos grupos de colesterol según tengan IAM o no
# utilizando los subgrupos creados anteriormente
boxplot(iamNo, iamSi,
main="Colesterol en pacientes sin IAM y con IAM",
ylab="Nivel de Colesterol (mg/dl)",
xlab="IAM")
A continuación se expone un cuadro general sobre algunas de las pruebas estadísticas para identificar la relación entre variables y que deben aplicarse en función del tipo de variable estudiada:
En ocasiones vamos a necesitar el uso del signo ~. Este signo ~ se obtiene en Windows con la combinación de las teclas ALT y los dígitos 126 en el teclado numérico, con Mac debemos combinar las teclas alt y ñ.
Es la distribución de probabilidad de una variable continua que aparece con gran frecuencia con datos reales.
set.seed(111)
datos <- rnorm(100,3,2)
hist(datos, freq=FALSE, main="Distribución normal", ylab="P(datos)", xlab="datos")
curve(dnorm(x,3,2), add=TRUE)
Es la distribución de probabilidad de la estimación de una media. Se muestra el % de datos según incluyamos diversas desviaciones estándar.
Distribución t de Student. Código obtenido y modificado de Rob Knell. Introductory R (2014).
Clásicamente para la comparación de dos variables cualitativas se utilizaba la prueba de Chi cuadrado o la prueba exacta de Fisher. Sin embargo, gracias a la potencia de computación acutal y también cuando en la tabla de datos existen celdas con valores < 5, es recomendable utilizar de forma general la prueba exacta de Fisher “fisher.test()”.
# creación de una tabla de datos de frecuencias absolutas con el comando "matrix"
grupo <- matrix(c(30,38,74, 65, 26, 44, 8, 17),ncol=4,
dimnames=list(c("Hombres", "Mujeres"),
c("solteros","casados", "divorciados", "viudos")))
grupo
## solteros casados divorciados viudos
## Hombres 30 74 26 8
## Mujeres 38 65 44 17
# tabla de frecuencias relativas
prop.table(grupo)
## solteros casados divorciados viudos
## Hombres 0.09933775 0.2450331 0.08609272 0.02649007
## Mujeres 0.12582781 0.2152318 0.14569536 0.05629139
margin.table(grupo, 1)
## Hombres Mujeres
## 138 164
margin.table(grupo, 2)
## solteros casados divorciados viudos
## 68 139 70 25
round(prop.table(grupo),2)* 100
## solteros casados divorciados viudos
## Hombres 10 25 9 3
## Mujeres 13 22 15 6
# Prueba de chi cuadrado de comparación de proporciones y Fisher test
chisq.test(grupo)
##
## Pearson's Chi-squared test
##
## data: grupo
## X-squared = 7.2075, df = 3, p-value = 0.06557
fisher.test(grupo)
##
## Fisher's Exact Test for Count Data
##
## data: grupo
## p-value = 0.06743
## alternative hypothesis: two.sided
# Otros ejemplos en el que no creamos la tabla sino que utilizamos el data.frame o conjunto de datos # directamente. Utilizaremos el dataset de pacientes en el que trataremos de determinar si existe
# relación entre el hecho de recibir tratamiento y padecer o no IAM:
Trat.IAM <- table(pacientes$Trat, pacientes$IAM)
Trat.IAM
##
## No Si
## No 6 7
## Si 15 2
fisher.test(Trat.IAM, alternative="two.sided")
##
## Fisher's Exact Test for Count Data
##
## data: Trat.IAM
## p-value = 0.01959
## alternative hypothesis: true odds ratio is not equal to 1
## 95 percent confidence interval:
## 0.009864672 0.897967749
## sample estimates:
## odds ratio
## 0.1242642
# Podemos estudiar también la relación entre diabetes y IAM
fisher.test(table(pacientes$Diabetes, pacientes$IAM))
##
## Fisher's Exact Test for Count Data
##
## data: table(pacientes$Diabetes, pacientes$IAM)
## p-value = 0.1019
## alternative hypothesis: true odds ratio is not equal to 1
## 95 percent confidence interval:
## 0.7226446 39.3241559
## sample estimates:
## odds ratio
## 4.706706
El t-test es una prueba que nos permite realizar la comparación de las medias de una variable cuantitativa entre dos grupos determinados (variable categórica).
# t-test para comparar las medias de colesterol en los grupos con IAM y sin IAM
# En primer lugar podemos utilizar los siguientes comandos:
t.test(Colesterol ~ IAM, data=pacientes, var.equal=T)
##
## Two Sample t-test
##
## data: Colesterol by IAM
## t = -6.0685, df = 28, p-value = 1.522e-06
## alternative hypothesis: true difference in means between group No and group Si is not equal to 0
## 95 percent confidence interval:
## -97.53465 -48.30662
## sample estimates:
## mean in group No mean in group Si
## 199.8571 272.7778
# En segundo lugar, creando en primer lugar los subgrupos correspondientes
# mediante la función para crear subgrupos como es "subset":
iamNo <- subset(pacientes, IAM=="No", select="Colesterol") # o select=c(Colesterol)
iamSi <- subset(pacientes, IAM=="Si", select="Colesterol")
# mostramos los casos de ambos grupos
iamNo
## Colesterol
## 1 210
## 2 180
## 3 190
## 5 165
## 6 186
## 7 210
## 8 198
## 9 238
## 11 174
## 13 190
## 16 220
## 17 138
## 18 269
## 21 235
## 22 250
## 23 220
## 25 160
## 26 210
## 27 167
## 29 200
## 30 187
iamSi
## Colesterol
## 4 280
## 10 266
## 12 295
## 14 220
## 15 275
## 19 249
## 20 290
## 24 280
## 28 300
# t-test para comparar la media de colesterol de los grupos iamNo y iamSi
t.test(iamNo, iamSi, var.equal=TRUE)
##
## Two Sample t-test
##
## data: iamNo and iamSi
## t = -6.0685, df = 28, p-value = 1.522e-06
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -97.53465 -48.30662
## sample estimates:
## mean of x mean of y
## 199.8571 272.7778
# Si disponemos de los vectores (grupos de datos) creados de forma independiente se puede
# realizar t-Student con los siguientes comandos:
grupo_tratamiento <- c(98,95,103,100,98,102)
grupo_control <- c(109,112,106,110,115,99)
t.test(grupo_tratamiento,grupo_control)
##
## Welch Two Sample t-test
##
## data: grupo_tratamiento and grupo_control
## t = -3.5787, df = 7.6146, p-value = 0.007815
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -15.125858 -3.207476
## sample estimates:
## mean of x mean of y
## 99.33333 108.50000
Obtenemos un valor de p < 0.05 y por tanto podemos afirmar que existen diferencias significativas entre ambos grupos de pacientes en cuanto a la presencia de IAM y colesterol, siendo la media de 199.86 mg/dl en aquellos que NO tienen IAM y de 272,78 en los que presentan IAM.
La ANOVA nos permite comparar las medias de dos o más grupos. En este caso compararemos la respuesta de un grupo de pacientes a diversos tratamientos sobre una posible reducción de los niveles de colesterol.
# instalamos el package "multcomp" que contiene el dataset "cholesterol" con el que
# trabajaremos este ejemplo. Con el siguiente comando instalamos el package:
# install.packages('multcomp')
library(multcomp)
# llamamos al dataset con data(cholesterol), que contiene este package y lo exploramos
data(cholesterol)
dim(cholesterol)
## [1] 50 2
str(cholesterol)
## 'data.frame': 50 obs. of 2 variables:
## $ trt : Factor w/ 5 levels "1time","2times",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ response: num 3.86 10.39 5.91 3.06 7.72 ...
head(cholesterol)
## trt response
## 1 1time 3.8612
## 2 1time 10.3868
## 3 1time 5.9059
## 4 1time 3.0609
## 5 1time 7.7204
## 6 1time 2.7139
table(cholesterol$trt)
##
## 1time 2times 4times drugD drugE
## 10 10 10 10 10
# se trata diversos pacientes que reciben 5 tratamientos diferentes (variable categórica)
# y que tienen un efecto o respuesta sobre el nivel de colesterol (variable numérica)
# por lo que realizamos un ANOVA para comparar la media de reducción de los 5 tratamientos
# Realizamos ANOVA:
resultado <- aov(cholesterol$response ~ cholesterol$trt)
# vemos el resultado:
summary(resultado)
## Df Sum Sq Mean Sq F value Pr(>F)
## cholesterol$trt 4 1351.4 337.8 32.43 9.82e-13 ***
## Residuals 45 468.8 10.4
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# el resultado nos indica que hay diferencias (p<0.0001) entre los tratamientos
# además vemos la representación gráfica con el package gplots
# instalamos el package gplots:
# install.packages('gplots')
library(gplots)
plotmeans(cholesterol$response ~ cholesterol$trt,
main="Medias de colesterol",
xlab="Tratamiento",
ylab="Respuesta")
Si estamos interesados en conocer las diferencias entre las distintas medias y por tanto cuáles son las diferencias entre los 5 tratamientos analizados debemos aplicar la prueba de Tukey:
# Mediante la siguiente instrucción aplicamos el método de Tukey.
TukeyHSD(resultado)
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = cholesterol$response ~ cholesterol$trt)
##
## $`cholesterol$trt`
## diff lwr upr p adj
## 2times-1time 3.44300 -0.6582817 7.544282 0.1380949
## 4times-1time 6.59281 2.4915283 10.694092 0.0003542
## drugD-1time 9.57920 5.4779183 13.680482 0.0000003
## drugE-1time 15.16555 11.0642683 19.266832 0.0000000
## 4times-2times 3.14981 -0.9514717 7.251092 0.2050382
## drugD-2times 6.13620 2.0349183 10.237482 0.0009611
## drugE-2times 11.72255 7.6212683 15.823832 0.0000000
## drugD-4times 2.98639 -1.1148917 7.087672 0.2512446
## drugE-4times 8.57274 4.4714583 12.674022 0.0000037
## drugE-drugD 5.58635 1.4850683 9.687632 0.0030633
par(las=2)
par(mar=c(5,8,4,2))
plot(TukeyHSD(resultado))
# Test de Kruskal-Wallis, kruskal.test(), para no paramétricos
Como podemos observar las comparaciones 2times-1time, 4times-2times y drugD-4times son las que no muestran diferencias significativas (la distribución del 95% llega a incluir el valor 0, señalada como una línea discontinua).
Para determinar si existe relación entre dos variables cuantitativas debemos utilizar la Correlación y la Regresión simple, la cual nos permite además predecir los valores que tomará la variable dependiente, en función de la variable independiente mediante un modelo matemático de regresión (ecuación lineal). En el caso de la regresión simple, tratamos de explicar la relación que existe entre una variable respuesta (y) y una única variable explicativa o independiente (x).
En este caso podemos realizar un estudio que permita comparar todas las variables cuantitativas (edad, glucemia y colesterol) y en primer lugar realizamos una representación gráfica de dichas variables.
# Creamos un subset con las variables cuantitativas utilizando la función subset()
edad_glu_col <- subset(pacientes,
select=c(Edad, Glucemia, Colesterol))
edad_glu_col <- subset(pacientes,
select=c("Edad", "Glucemia", "Colesterol"))
# Mostramos los primeros casos del data.frame
head(edad_glu_col)
## Edad Glucemia Colesterol
## 1 56 116 210
## 2 49 105 180
## 3 66 134 190
## 4 78 140 280
## 5 50 90 165
## 6 53 95 186
# Estudiamos las relaciones entre variables gráficamente
pairs(edad_glu_col)
### Realizamos las diversas Regresiones:
# entre glucemia (variable dependiente) y edad (independiente)
regre <- lm(Glucemia ~ Edad, data=edad_glu_col)
summary(regre)
##
## Call:
## lm(formula = Glucemia ~ Edad, data = edad_glu_col)
##
## Residuals:
## Min 1Q Median 3Q Max
## -36.034 -12.486 -2.260 8.675 49.622
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 59.6470 17.5019 3.408 0.00200 **
## Edad 0.9785 0.2798 3.497 0.00159 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 20.47 on 28 degrees of freedom
## Multiple R-squared: 0.3039, Adjusted R-squared: 0.2791
## F-statistic: 12.23 on 1 and 28 DF, p-value: 0.00159
# entre colesterol y edad
regre2 <- lm(Colesterol ~ Edad, data=edad_glu_col)
summary(regre2)
##
## Call:
## lm(formula = Colesterol ~ Edad, data = edad_glu_col)
##
## Residuals:
## Min 1Q Median 3Q Max
## -51.341 -18.259 2.332 15.614 88.350
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 70.6506 26.1919 2.697 0.0117 *
## Edad 2.4727 0.4188 5.904 2.37e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 30.63 on 28 degrees of freedom
## Multiple R-squared: 0.5546, Adjusted R-squared: 0.5387
## F-statistic: 34.86 on 1 and 28 DF, p-value: 2.367e-06
# cuantificamos la correlación (cor) con el coeficiente de Pearson en todos los casos
cor(edad_glu_col)
## Edad Glucemia Colesterol
## Edad 1.0000000 0.5513062 0.7447024
## Glucemia 0.5513062 1.0000000 0.3730618
## Colesterol 0.7447024 0.3730618 1.0000000
# ¿Qué ocurre si consideramos un regresión múltiple incluyendo todos los factores para conocer
# el efecto de la edad y el colesterol sobre la glucemia?
regre3 <- lm(Glucemia ~ Colesterol, data=edad_glu_col)
regre.all <- lm(Glucemia ~ Colesterol + Edad, data=edad_glu_col)
summary(regre3)
##
## Call:
## lm(formula = Glucemia ~ Colesterol, data = edad_glu_col)
##
## Residuals:
## Min 1Q Median 3Q Max
## -38.041 -17.860 -4.602 16.035 42.129
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 75.21642 21.19330 3.549 0.00139 **
## Colesterol 0.19941 0.09372 2.128 0.04231 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 22.76 on 28 degrees of freedom
## Multiple R-squared: 0.1392, Adjusted R-squared: 0.1084
## F-statistic: 4.527 on 1 and 28 DF, p-value: 0.04231
summary(regre.all)
##
## Call:
## lm(formula = Glucemia ~ Colesterol + Edad, data = edad_glu_col)
##
## Residuals:
## Min 1Q Median 3Q Max
## -34.059 -12.471 -3.131 7.477 51.082
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 62.8263 19.9598 3.148 0.00399 **
## Colesterol -0.0450 0.1283 -0.351 0.72852
## Edad 1.0898 0.4260 2.558 0.01646 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 20.79 on 27 degrees of freedom
## Multiple R-squared: 0.3071, Adjusted R-squared: 0.2558
## F-statistic: 5.983 on 2 and 27 DF, p-value: 0.007065
En este caso observamos que realmente el efecto del Colesterol sobre la Glucemia desaparece y que en realidad el incremento de la Glucemia tiene relación (lineal) con la edad y no con el incremento de Colesterol.
# podemos utilizar el package sjPlot y relacionados, para representar los
# resultados en un formato similar a SPSS, a continuación vemos un ejemplo con la regresión
# podemos instalar todos los sj* con: devtools::install_github("strengejacke/strengejacke")
library(sjPlot)
## Install package "strengejacke" from GitHub (`devtools::install_github("strengejacke/strengejacke")`) to load all sj-packages at once!
# con la función tab_model() podemos representar la regresión
tab_model(regre)
Glucemia | |||
---|---|---|---|
Predictors | Estimates | CI | p |
(Intercept) | 59.65 | 23.80 – 95.50 | 0.002 |
Edad | 0.98 | 0.41 – 1.55 | 0.002 |
Observations | 30 | ||
R2 / R2 adjusted | 0.304 / 0.279 |
### Correlación y Regresión simple entre edad y glucemia y colesterol.
# siendo la Edad la variable independiente
# Correlación mediante: cor(x,y) y sus significaiones con cor.test(x,y):
cor(pacientes$Edad, pacientes$Glucemia)
## [1] 0.5513062
cor.test(pacientes$Edad,pacientes$Glucemia) # Edad y Glucemia
##
## Pearson's product-moment correlation
##
## data: pacientes$Edad and pacientes$Glucemia
## t = 3.4966, df = 28, p-value = 0.00159
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.2383847 0.7605217
## sample estimates:
## cor
## 0.5513062
cor.test(pacientes$Edad,pacientes$Colesterol) # Edad y Colesterol
##
## Pearson's product-moment correlation
##
## data: pacientes$Edad and pacientes$Colesterol
## t = 5.9044, df = 28, p-value = 2.367e-06
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.5253925 0.8712272
## sample estimates:
## cor
## 0.7447024
cor.test(pacientes$Glucemia,pacientes$Colesterol) # Glucemia y Colesterol
##
## Pearson's product-moment correlation
##
## data: pacientes$Glucemia and pacientes$Colesterol
## t = 2.1277, df = 28, p-value = 0.04231
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.01477888 0.64644682
## sample estimates:
## cor
## 0.3730618
# Regresión lineal (ecuación relación lineal)
fit <- lm(pacientes$Glucemia ~ pacientes$Edad) # lm(y~x)
summary(fit)
##
## Call:
## lm(formula = pacientes$Glucemia ~ pacientes$Edad)
##
## Residuals:
## Min 1Q Median 3Q Max
## -36.034 -12.486 -2.260 8.675 49.622
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 59.6470 17.5019 3.408 0.00200 **
## pacientes$Edad 0.9785 0.2798 3.497 0.00159 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 20.47 on 28 degrees of freedom
## Multiple R-squared: 0.3039, Adjusted R-squared: 0.2791
## F-statistic: 12.23 on 1 and 28 DF, p-value: 0.00159
# Nos indica que con una p < 0.05 la edad influye en los valores de
# glucemia y la recta de regresión es: glucemia = 59.65 + 0.98*edad
# A mayor edad, valores de glucemia más altos
El valor del coeficiente de determinación o “R-squared”, nos permite conocer la bondad de ajuste del modelo de regresión y explica el tanto por ciento de variación de y (variable dependiente) en función de x (variable independiente). En este caso el valor de 0.304 nos indica que esta variación explicativa está en torno al 30.4%, por lo que explica muy parcialmente dicha variación.
##### Gráficos de ambas variables utilizando plot()
plot(pacientes$Glucemia ~ pacientes$Edad)
abline(fit)
fit2 <- lm(pacientes$Colesterol ~ pacientes$Edad) # lm(y~x)
summary(fit2)
##
## Call:
## lm(formula = pacientes$Colesterol ~ pacientes$Edad)
##
## Residuals:
## Min 1Q Median 3Q Max
## -51.341 -18.259 2.332 15.614 88.350
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 70.6506 26.1919 2.697 0.0117 *
## pacientes$Edad 2.4727 0.4188 5.904 2.37e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 30.63 on 28 degrees of freedom
## Multiple R-squared: 0.5546, Adjusted R-squared: 0.5387
## F-statistic: 34.86 on 1 and 28 DF, p-value: 2.367e-06
plot(pacientes$Colesterol ~ pacientes$Edad)
abline(fit2)
La regresión logística es una prueba estadística multivariante que nos permite estimar la relación entre una variable dependiente cualitativa dicotómica y un conjunto de variables independientes que pueden ser cualitativas y/o cuantitativas. La regresión logística nos permite además calcular la razón de probabilidad u Odds Ratio (OR) de un evento.
Siguiendo con los datos de pacientes elaboramos un modelo de regresión logística para estudiar la posible relación de diversas variables como la edad, el nivel de colesterol, ser diabético o el género, sobre su posible relación con la presencia de infarto de miocardio o no en estos pacientes.
head(pacientes)
## Edad Genero Diabetes Glucemia Colesterol IAM Trat
## 1 56 H No 116 210 No Si
## 2 49 M No 105 180 No Si
## 3 66 H Si 134 190 No No
## 4 78 H Si 140 280 Si Si
## 5 50 M No 90 165 No No
## 6 53 M No 95 186 No No
str(pacientes)
## 'data.frame': 30 obs. of 7 variables:
## $ Edad : int 56 49 66 78 50 53 64 62 71 75 ...
## $ Genero : chr "H" "M" "H" "H" ...
## $ Diabetes : chr "No" "No" "Si" "Si" ...
## $ Glucemia : int 116 105 134 140 90 95 114 105 150 145 ...
## $ Colesterol: int 210 180 190 280 165 186 210 198 238 266 ...
## $ IAM : chr "No" "No" "No" "Si" ...
## $ Trat : chr "Si" "Si" "No" "Si" ...
pacientes$IAM[pacientes$IAM == "No"] <- 0
pacientes$IAM[pacientes$IAM == "Si"] <- 1
pacientes$IAM <- factor(pacientes$IAM,
levels=c(0,1),
labels=c("No", "Si"))
pacientes$Trat <- as.factor(pacientes$Trat)
pacientes$Genero <- as.factor(pacientes$Genero)
pacientes$Diabetes <- as.factor(pacientes$Diabetes)
model <- glm(IAM ~ Colesterol + Edad + Genero + Diabetes, family=binomial(), data=pacientes)
model2 <- glm(IAM ~ Colesterol, family=binomial(), data=pacientes)
# Los datos del modelo se visualizan con el comando:
summary(model)
##
## Call:
## glm(formula = IAM ~ Colesterol + Edad + Genero + Diabetes, family = binomial(),
## data = pacientes)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -26.87770 12.90856 -2.082 0.0373 *
## Colesterol 0.09342 0.04291 2.177 0.0295 *
## Edad 0.01348 0.09428 0.143 0.8863
## GeneroM 1.98329 3.23865 0.612 0.5403
## DiabetesSi 3.09118 2.53252 1.221 0.2222
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 36.652 on 29 degrees of freedom
## Residual deviance: 11.269 on 25 degrees of freedom
## AIC: 21.269
##
## Number of Fisher Scoring iterations: 8
summary(model2)
##
## Call:
## glm(formula = IAM ~ Colesterol, family = binomial(), data = pacientes)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -18.49669 6.63676 -2.787 0.00532 **
## Colesterol 0.07362 0.02657 2.770 0.00560 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 36.652 on 29 degrees of freedom
## Residual deviance: 14.364 on 28 degrees of freedom
## AIC: 18.364
##
## Number of Fisher Scoring iterations: 6
exp(cbind(OR=coef(model), confint(model)))
## Waiting for profiling to be done...
## OR 2.5 % 97.5 %
## (Intercept) 2.124037e-12 1.677862e-30 2.546706e-05
## Colesterol 1.097922e+00 1.034500e+00 1.247954e+00
## Edad 1.013572e+00 8.332381e-01 1.256869e+00
## GeneroM 7.266638e+00 2.583686e-02 1.889066e+05
## DiabetesSi 2.200308e+01 3.045687e-01 2.002333e+04
Observamos que únicamente el colesterol muestra un valor de una p significativa y por tanto podemos afirmar que existe alguna relación entre los niveles de colesterol y la aparición de IAM.
En Internet disponemos de un gran número de recursos sobre R. Además ChatGPT y otros Large Language Models (LLM) pueden ser de gran utilidad para generar y revisar comandos de R.
E. Paradis. R para principiantes: https://cran.r-project.org/doc/contrib/rdebuts_es.pdf
R Development Core Team. Introducción a R: https://cran.r-project.org/doc/contrib/R-intro-1.1.0-espanol.1.pdf
Chi Yau. Elementary statistics with R: http://www.r-tutor.com/elementary-statistics
WN Venables, DM Smith and the R Core Team. An introduccion to R: https://cran.r-project.org/doc/manuals/R-intro.pdf