Capítulo 1 Introduccion a R

  • La programación de rutinas en software específico para la manipulación y análisis de bases de datos permite asegurar procesos homogéneos, documentados, fácilmente auditables, modificables y que pueden ser compartidos entre diferentes usuarios. Además, resulta sumamente útil para realizar tareas repetitivas generando ganancias de eficiencia.

  • Es muy importante realizar anotaciones, tanto para compartir código con otro usuario como para uno mismo en el futuro (por ejemplo, cuáles son los insumos/output, los ¿por qué?). La combinación de teclas Ctrl/Cmd + Shift + R permite crear secciones en scripts que luego sirven para navegar y ser ordenados.

A la gloria no se llega por un camino de rosas. Trabajar, trabajar y trabajar.

Osvaldo Zubeldia

1.1 Primeros pasos

R es un lenguaje orientado a objetos (vectores, listas, matrices). Si bien al principio puede parecer demasiado complejo, no es así. De hecho, una característica destacada de R es su flexibilidad.

Mientras que un software clásico muestra inmediatamente los resultados de un comando, R los almacena en un objeto, por lo que se puede realizar un análisis sin el resultado desplegado.

R (el motor) puede complementarse con RStudio (tablero de instrumentos) que es una IDE (integrated development environment) para operar de manera mas amigable (editor con sintaxis y distintos espacios de trabajo). Cada uno se encuentra disponible en:4

  1. R
  2. RStudio

Una vez instalados los programas se deben descargar “paquetes” que agregan funcionalidades al paquete que viene incorporado (base).

#Descarga de programa
install.packages('tidyverse')

#Carga de programa antes de utilizarlo en un script
library(tidyverse)

Eventualmente se puede utilizar una función específica de un paquete previamente instalado sin cargar el paquete completo. Por ejemplo, si se quiere utilizar la función read_excel() del paquete readxl.

readxl::read_excel()

1.2 Busacar ayuda

# Por comando
?rm # Para poder ver la ayuda el paquete debe estar instalado
help(lm)
  • Buscar el tab Help en la ventana de abajo a la derecha de RStudio

  • Google

1.3 Tipos de datos

  • character/string

  • numeric (integer, double)

  • factor (variables categóricas, importante para clasificación)

  • logical

  • date

1.4 Limpieza de memoria

rm(list = ls()) # Elimina todos los objetos en memoria
gc() # Garbage Collection

1.5 Asignación de valores

# nombre_objeto <- valor
x <- 1
x = 5
x
## [1] 5
y = x
y = 4

1.6 Operadores aritméticos

y + x
## [1] 9
y - x
## [1] -1
y * x
## [1] 20
4 / 8
## [1] 0.5
8 %% 4
## [1] 0
2**5
## [1] 32
2^5
## [1] 32
sqrt(9)
## [1] 3
log(1)
## [1] 0

1.7 Operadores relacionales

# < <= > >= == !=
x == 1
## [1] FALSE
x == y
## [1] FALSE
y < x
## [1] TRUE

1.8 Operadores lógicos

Nota: Se puede usar || (o) y && (y) para combinar múltiples expresiones lógicas. Estos operadores se llaman “cortocircuito”: tan pronto como || ve el primer VERDADERO devuelve VERDADERO sin calcular nada más. Tan pronto como && ve el primer FALSO, devuelve FALSO.

# ! & | && ||
TRUE
## [1] TRUE
!FALSE
## [1] TRUE
!F
## [1] TRUE
F & T
## [1] FALSE
F | T
## [1] TRUE
x == 1 & y==4
## [1] FALSE
x == 1 | y==4
## [1] TRUE
!(x > y); x <= y
## [1] FALSE
## [1] FALSE

1.9 Vectores

Una característica distintiva de los vectores es que son atómicos / homogéneos.

a = c(0,2,5,3,8) 
typeof(a) 
## [1] "double"
class(a)
## [1] "numeric"
b = c("a","b","c","d","e")
typeof(b)
## [1] "character"
class(b)
## [1] "character"
f = c(F,T,F,T,T)
typeof(f)
## [1] "logical"
c(a,b)   # coerción (transforma todo en character)
##  [1] "0" "2" "5" "3" "8" "a" "b" "c" "d" "e"
typeof(c(a,b))  
## [1] "character"
c(NA,5,2,3,4)   
## [1] NA  5  2  3  4
c(NULL,5,2,3,4) 
## [1] 5 2 3 4
length(a) 
## [1] 5
names(a)  
## NULL
names(a) = b
a
## a b c d e 
## 0 2 5 3 8
## Subsetting / extraer 

# por posicion
a[3] 
## c 
## 5
a[3:5]
## c d e 
## 5 3 8
a[c(1,5)]
## a e 
## 0 8
a[-1]
## b c d e 
## 2 5 3 8
# por nombre
a[c('a','e')]
## a e 
## 0 8
# con booleanos
a[a >= 4]
## c e 
## 5 8
a[!(a >= 4)]
## a b d 
## 0 2 3
a[a > 2 & a < 7]
## c d 
## 5 3
a[a==0 | a==5]
## a c 
## 0 5
a[a %in% c(0, 5)]
## a c 
## 0 5
# muestra las posiciones que cumplen
# con la condición (no los valores)
which(a < 4) 
## a b d 
## 1 2 4

1.10 Secuencias

# Utilizar una funcion
# nombre_funcion(arg1 = val1, arg2 = val2, ...)
# Los argumentos se pueden nombrar,
# utilizar forma implícita o dejarlo definido por default
d = c(1,1,2,3,4,4,5,6,8,9,7,7,0)
unique(d)
##  [1] 1 2 3 4 5 6 8 9 7 0
rep(5, 10) 
##  [1] 5 5 5 5 5 5 5 5 5 5
seq(1, 20) 
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
seq(1, 20, by = 0.7)
##  [1]  1.0  1.7  2.4  3.1  3.8  4.5  5.2  5.9  6.6  7.3  8.0  8.7  9.4 10.1 10.8
## [16] 11.5 12.2 12.9 13.6 14.3 15.0 15.7 16.4 17.1 17.8 18.5 19.2 19.9
1:length(a)
## [1] 1 2 3 4 5
seq_along(a) # equivalente, pero en un caso mas seguro (ver abajo)
## [1] 1 2 3 4 5
1:20
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
set.seed(8) 
muestra = sample(1:10, 15, replace = T)
muestra
##  [1]  4  7  2  7 10  7  1  2  3  3  6  6  4  8  4
sample(letters, 10, rep = T)
##  [1] "n" "i" "i" "l" "g" "h" "s" "f" "g" "b"
# operaciones vectorizadas
a*c(1, 0, 10, 1, 5)
##  a  b  c  d  e 
##  0  0 50  3 40
a==c(0, 1, 5, 0, 0)
##     a     b     c     d     e 
##  TRUE FALSE  TRUE FALSE FALSE
1:6 + c(10, 2) # reciclaje (extiende el vector mas corto)
## [1] 11  4 13  6 15  8

1.11 Factores

# Variables categóricas con valores limitados 
# (importante para modelos de clasificación)
data = c(1,2,2,3,1,2,3,3,1,2,3,3,1)
fdata = as.factor(data)
fdata
##  [1] 1 2 2 3 1 2 3 3 1 2 3 3 1
## Levels: 1 2 3
# Niveles definidos por el usuario 
fdata2 = factor(data, labels = c('a', 'b', 'c'))
fdata2
##  [1] a b b c a b c c a b c c a
## Levels: a b c
factor_order = c('c', 'b', 'a')
fdata3 = factor(fdata2, levels = factor_order)
fdata3
##  [1] a b b c a b c c a b c c a
## Levels: c b a

1.12 Matrices

matrix(rep(3, 8))
##      [,1]
## [1,]    3
## [2,]    3
## [3,]    3
## [4,]    3
## [5,]    3
## [6,]    3
## [7,]    3
## [8,]    3
matrix(rep(3, 8), nrow = 4)
##      [,1] [,2]
## [1,]    3    3
## [2,]    3    3
## [3,]    3    3
## [4,]    3    3
matrix(seq(1,12), nrow = 4)
##      [,1] [,2] [,3]
## [1,]    1    5    9
## [2,]    2    6   10
## [3,]    3    7   11
## [4,]    4    8   12
matrix(1:12, nrow = 4, byrow = T)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9
## [4,]   10   11   12
matrix(a, nr = 2, nc = 4) # completa pero avisa sobre las dimensiones
##      [,1] [,2] [,3] [,4]
## [1,]    0    5    8    2
## [2,]    2    3    0    5
cbind(1:5, 5:1)
##      [,1] [,2]
## [1,]    1    5
## [2,]    2    4
## [3,]    3    3
## [4,]    4    2
## [5,]    5    1
rbind(1:10, letters[10:1])
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" 
## [2,] "j"  "i"  "h"  "g"  "f"  "e"  "d"  "c"  "b"  "a"
mat1 = matrix(muestra, nc = 5)
mat1
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    4    7    1    3    4
## [2,]    7   10    2    6    8
## [3,]    2    7    3    6    4
dim(mat1) 
## [1] 3 5
# subsetting/extraer
mat1[5]
## [1] 10
mat1[2, 3]
## [1] 2
mat1[3,]
## [1] 2 7 3 6 4
mat1[, 4]
## [1] 3 6 6
mat1[, 4, drop = F] # para no perder la dimensión de matriz
##      [,1]
## [1,]    3
## [2,]    6
## [3,]    6
mat1[c(1,3), c(1:3,5)]
##      [,1] [,2] [,3] [,4]
## [1,]    4    7    1    4
## [2,]    2    7    3    4
mat1[-2, -4]
##      [,1] [,2] [,3] [,4]
## [1,]    4    7    1    4
## [2,]    2    7    3    4
mat2 = matrix(sample(1:10, 4, replace = T), nc = 2)
mat3 = matrix(sample(1:10, 4, replace = T), nc = 2)
mat4 = mat2 * mat3   # elemento a elemento
mat5 = mat2 %*% mat3 # multiplicación de matrices

mat2
##      [,1] [,2]
## [1,]    5   10
## [2,]   10    6
mat3
##      [,1] [,2]
## [1,]    9    8
## [2,]   10    5
mat4
##      [,1] [,2]
## [1,]   45   80
## [2,]  100   30
mat5
##      [,1] [,2]
## [1,]  145   90
## [2,]  150  110

1.13 Listas

Una característica distintiva de las listas es que son recursivas y heterogéneas.

# Las listas pueden contener elementos de distinto tipo
ms <- list('a', 1L, 1.5, TRUE)
str(ms)
## List of 4
##  $ : chr "a"
##  $ : int 1
##  $ : num 1.5
##  $ : logi TRUE
lista1 <- list(mat1, a, b)
str(lista1)
## List of 3
##  $ : int [1:3, 1:5] 4 7 2 7 10 7 1 2 3 3 ...
##  $ : Named num [1:5] 0 2 5 3 8
##   ..- attr(*, "names")= chr [1:5] "a" "b" "c" "d" ...
##  $ : chr [1:5] "a" "b" "c" "d" ...
names(lista1) = c('a', 'b', 'c')

# subsetting/extraer
lista1$a
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    4    7    1    3    4
## [2,]    7   10    2    6    8
## [3,]    2    7    3    6    4
lista1[[1]]
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    4    7    1    3    4
## [2,]    7   10    2    6    8
## [3,]    2    7    3    6    4
lista1[[1]][1, 1]
## [1] 4
lista1['a']
## $a
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    4    7    1    3    4
## [2,]    7   10    2    6    8
## [3,]    2    7    3    6    4
lista1$c[5]
## [1] "e"

1.14 Data frames

df1 = data.frame(mat1)
names(df1) = c('var1', 'var2', 'var3', 'var4', 'var5')
df2 = data.frame(
  v1 = 1:10,
  v2 = 10:1,
  v3 = sample(1:10, rep = T),
  v4 = 0,
  v5 = sample(letters, 10, rep = T),
  stringsAsFactors = F)
str(df2)
## 'data.frame':    10 obs. of  5 variables:
##  $ v1: int  1 2 3 4 5 6 7 8 9 10
##  $ v2: int  10 9 8 7 6 5 4 3 2 1
##  $ v3: int  5 3 6 5 9 10 9 10 3 7
##  $ v4: num  0 0 0 0 0 0 0 0 0 0
##  $ v5: chr  "h" "n" "m" "e" ...
dim(df2)
## [1] 10  5
length(df2)
## [1] 5
# subsetting/extraer
df2[, 4]
##  [1] 0 0 0 0 0 0 0 0 0 0
df2[, 'v4']
##  [1] 0 0 0 0 0 0 0 0 0 0
df2$v4
##  [1] 0 0 0 0 0 0 0 0 0 0
df2['v4']
##    v4
## 1   0
## 2   0
## 3   0
## 4   0
## 5   0
## 6   0
## 7   0
## 8   0
## 9   0
## 10  0
df2$v5[1:5]
## [1] "h" "n" "m" "e" "t"
df2[3:8, c(1,5)]
##   v1 v5
## 3  3  m
## 4  4  e
## 5  5  t
## 6  6  o
## 7  7  y
## 8  8  q
# con booleanos:
df2[df2$v5 == "m",]
##   v1 v2 v3 v4 v5
## 3  3  8  6  0  m
df2[df2$v2 >= 4, 'v5']
## [1] "h" "n" "m" "e" "t" "o" "y"
df2[df2$v2 %in% c(3,5), 'v5']
## [1] "o" "q"
head(df2,5)
##   v1 v2 v3 v4 v5
## 1  1 10  5  0  h
## 2  2  9  3  0  n
## 3  3  8  6  0  m
## 4  4  7  5  0  e
## 5  5  6  9  0  t
tail(df2)
##    v1 v2 v3 v4 v5
## 5   5  6  9  0  t
## 6   6  5 10  0  o
## 7   7  4  9  0  y
## 8   8  3 10  0  q
## 9   9  2  3  0  f
## 10 10  1  7  0  h
# View(df2[c("v4","v1")])

1.15 R base

Se muestran algunas funciones básicas con R base para que puedan conocerlas aunque mas adelante utilizaremos tityverse para la manipulación y transformación de datos.

# crear una variable
df2$v6 = sample(1:10, 10, rep = T)
# rename
names(df2)[names(df2) == "v6"] = "v7"
names(df2)
## [1] "v1" "v2" "v3" "v4" "v5" "v7"
# delete
df2$v7 = NULL
names(df2)
## [1] "v1" "v2" "v3" "v4" "v5"
# Ver todos los objetos de "Enviroment":    
ls()
##  [1] "a"            "b"            "d"            "data"         "df1"         
##  [6] "df2"          "f"            "factor_order" "fdata"        "fdata2"      
## [11] "fdata3"       "hook_output"  "lista1"       "mat1"         "mat2"        
## [16] "mat3"         "mat4"         "mat5"         "ms"           "muestra"     
## [21] "x"            "y"

1.16 apply, lapply y tapply

# MARGIN 1 = FILAS
# MARGIN 2 = COLUMNAS
apply(df1, MARGIN = 1 ,sum)
## [1] 19 33 22
lista = list(1:5, 20, 12:9)
lapply(lista,mean)
## [[1]]
## [1] 3
## 
## [[2]]
## [1] 20
## 
## [[3]]
## [1] 10.5
data(iris)
str(iris)
## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
# Aplica una funcion a un vector en los subvectores que 
# define otro vector. Notar que la variable Species es factor
tapply(iris$Petal.Length, iris$Species, mean)
##     setosa versicolor  virginica 
##      1.462      4.260      5.552

1.17 Map

Toma un vector como entrada, aplica una función a cada pieza y devuelve un nuevo vector que tiene la misma longitud (y los mismos nombres) que el de entrada.

purrr::map(lista, mean)
## [[1]]
## [1] 3
## 
## [[2]]
## [1] 20
## 
## [[3]]
## [1] 10.5
# Se puede aplicar una función anónima (sin nombre) 
# Ver como definir una función (y sus componentes) más abajo 
# Una función corta se puede usar sin llaves {}
resultado = purrr::map(lista, function(x) x + 5) 
resultado
## [[1]]
## [1]  6  7  8  9 10
## 
## [[2]]
## [1] 25
## 
## [[3]]
## [1] 17 16 15 14

1.18 Loops

# for 
for (x in 1:5) {
  print(x*2)
  print("listo")
}
## [1] 2
## [1] "listo"
## [1] 4
## [1] "listo"
## [1] 6
## [1] "listo"
## [1] 8
## [1] "listo"
## [1] 10
## [1] "listo"
resultado = c()   # Inicializa vector de resultados
for (i in seq_along(a)) {
  resultado[i] = a[i] * 2
}
resultado
## [1]  0  4 10  6 16
a * 2
##  a  b  c  d  e 
##  0  4 10  6 16
# seq_along vs. length(). En un vector vacío el primero 
# hace el proceso correcto (con integer(0) se interrumpe)
# Útil para un entorno de programación
conj1 = 1:10; conj2 = 20:30
x = intersect(conj1, conj2)
seq_along(x)
## integer(0)
3:seq_along(x)
## Error in 3:seq_along(x): argument of length 0
3:length(x) # secuencia descendente de 3 a 0      
## [1] 3 2 1 0
# while
resultado = c()
i = 1 
while (i <= length(a)) {
  resultado[i] = a[i] * 2
  i = i + 1
}
resultado
## [1]  0  4 10  6 16

1.19 Condicionales

y = 2; f = 'auto'

if (is.numeric(y)) {
  print('es numerico!')
}
## [1] "es numerico!"
if (is.numeric(y)) print('es numerico!')
## [1] "es numerico!"
if (is.numeric(f)) {
  print('es numerico!')
} else {
  print('no es numerico!')
}
## [1] "no es numerico!"
ifelse(is.numeric(y), y+8, NA)
## [1] 10
ifelse(a>=5, a+10, 0)
##  a  b  c  d  e 
##  0  0 15  0 18
if (this) {
    # hace esto
} else if (that) {
    # hace esto otro
} else {
    # hace otra cosa
}

1.20 Funciones

# Componentes: nombre, argumentos, cuerpo y return 
# (opcional, pero generalmente se usa).
# Si el programa es para uso personal no es necesario
# validar inputs
suma = function(x, y) {
  s = x + y
  return(s)
}
res = suma(3,5)
res
## [1] 8

1.20.1 Output más de un resultado

suma2 = function(x, y) {
  s = x + y
  m = x * y
  return(list(suma = s, mult = m))
}
res = suma2(3,5)
res['suma']
## $suma
## [1] 8
res['mult']
## $mult
## [1] 15

1.20.2 Argumentos con valores default

suma3 = function(x, y = 2) {
  s = x + y
  return(s)
}
suma3(7)
## [1] 9
suma3(7, y = 0)
## [1] 7

Nota: se puede escribir una funcion (o varias) en un script y luego utilizar source('mifuncion.R') para tenerlas diponibles en el espacio de trabajo.


  1. Buscar las versiones adecuadas para el sistema operativo utilizado.↩︎