author: Javier Ballesteros date: agosto-septiembre 2015
R: www.r-project.org
RStudio: www.rstudio.com
R funciona con interfaz de línea de comandos en vez de con interfaz gráfica (GUI)
RStudio es una herramienta de libre acceso que representa un ambiente integrado de desarrollo (Integrated Development Environment o IDE), que hace más fácil:
Lo que hace más eficaz y eficiente el trabajo con R
Investigación reproducible (reproducible research): enlaza instrucciones específicas para el análisis de datos a las bases de datos, y genera informes del análisis que pueden ser reproducidos y verificados
Programación educada (literate programming): metodología que combina un lenguaje de programación (Python, R, …) con un lenguaje de documentación (Latex, Markdown, …)
Se puede utilizar Google para buscar información sobre funciones o paquetes de R. Se recomienda utilizar r: o r- como prefijo. Por ejemplo r: meta-analysis
Una función de R está compuesta por su nombre y (entre paréntesis) sus posibles argumentos separados por comas:
El nombre de la función es t.test, y sus opciones o argumentos implican una fórmula y ~ x, un test para grupos independientes paired = FALSE, que asume varianzas iguales var.equal = TRUE, y que las variables y y x cuya asociación se quiere estudiar se encuentran en data = mis.datos
Hay 2 tipos de argumentos:
La ayuda de una función proporciona diversas informaciones - algunas más crípticas que otras. Por ejemplo, la función t.test puede ser utilizada para:
R trabaja en un directorio por defecto o especificado.
R puede verse como una calculadora vectorizada que utiliza las reglas comunes de precedencia de operaciones
35*12;35*12+4;35*(12+4)
[1] 420
[1] 424
[1] 560
exp(0.95)*2^10
[1] 2647.767
Ninguna de las operaciones anteriores se ha conservado en memoria. R evalúa una instrucción y devuelve un valor. Para mantener esos valores en memoria hay que asignarlos a un objeto. La asignación se realiza con un símbolo compuesto por los símbolos menor que < y guión alto -
y <- c(1:10)
y1 <- y * 10
y; y1
[1] 1 2 3 4 5 6 7 8 9 10
[1] 10 20 30 40 50 60 70 80 90 100
Hay 4 tipos principales de vectores en R
Las maneras más comunes de generar un vector son por la combinación, secuencia, o repetición de valores
y <- c(1:10)
y1 <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
y; y1
[1] 1 2 3 4 5 6 7 8 9 10
[1] 1 2 3 4 5 6 7 8 9 10
class(y); class(y1)
[1] "integer"
[1] "numeric"
y <- seq(from=1, to=10, by=1)
y
[1] 1 2 3 4 5 6 7 8 9 10
class(y)
[1] "numeric"
y <- rep(1:2, each=5)
y
[1] 1 1 1 1 1 2 2 2 2 2
class(y)
[1] "integer"
Se pueden generar de manera individual o por la aplicación de condiciones lógicas a otro vector. Presentan los valores TRUE y FALSE con los valores 1 y 0 respectivamente Las operaciones lógicas son las habituales: <, <=, >, >=, ==, !=, y con conjuntos: intersección &, unión |, y negación !
y <- 1:10; y1 <- y > 5; y; y1
[1] 1 2 3 4 5 6 7 8 9 10
[1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
class(y); class(y1)
[1] "integer"
[1] "logical"
names <- c("Juan", "Pedro", "Maria")
names
[1] "Juan" "Pedro" "Maria"
class(names)
[1] "character"
En general las operaciones con valores missing NA o NaN devuelven un valor missing
y <- c(1:9, NA)
y
[1] 1 2 3 4 5 6 7 8 9 NA
sum(y)
[1] NA
mean(y)
[1] NA
0/0
[1] NaN
Inf - Inf
[1] NaN
Las funciones que utilizan la estructura de formula para definir relaciones entre variables \(y \sim x\), toman en cuenta los valores missing, pero no funciones simples como las de estadística descriptiva u operaciones matemáticas. Siempre es aconsejable saber como es la estructura de valores perdidos en nuestros datos. La función summary() devuelve esa información. Un argumento general para no tomar en cuenta los valores perdidos es na.rm=TRUE
y <- c(1:9, NA)
is.na(y)
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
sum(is.na(y))
[1] 1
Los vectores de cadenas de carácteres se importan a R por defecto como factores, lo que no siempre es lógico o aconsejable
Dentro de la función dataframe() , o relacionadas, utilizar el argumento stringsAsFactors = FALSE para eliminar esa opción por defecto, y convertir manualmente con la función factor() los vectores de carácteres que realmente sean variables categóricas
R presenta una estructura específica de datos para variables categóricas que son los factores, cuyos valores están incluidos entre “”, y que se generan con la función factor(). La función factor() ordena los niveles del factor alfabéticamente
sex <- c("F", "F", "F", "F", "M", "M")
sex.factor <- factor(sex, labels=c("Female", "Male"))
class(sex); class(sex.factor)
[1] "character"
[1] "factor"
summary(sex)
Length Class Mode
6 character character
summary(sex.factor)
Female Male
4 2
La función levels() (o argumento dentro de la función factor()), permite cambiar el orden (alfabético) en el que se recogen los valores del factor
sex <- c("F", "F", "F", "F", "M", "M")
sex.factor <- factor(sex, levels=c("M", "F"), labels=c("Male", "Female"))
summary(sex.factor)
Male Female
2 4
La función relevel() permiten cambiar el orden (alfabético) en el que se recogen los valores del factor
sex <- c("F", "F", "F", "F", "M", "M")
sex.factor <- factor(sex, labels=c("Female", "Male"))
sex.factor <- relevel(sex.factor, ref="Female")
summary(sex.factor)
Female Male
4 2
Un factor que presente categorías ordenadas se obtiene en R con el argumento ordered
vector.ordered <- c("high", "high", "low", "low", "medium")
factor.ordered <- factor(vector.ordered, order=TRUE, levels=c("low", "medium", "high"), labels=c("Bajo", "Medio", "Alto"))
summary(factor.ordered)
Bajo Medio Alto
2 1 2
Los niveles de los factores se representan internamente por números enteros positivos (1, 2,…). La función as.numeric() cambia del modo factor al modo numérico las categorías de un factor. La función as.factor() cambia una variable numérica que representa niveles de categorías a una variable de tipo factor sin necesidad de definirla previamente como factor. Este cambio de factor a numérico es importante en el análisis de tendencias lineales o relaciones dosis-efecto en modelos lineales anidados
Se realiza con la expresión vector[i] donde i es la posición del elemento que se quieren indexar
x <- 1:10
x
[1] 1 2 3 4 5 6 7 8 9 10
x[5]; x[8]
[1] 5
[1] 8
Se realiza con la expresión vector[i] donde i contiene ahora múltiples elementos
x <- 1:10
x[c(1, 3, 5)]
[1] 1 3 5
x[1:5]
[1] 1 2 3 4 5
x <- 1:10
x1 <- x > 5; x1
[1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
x[x1]
[1] 6 7 8 9 10
Se realiza con la expresión vector[i] donde i es la posición o posiciones de los elementos que se quieren indexar
y <- rnorm(10); mean(y); y[10]
[1] 0.3233025
[1] 1.178389
y[10] <- 10; mean(y)
[1] 1.205464
Una matriz de dimensión \(r \times c\), se genera con la función matrix(), o uniendo un conjunto de vectores con la función cbind(), o un conjunto de observaciones con la función rbind(). Todos sus elementos son numéricos
La sintaxis general de la función matrix es: matrix(data, nrow, ncol, byrow=F)
A <- matrix(c(1, 3, 5, 7), nrow=2, byrow=T)
A
[,1] [,2]
[1,] 1 3
[2,] 5 7
a <- rep(1, 10)
b <- rnorm(10)
B <- cbind(a, b)
B
a b
[1,] 1 0.8372790
[2,] 1 -1.5891612
[3,] 1 0.3444779
[4,] 1 0.3005216
[5,] 1 0.9383893
[6,] 1 1.1463592
[7,] 1 -0.4164933
[8,] 1 -1.3625502
[9,] 1 0.8350266
[10,] 1 -0.8900460
C <- rbind(a[1:4], b[1:4])
C
[,1] [,2] [,3] [,4]
[1,] 1.000000 1.000000 1.0000000 1.0000000
[2,] 0.837279 -1.589161 0.3444779 0.3005216
Además de informar y servir también para indexar la matriz, el nombrar las filas y columnas es interesante en el análisis secundario de datos publicados:
tabla <- matrix(c(10, 30, 5, 28), nrow=2) # tabla 2x2
rownames(tabla) <- c("Resp +", "Resp -")
colnames(tabla) <- c("Exp", "Ctrl")
tabla
Exp Ctrl
Resp + 10 5
Resp - 30 28
Al igual que con vectores con el operador [, sólo que al ser las matrices bidimensionales se necesitan 2 índices, uno para las filas y otro para las columnas m[i, j]
A <- matrix(c(1:10), nrow=2)
A
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
A[2, 3] # 1 elemento específico
[1] 6
A[, c(1,3)] # todas las filas, algunas columnas
[,1] [,2]
[1,] 1 5
[2,] 2 6
A[1,] # primera fila, todas las columnas
[1] 1 3 5 7 9
A <- matrix(1:6, nrow=3)
A
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
ind <- c(TRUE, FALSE, TRUE, FALSE,TRUE, FALSE)
A[ind]
[1] 1 3 5
Además de las propias de algebra matricial, las operaciones matemáticas simples de una matriz y un escalar, y entre matrices, siguen - como en el caso de los vectores - una estructura de operaciones individuales:
A <- matrix(c(1:12), nrow=3)
A
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
A*5
[,1] [,2] [,3] [,4]
[1,] 5 20 35 50
[2,] 10 25 40 55
[3,] 15 30 45 60
A/10
[,1] [,2] [,3] [,4]
[1,] 0.1 0.4 0.7 1.0
[2,] 0.2 0.5 0.8 1.1
[3,] 0.3 0.6 0.9 1.2
B <- matrix(c(1:12), nrow=3)
B
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
A + B
[,1] [,2] [,3] [,4]
[1,] 2 8 14 20
[2,] 4 10 16 22
[3,] 6 12 18 24
Una lista en R es un objeto que contiene una colección ordenada de objetos que -normalmente- tienen diversas estructuras (vectores, matrices,…), y longitudes
Para este curso el principal interés de una lista es que de esa manera se recogen y presentan los resultados de distintos modelos y funciones en R, y es también una forma de devolver resultados a partir de funciones programadas
La manera más simple de generar una lista es usar la función list() para combinar objetos
mi.lista <- list(curso="Intro R", sitio="ULH", semanas=2, requerido=T)
mi.lista
$curso
[1] "Intro R"
$sitio
[1] "ULH"
$semanas
[1] 2
$requerido
[1] TRUE
Una base de datos rectangular (filas por columnas) es una lista de clase data.frame en la que sus componentes son vectores (numéricos, carácter, o lógicos) o factores de la misma longitud. La diferencia básica entre una data frame y una matriz, es que la matriz sólo puede contener valores numéricos, restricción que no se aplica a una data frame, ya que puede contener elementos de distinto tipo
Una data frame puede ser generada con la función data.frame(), aunque normalmente es importada de otras bases de datos
Necesario para saber si los datos se ajustan a la memoria del ordenador. El cálculo aproximado del espacio RAM necesario asumiendo variables numéricas (8 bytes) es: - Número de bytes \(\small{\sim}\) número filas \(\small{\times}\) número columnas \(\small{\times}\) 8 - Kilobytes (KB) = bytes/10^3 - Megabytes (MB) = bytes/10^6 - Gigabytes (GB) = bytes/10^9
Añade vectores de columna
y <- round(rnorm(8, 25, 4))
grupo <- rep(1:2, each=4)
edad <- round(rnorm(8, 40, 5))
data <- data.frame(y, grupo, edad)
data
y grupo edad
1 28 1 30
2 24 1 45
3 30 1 44
4 24 1 41
5 22 2 42
6 31 2 43
7 24 2 42
8 28 2 44
head(data) # 6 primeros registros
y grupo edad
1 28 1 30
2 24 1 45
3 30 1 44
4 24 1 41
5 22 2 42
6 31 2 43
tail(data) # 6 últimos registros
y grupo edad
3 30 1 44
4 24 1 41
5 22 2 42
6 31 2 43
7 24 2 42
8 28 2 44
dim(data) # observaciones x variables
[1] 8 3
str(data) # estructura del objeto
'data.frame': 8 obs. of 3 variables:
$ y : num 28 24 30 24 22 31 24 28
$ grupo: int 1 1 1 1 2 2 2 2
$ edad : num 30 45 44 41 42 43 42 44
name <- c("Ana", "Pedro", "Jose", "Julia", "Maria") # variable string/cadena
age <- c(28, 30, 21, 39, 35) # variable numérica
child <- c(FALSE, TRUE, TRUE, FALSE, TRUE) # variable lógica
people <- data.frame(name, age, child, stringsAsFactors=FALSE)
people
name age child
1 Ana 28 FALSE
2 Pedro 30 TRUE
3 Jose 21 TRUE
4 Julia 39 FALSE
5 Maria 35 TRUE
str(people)
'data.frame': 5 obs. of 3 variables:
$ name : chr "Ana" "Pedro" "Jose" "Julia" ...
$ age : num 28 30 21 39 35
$ child: logi FALSE TRUE TRUE FALSE TRUE
Se realiza con la expresión dataframe[r,c] donde r indiza el número de fila ,y c indexa el número de columna. La instrucción data[1:10, 1:10] selecciona las 10 primeras filas, y las 10 primeras columnas de data. La instrucción data[1:10,] selecciona las 10 primeras filas y todas las columnas de data. La instrucción data[, 1:10] selecciona todas las filas, pero sólo las 10 primeras columnas. En todos los casos el operador [ devuelve otra data frame
people[1:2,]
name age child
1 Ana 28 FALSE
2 Pedro 30 TRUE
people[3, 2]
[1] 21
people[, c(1, 3)]
name child
1 Ana FALSE
2 Pedro TRUE
3 Jose TRUE
4 Julia FALSE
5 Maria TRUE
Los operadores [[ y $ devuelven un objeto, en este caso un vector de una data frame
people[["age"]]
[1] 28 30 21 39 35
people[[2]]
[1] 28 30 21 39 35
people$age
[1] 28 30 21 39 35
La función subset() se puede utilizar para seleccionar subconjuntos de valores de vectores, matrices y data frames, en base a condiciones lógicas
people$age
[1] 28 30 21 39 35
subset(people, age > 30)
name age child
4 Julia 39 FALSE
5 Maria 35 TRUE
El argumento subset de la función subset(), selecciona observaciones, mientras que el argumento select selecciona variables
height <- c(163, 177, 163, 162, 157)
people$height <- height
people[["height"]] <- height
people
name age child height
1 Ana 28 FALSE 163
2 Pedro 30 TRUE 177
3 Jose 21 TRUE 163
4 Julia 39 FALSE 162
5 Maria 35 TRUE 157
cbind() sólo genera data frames si uno de los argumentos lo es, en otro caso genera una matriz
weight <- c(74, 63, 68, 55, 56)
cbind(people, weight)
name age child height weight
1 Ana 28 FALSE 163 74
2 Pedro 30 TRUE 177 63
3 Jose 21 TRUE 163 68
4 Julia 39 FALSE 162 55
5 Maria 35 TRUE 157 56
rbind() sólo genera data frames si uno de los argumentos lo es, en otro caso genera una matriz. Es más compleja que cbind(), consiste en pegar 2 data frames con el mismo nombre para las variables
new.obs <- data.frame(name="Tomas", age=37, child=FALSE, height=183)
rbind(people, new.obs)
name age child height
1 Ana 28 FALSE 163
2 Pedro 30 TRUE 177
3 Jose 21 TRUE 163
4 Julia 39 FALSE 162
5 Maria 35 TRUE 157
6 Tomas 37 FALSE 183
Hay 2 posibilidades para unir bases de datos, (1) que sean independientes (por ejemplo las bases de datos de los distintos centros de un estudio multicéntrico, es decir que añadimos observaciones), o (2) que sean dependientes (por ejemplo las bases de datos de las distintas visitas realizadas en cada uno de los centros, es decir añadimos columnas). En ambos casos la función merge() resuelve la tarea
id <- 1:3; v1 <- round(rnorm(3, 25, 4)); v2 <- v1-5; v3 <- v1-10
data1 <- data.frame(id, v1, v2, v3)
id <- 4:6; v1 <- round(rnorm(3, 25, 4)); v2 <- v1-5; v3 <- v1-10
data2 <- data.frame(id, v1, v2, v3)
data <- merge(data1, data2, all.x=T, all.y=T)
data
id v1 v2 v3
1 1 27 22 17
2 2 31 26 21
3 3 33 28 23
4 4 22 17 12
5 5 26 21 16
6 6 21 16 11
id <- 1:5; v1 <- round(rnorm(5, 25, 4)); v2 <- v1-5; v3 <- v1-10
visit1 <- data.frame(id, v1)
visit2 <- data.frame(id, v2)
visit3 <- data.frame(id, v3)
data <- merge(visit1, visit2, by="id")
data1 <- merge(data, visit3, by="id")
data1
id v1 v2 v3
1 1 24 19 14
2 2 26 21 16
3 3 22 17 12
4 4 20 15 10
5 5 29 24 19
nombre <- c("Juan", "Tomas", "Virginia", "Leyre")
edad <- c(45, 35, 28, 52)
data <- data.frame(nombre, edad)
data
nombre edad
1 Juan 45
2 Tomas 35
3 Virginia 28
4 Leyre 52
data[order(data$edad),]
nombre edad
3 Virginia 28
2 Tomas 35
1 Juan 45
4 Leyre 52