Introducción

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.

Más información sobre M.A.Mayer en Wikipedia.

Sección 1. Generalidades del Programa R y Rstudio

Programa Estadístico 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.

Instalación de R

En primer lugar, debemos instalar el programa estadístico R. Para ello debemos acceder a la web:

https://www.r-project.org/

Instalación de RStudio

Una vez instalado R, debemos proceder a la instalación de RStudio. Para ello accedemos a la web:

https://www.rstudio.com/products/rstudio/download/

RStudio

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.

Figura 1. Aspecto que ofrece RStudio.
Figura 1. Aspecto que ofrece 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.

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.

Directorio de trabajo de 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:

Figura 2. Seleccionar el Directorio de Trabajo.
Figura 2. Seleccionar el Directorio de Trabajo.

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")

Sección 2. Conceptos generales sobre estadística y tipos de datos en R

Tipos de Variables

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.

Los DATOS en R

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:

  • Vectores: conjunto de elementos, como por ejemplo los valores numéricos de los niveles de glucemia. Un vector debe contener datos de igual modo, así todos los valores de glucemia son numéricos. Los vectores son el tipo de dato más utilizado en R. Para crear un vector utilizamos el formato siguiente con la función “c” y el signo de asignación “<-” de la siguiente forma:
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.

Medidas de tendencia central

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

Medidas de dispersión

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

Sección 3. Seguimos avanzando con R y RStudio

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

Comandos para el acceso a diferentes datos y variables

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

Manejo de variables y nuevos casos

a) Renombrar variables

# 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"))

b) Añadir o eliminar variables

# 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')

c) Variables calculadas

# 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

d) Añadir nuevos casos o eliminar casos

# 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

Importación y exportación de datos

a) Importar datos de un archivo en formato txt como pacientes.txt.

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" ...

b) Importar datos de un archivo en Excel.

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')

c) Importar los datos de un archivo de SPSS.

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")

d) Importar los datos de un archivo en formato csv.

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')

e) Exportar los datos de un data.frame a un archivo en formato 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=“;”.

Sección 4. Estructura de datos

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

Comandos de interés para explorar variables numéricas

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)

Sección 5. Representación gráfica

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.

Variables cualitativas

a) Diagrama de barras

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

b) Diagrama de sectores

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

Variables cuantitativas

Para la representación de variables cuantitativas disponemos de diversas opciones gráficas.

a) Histograma

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

b) Boxplot

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

Sección 6. Estadística descriptiva

Tabla de datos de variables cualitativas y cuantitativos

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")

Sección 7. Pruebas estadísticas

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:

Figura 3. Pruebas estadísticas para identificar la relación entre dos variables.
Figura 3. Pruebas estadísticas para identificar la relación entre dos variables.

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 ñ.

Distribución normal

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)

Distribución t de Student

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).

Chi cuadrado y Fisher test

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

t-Test o t de Student

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.

ANOVA

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")

Prueba de Tukey

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).

Correlación y Regresión simple

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)

Regresión logística (multivariante)

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.

Bibliografía complementaria

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