R-base: algunas ideas básicas

Programación y manejo de datos con R (Slides 03)

Pedro J. Pérez

R-base (algunas ideas básicas)

Es muy importante empezar a entenderlas

Veremos conceptos/ideas como


  • asignación

  • tipos de datos

  • estructuras de datos

  • funciones

  • paquetes: instalación y ayuda


Creación de objetos (asignación)

En R, la asignación se hace, generalmente, con el símbolo: <-

Creación de objetos y asignación (<-)

  • El operador de asignación (<-) permite asignar un valor (o dato) a un objeto. Tras la asignación, este objeto queda guardado y puede ser utilizado en operaciones posteriores
  • Es mucho más fácil explicarlo apoyándose en ejemplos:
#- ¿Qué diferencias hay entre las siguientes 2 expresiones?
2 + 2
aa <- 2 + 2

#- una vez hemos creado una variable, podemos usarla para efectuar nuevos cálculos
aa + 1

#- podemos cambiar el valor de una variable
aa
aa <- 10
aa

#- ¿Qué hacen las siguientes líneas de código? 
aa <- 2 + 2
bb <- 5 + aa
cc <- 1 + aa * 2
dd <- bb

Sé que te ha resultado muy fácil, pero vuelvo a insistir:

En R, la forma genérica de una operación de asignación, o de “creación de objetos”, es: nombre_del_objeto <- valor

por ejemplo aa <- 2 + 2

  • Recuerda que para que un nombre sea sintácticamente válido en R sólo puede contener caracteres alfanuméricos (letras y números), puntos (.) y guiones bajos (_).

  • Además, hay nombres reservados (TRUE, FALSE, NA, NULL, Inf, if, else, for, in, while, function, next, break …)


Global environment (primera referencia al)

Cada vez que asignamos un nombre a un valor, R crea un nuevo objeto en el Global environment. Veámoslo:

aa <- 2 + 2
bb <- 5 + aa
cc <- 1 + aa * 2
dd <- bb

ls()              #- muestra los objetos q hay en el  Global env. 
rm(cc)            #- borra/elimina el objeto cc del Global env.
rm(list = ls())   #- borra todos los objetos del Global env.

Tipos de datos

numéricos (enteros y doubles), lógicos y textuales

Tipos de datos

  • Hay 3 tipos principales: numéricos, de texto y lógicos
  • Además, hay 4 valores especiales: NULL, NA, NaN, e infinito


  • Cada dato, valor o variable es de un tipo.
aa <- "La calle en la que vivo es"    #- texto (character)
bb <- 4L                              #- número entero
cc <- 4.3                             #- número decimal
dd <- TRUE                            #- logical

typeof(aa)
typeof(dd)


  • IMPORTANTE [ 🌟 ]: El tipo de una variable determina las operaciones que se pueden hacer con él.

Operaciones con variables numéricas

  • Operaciones aritméticas
2 + 2
5 * 6
  • Operaciones de comparación
2 < 4    # MENOR que: esta expresión chequea si 2 es MENOR que cuatro. Como es cierto, nos devuelve un TRUE

2 > 4    # MAYOR que: esta expresión chequea si 2 es MAYOR que cuatro. Como es falso, nos devuelve un FALSE

5 >= 7   # MAYOR o IGUAL que.
8 <= 8   # MENOR o IGUAL que.

5 == 4  # == IGUAL: == chequea si dos valores son iguales, como no son iguales devolverá FALSE

2 != 4   # NO IGUAL: como 2 no es igual a 4 nos devuelve TRUE
5 != 5   # NO IGUAL: como 5 es igual a 5, nos devuelve FALSE 
  • Fíjate que las expresiones de comparación al ser ejecutadas devuelven un “boolean”: el resultado de la comparación solo puede ser TRUE (si la afirmación es cierta) o FALSE.
2 = 2    #- ¿qué ocurre? ¿xq se queja R?

Operaciones con texto

  • En R hay muchas funciones para trabajar/operar sobre texto

  • Por ejemplo, la función paste() nos permite pegar o concatenar dos variables de tipo character:

aa <- "mi nombre es"
bb <- "pedro"

paste(aa, bb)

paste(aa, bb, sep = " ... ")

# Prueba tú mismo que hace la función paste0()


toupper(aa)
tolower(aa)

stringr::str_to_sentence(aa)   #- stringr es un pkg del tidyverse

nchar(bb)                      #- nchar() nos devuelve el número de caracteres de un string

substring(bb, 2, nchar(bb))    #- substring() extrae caracteres de un string  [🌶🌶]

Operaciones lógicas

  • Los 3 principales operadores lógicos son: ( & ), ( |) y ( ! ). Son los operadores lógicos AND, OR y NOT
TRUE & TRUE    #- AND: para q devuelva TRUE hace falta que TODAS las condiciones sean ciertas
TRUE & FALSE
FALSE & FALSE

TRUE | TRUE   #- OR: devuelve TRUE si ALGUNA de las condiciones es cierta
TRUE | FALSE
FALSE | FALSE

!TRUE         #- NOT: devuelve el valor contrario
!FALSE


(4 > 3) & (3 < 2)  #- AND: como solo se cumple la primera condición, nos devuelve FALSE

(1==2) | (2 >3)   #- OR: Como no se cumple ninguna de las 2 condiciones nos devuelve FALSE

!(4 > 3)          #- NOT: 4 es mayor que 3 es TRUE, pero el ! delante de esa condición la niega y pasa a FALSE

!!(4 > 3)         #- si niegas dos veces, vuelves al principio: TRUE
  • Hay más operadores lógicos, por ejemplo: xor(), all(), any(), && y || , pero es fácil que no los usemos, y si los usamos ya los veremos.

Estructuras de datos

Es muy importante!!! [ 🌟 ] pero en realidad para el curso basta con una “ligera” idea, porque trabajaremos (casi siempre) con una sola estructura de datos: los data.frame

Estructuras de datos

R sirve para hacer análisis estadísticos con datos, y los datos tienen que estar almacenados en alguna estructura. Las principales estructuras de datos en R son:

  • vectores

  • matrices

  • arrays (matrices multidimensionales)

  • listas

  • data.frames


  • Las que más utilizaremos en el curso son los data.frames, y en segundo lugar las listas.

  • Sí, pero en realidad estas 2 estructuras (data.frames y listas) son en realidad agrupaciones de vectores; es decir, la estructura básica, la más importante en R son los vectores.

  • Son los más importantes porque el resto de estructuras se construyen a partir de grupos de vectores o añadiendo alguna propiedad adicional, o atributo, a un vector.

VECTORES

No los utilizaremos mucho-mucho, pero es la estructura de datos fundamental

Vectores

  • La estructura de datos fundamental en R es el vector.

  • En R, un vector es una estructura de datos que sirve para almacenar un conjunto ordenado de valores o elementos.

  • Un vector puede contener cualquier número de elementos; sin embargo, todos los elementos deben ser del mismo tipo. Por ejemplo, un vector no puede contener simultáneamente números y texto.

¿Cómo crear un vector?

  • Con la función c()
aa <- c(3, 22, 6)
aa

is.vector(aa)
typeof(aa)


Tarea: crea un vector de tipo character con 3 elementos

aa <- c("Hola", "número", "9")

is.vector(aa)
typeof(aa)

Coerción (implícita)

  • Sabemos que un vector solo puede contener elementos de un tipo (es una estructura homogénea)

  • ¿Qué ocurre si intentamos mezclar en un vector elementos de distinto tipo? R convertirá (coercerá) los elementos para que sean del mismo tipo

aa <- c(4, 6,  "Hola")  #- intentamos poner en aa elementos numéricos y character (¿?)

is.vector(aa)
typeof(aa)       #- ¿qué ha pasado?
aa               #- ¿qué ha pasado?
  • R convertirá todos los elementos al tipo más flexible: character > double > integer > logical. Por ejemplo, si en el vector hay un valor textual, todos los valores se convertirán al tipo character.

Coerción (explícita)

  • A veces tendremos un vector de un tipo, por ejemplo numérico, pero nos gustaría convertirlo a por ejemplo character.
aa <- c(1:4)
aa
aa <- as.character(aa)
aa

Subsetting con vectores

  • En R podemos agrupar valores en vectores. Perfecto, pero habrá veces que necesitemos manipular los vectores. Por ejemplo necesitaremos acceder a determinados elementos de un vector. Este tipo de operaciones sobre los vectores se les conoce genéricamente como subsetting.

  • Para hacer subsetting se usan los corchetes: []

  • Vemos 3 tipos de subsetting

3 tipos de subsetting

1. Seleccionar por posición

aa <- c(10:1)
aa[c(1:2)]        #- primer y segundo elemento del vector

aa[c(1, 2, 9, 10)]   #- dos primeros y 2 últimos

aa[c(1, 1, 10, 10)]  #- si repites el índice se repite el elemento del vector

2. Eliminar por posición

aa <- c(10:1)
aa[-2]

aa[- c(1, 2, 9:10)]

3. Subsetting lógico

aa <- 1:10
aa[aa >= 7]
aa[aa < 4]

aa[(aa >= 9) | (aa < 2)]
aa[(aa >= 9) & (aa < 2)]

Intenta entender bien el siguiente chunk. Es importante!!

aa <- 1:10
aa <= 4
aa[aa <= 4]
aa <- aa[aa <= 4]
aa

Modificando elementos de un vector

aa <- c(1:10)
aa[4] <- 88             #- el cuarto elemento de aa tomará el valor 88
aa <- c(aa, 111, 112)   #- añadimos 2 elementos al vector aa

Los vectores se pueden concatenar

aa <- c(1:5)
bb <- c(100:105)
cc <- c(aa, bb)

Operaciones con vectores

  • Generalmente son operaciones elemento a elemento
aa <- 1:10
bb <- 1:10
aa + bb
aa * bb
  • Si quieres hacer álgebra matricial son otros operadores
aa  %*% bb



Recycling

aa <- 1:10
aa + 1

Funciones vectorizadas

  • La mayoría de funciones, y todos los operadores de R están vectorizados; es decir, si una función recibe como input un vector, se aplicará la función a cada uno de los elementos del vector.
aa <- c(4, 9, 25)
sqrt(aa)

Operaciones de comparación

aa <- 1:3
bb <- 3:1

aa == bb
aa >= bb
aa != bb
  • En las operaciones de comparación también aplica el Recycling
aa <- 1:3
bb <- 2

aa == bb
aa >= bb
aa != bb

LISTAS

No las utilizaremos demasiado, pero …

Lists

  • Esta estructura de datos, aunque en realidad se construye por agrupación de vectores, sí que se comporta de forma diferente a los vectores.

  • Las listas son una estructura de datos heterogénea: sí pueden contener elementos de distinto tipo.

  • La mejor forma de entender cómo funciona una lista es pensar que es como una cajonera. En cada cajón podemos poner objetos de diferentes tipos.


  • Vamos a crear una lista. Se hace con list()
# defino 3 vectores y una matriz
vec_numerico <- c(1:8)
vec_character <- c("Pedro", "Rebeca", "Susana")
vec_logic <- c(TRUE, FALSE, TRUE)
matriz <- matrix(1:6, nrow = 2, ncol = 3)

# creo una lista con cuatro elementos
my_list <- list(vec_numerico, vec_character, vec_logic, matriz)
my_list

más cosas sobre las listas

  • Las listas son sumamente flexibles porque un elemento de una lista puede ser otra lista.

  • Como son tan flexibles, se usan para muchas cosas, por ejemplo para almacenar los resultados de la estimación de modelos estadísticos. (por ejemplo, el resultado de estimar un modelo con lm() es una lista)

  • Un ejemplo:
my_list_2 <- list(primer_slot = c(44:47), segundo_slot = my_list)
my_list_2

Subsetting con listas

  • Con listas se usan 3 operadores: [, [[ y $

    • [ devuelve una lista

    • [[ y $ devuelven el contenido del cajón

my_list_2 <- list(primer_slot = 44:47, segundo_slot = my_list)

my_list_2[1]              #- devuelve una lista con un elemento
my_list_2[[1]]            #- devuelve el vector 44:47
my_list_2$primer_slot     #- igual que el anterior, pero por nombre

typeof(my_list_2[1])
typeof(my_list_2[[1]])

DATA FRAMES

Estaremos todo el curso trabajando con DATA FRAMES

Data frames

  • Son otra estructura de R para almacenar datos. Se utiliza para almacenar datos tabulares, tablas de datos

  • En el fondo, un data.frame es una lista. Al ser una lista puede almacenar elementos de distinto tipo (numéricos, carácter etc…).

  • PERO es una lista especial: está restringida a que sus elementos/slots son vectores con la misma longitud; de forma que, al final tenemos una tabla de datos, donde cada columna será una variable

  • Otra propiedad de los data.frames es que sus vectores (o columnas) tienen que tener un nombre: será el nombre de la variable.

Creación de data frames

  • Generalmente no crearemos data.frames sino que los importaremos de repositorios de datos, por ejemplo de Eurostat o del INE, pero hoy vamos a crear uno con la función data.frame()
aa <- c(4, 8, 6, 3)
bb <- c("Juan", "Paz", "Adrian", "Marquitos")
cc <- c(FALSE, TRUE, TRUE, FALSE)

df <- data.frame(aa, bb, cc)


  • Podemos ponerle otros nombres a las columnas, nombres que tengan sentido y que nos recuerden las variables que contienen:
df <- data.frame(Nota = aa, Nombre = bb, Aprobado = cc)

Subsetting en data frames

Generalmente, cuando tengamos que hacer subsetting en un data frame, lo haremos à la tidyverse, pero conviene al menos conocer lo básico de cómo hacer subsetting con R-base.

Varias formas de subsetting:

  • como si fuera una matriz, usando el corchete; o sea, con [.

  • como si fuera una lista. De hecho un df es una clase especial de lista. Podemos usar 3 operadores: [, [[ y $.



subsetting como si fuera matriz (con [ )

df_s <- df[,1]        #- seleccionamos la primera columna. devuelve un vector !!!
df_s <- df[,c(2,3)]   #- seleccionamos la segunda y tercera columna. devuelve un df
df_s <- df[1, ]       #- seleccionamos primera fila de todas las variables. devuelve un df. ¿xq no devuelve un vector? Preguntad si no lo sabéis
df_s <- df[c(1,4), ]  #- seleccionamos primera y cuarta fila. devuelve un df
df_s <- df[2, 3]      #- seleccionamos segunda observación de la tercera variable. Devuelve un vector.

data.frames: subsetting como si fuera una lista (con [, [[, $)

Como lista con [

  • siempre devuelve un df
df_s <- df[3]        #- devuelve un df. Good!!
df_s <- df[c(1,2)]

#- también se puede hacer por nombre
df_s <- df["Nombre"]              #- devuelve un df
df_s <- df[c("Nombre", "Nota")]   

Como lista con [[

df_s <- df[[2]]   #- Extraemos la segunda columna. Devuelve un vector (de tipo character)

Como lista con $

df_s <- df$Nombre   #- Extraemos la columna con nombre "Nombre". Devuelve un vector (de tipo character)
df_s <- df$Nota     #- Extraemos la columna con nombre "Nota". Devuelve un vector numérico

¿Y los tibbles?

  • En el curso trabajaremos mucho con tibbles: son los data.frames del tidyverse. Casi todo funciona igual, pero hay una diferencia que suele confundir:
tb <- tibble::as_tibble(df)

df[, 1]    #- con un data.frame devuelve un vector
tb[, 1]    #- con un tibble devuelve un tibble (una tabla con una columna)

tb[[1]]    #- para extraer el vector usa [[ o $
tb$Nota

FUNCIONES

Quizás lo más importante del curso sea entender bien cómo “funciona” una función

Entender qué es una función y cómo “funciona una función” es muuuuy importante!!!

  • Repito, es muy importante entender qué es y cómo usar una función. De hecho, todo lo que ocurre/pasa en R es porque has llamado a una función. Si algo ocurre en R es porque has hecho una llamada a una función, una “function call”.

To understand computations in R, two slogans are helpful:
- Everything that exists is an object.
- Everything that happens is a function call.
— John Chambers (creador de S)


  • ¿Qué es una función? Una función no es más que un trozo de código R, unas instrucciones de R, a las que les hemos puesto/asignado un nombre; entonces, cuando invoquemos ese nombre, esa función, se ejecutarán esas líneas de código y nos devolverá un resultado (!!!)

  • Como no creo que lo anterior os diga mucho, voy a usar 5 minutos para crear nuestra primera función. Vamos a R

Creamos nuestra primera función [🌶🌶🌶]

Tarea: crea una función que permita sumar 2 números


Usar funciones permite: 1) Reutilizar código y organizar los programas de manera más eficiente, 2) Facilita la depuración de errores y el mantenimiento y 3) Mejora la legibilidad del código

Pista: Las funciones en R se crean con la función llamada function(). Sí, un poco trabalenguas.

Pista: La función que vamos a crear será un objeto de R, así que le tenemos que asignar un nombre

Pista: Los argumentos de la función van dentro de los paréntesis separados por comas

Pista: El código que queramos que se ejecute cuando llamemos a la función va entre llaves

Por lo tanto, en genérico, una función en R se crea así:

nombre_de_mi_funcion <- function(primer_argumento, segundo_argumento, ...) {
  <el-codigo-q-quiero-q-se-ejecute-cuando-se-invoque-a-la-función>
}

Si lo conseguís sois genios o ya habéis visto esto en otro lenguaje

#- creamos una función llamada "my_suma()". Lo hacemos con la función de R llamada "function()"
my_suma <- function(n1 , n2){
  n1 + n2
}

#- para usar la función que hemos creado
my_suma(3 , 5)
my_suma(n1 = 3 , n2 = 5)

aa <- my_suma(30 , 50)



entiendes mejor ahora qué es una función?

  • Tras haber creado nuestra primera función, yo creo que ahora entenderás mejor que una función no es más que un trozo de instrucciones/código en R que alguien ha creado para ser usada. Solo tenemos que invocar su nombre y dar valores a sus argumentos.

seguimos con las funciones

  • Vamos a profundizar en nuestro conocimiento de las funciones usando una: usando la función sqrt(). Resulta que alguien se ha preocupado de construir una función llamada sqrt() que sirve para calcular raíces cuadradas. Vamos a usarla!! Cómo??

saber consultar la ayuda de una función is VERY important [ 🌟 ]

  • Para saber como usar una función lo que hay que hacer es consultar la ayuda de la función; sí, cada función de R tiene una página de ayuda interna.

  • Para abrir la ayuda de una función tienes que situar el cursor en el nombre de la función y pinchar en F1. También puedes hacer:

help(sqrt)


  • Pufff!!! la ayuda de la función parece muy complicada. Sí, eso parece: hay que aprender a leer las ayudas de las funciones. Esto es MUY IMPORTANTE!!!! si quieres aprender a manejarte con R. Enseguida lo vemos

seguimos con las funciones

  • Aunque no lo entiendas del todo, tienes que saber que, cuando vamos a usar una función, su estructura es: nombre_de_la_funcion(argumento_1, argumento_2, ….) . Luego volveremos a este punto.


  • Tarea:Ejecuta estas instrucciones e intenta entender qué ocurre.
sqrt(9)
sqrt(9, 4)   #- no funciona ¿por qué? ¿cuantos argumentos tiene la f. sqrt()?
sqrt("9")    #- no funciona, ¿por qué? ¿Cómo, de qué tipo, ha de ser el argumento?


seguimos con las funciones (más detalles) [🌶🌶🌶]

  • En realidad, cuando vamos a usar una función, cada argumento de la función tiene 2 elementos: el nombre del argumento y un valor para el argumento
nombre_de_la_funcion(name_argumento_1 = valor_1, name_argumento_2 = valor_2, ....)
  • El nombre de la función sqrt() es sqrt, ok, pero ¿cuáles son sus argumentos? La ayuda nos dice que sólo tiene un argumento, cuyo nombre es x; además, el valor del argumento debe ser numérico. (!!!).
sqrt(9)       #- en realidad "no hace falta" poner el nombre del argumento
sqrt(x = 9)   #- 
sqrt(x = 4)

  • Vamos a aprender a diferenciar el nombre y el valor del argumento de una función:
sqrt(9)
sqrt(x = 9)

x <- 25
sqrt(x)

sqrt(x = x)          #- !!!
sqrt(x = un_valor)   #- !!!
sqrt(nn = 9)         #- !!!

seguimos con las funciones (ya casi lo tenemos!!)

  • Tarea: calculad con R el logaritmo de 1000 en base 10.

    Para ello tenéis que usar la función log(), y como no sabéis cómo se usa, no sabéis cómo es su sintaxis, no sabéis cuáles son sus argumentos, os tocará mirar la ayuda de la función.


  • Venga, que os ayudo: log(1000) no va a funcionar. ¿Por qué? para saberlo tendrás que mirar la ayuda de la función log()

help(log)
log(1000)  #- como no especificamos el valor del argumento "base",
           #- R lo fija a su valor x defecto; es decir, base = exp(1) 
           #- así que estamos tomando logaritmos naturales
log(x = 1000, base = 10)    #- GOOD

log(1000, base = 10)        #- es equivalente
log(x = 1000, 10)           #- es equivalente
log(1000, 10)               #- es equivalente

log(1000, bas = 10)         #- funciona, pero ...

¿Por qué no podemos usar la expresión de abajo?

log(10, 1000)
log(base = 10, 1000)

Para finalizar (de momento) con las funciones, 2 cosas:


  • En casa, podéis ver [este video]: en él nos cuentan que, cuando creas una función, su estructura general es:
    function_name <- function(my_args) {
    # process the arguments
    # return some value
    }

Por ejemplo, podríamos crear una función para sumar 1 a un número:

add1 <- function(my_number) {
  my_number + 1
}

venga a hacer la tarea para finalizar con las funciones!! [🌶🌶🌶🌶]

  • Tarea: cread una función que sume 3 números (!!)

  • Venga, que os ayudo: Hay que utilizar la f. llamada function() y poner entre llaves el código que quieres que implemente la función.

  • Recuerda que has de poner un nombre a tu función.

  • Recuerda que has de poner el nombre de los argumentos de tu función dentro del paréntesis, separados por comas. Nuestra función tendrá 3 argumentos


Quedará algo así:

name_of_my_function <- function(<los argumentos van AQUI>){
  #- aquí tienes que poner el código de la función
}

Esta vez no hay solución.





Como ya hemos creado nuestra función que suma 3 números, vamos a mejorarla un poco: vamos a poner valores por defecto a los argumentos (por si alguien se olvida de introducir los valores a nuestra función).

  • Por ejemplo que el valor por defecto del primer argumento sea 4, el del segundo que sea 6, y el del tercero que sea 3.

Venga, os doy una solución parcial. Solo tenéis que rellenar los 7 sitios en los que aparece “…”

... <- function(n1 = ... , ... = 6, ... = ... ){
   ... + n2 + ...
}







Solución a la primera tarea

my_suma <- function(n1 , n2, n3){
   n1 + n2 + n3
}

#- vamos a usar nuestra función
my_suma(2, 2, 2)
my_suma(2)        #- xq no funciona

Solución a la segunda tarea

my_suma <- function(n1 = 4 , n2 = 6, n3 = 3){
   n1 + n2 + n3
}

#- vamos a usar nuestra función
my_suma(2, 2, 2)
my_suma(2)        #- xq ahora sí funciona

Paquetes: instalación y ayuda

Es importante entender la diferencia entre paquetes en CRAN y en otros repositorios, y sobre todo, saber buscar la ayuda de un paquete.

Paquetes (primeras ideas)


  • ¿Qué son los paquetes? trozos/porciones de código R que podemos instalar en nuestro ordenador

  • ¿Qué ganamos instalando un paquete? Los paquetes nos proveen de nuevas funciones o nuevos datos; es decir incrementa la funcionalidad de R: por ejemplo, con el pkg meme podemos hacer memes.


  • Los paquetes suelen estar en repositorios


  • R tiene un repositorio oficial llamado CRAN. Tiene más de 20.000 paquetes. Aquí puedes ver el listado de paquetes ordenados alfabéticamente y por fecha, y aquí ordenados por tópico.


  • Hay otros repositorios: Github, Gitlab, Bioconductor, …

¿Cómo me instalo un paquete? (Forma habitual)

  • Para instalar un paquete que está en CRAN hay que usar:
install.packages("dplyr")    #- instalamos el pkg dplyr en nuestro ordenador
library(dplyr)               #- cargamos dplyr en memoria de R para así poder usarlo
  • Para instalar un paquete que está en GitHub lo más cómodo es usar el paquete pak:
install.packages("pak")       #- previamente hay que instalar el pkg pak
pak::pak("tidyverse/dplyr")   #- instalamos la versión de github del pkg dplyr



  • Recuerda que, una vez instalado un paquete, cada vez que queramos usar ese paquete hay que cargarlo en memoria con
library(dplyr)    #- cargamos dplyr en memoria de R para así poder usarlo


  • Recuerda que los paquetes se instalan una sola vez, pero que cada vez que queramos usarlo hay que “cargarlo” en memoria con library()

Obtener ayuda de un paquete

  • Los paquetes que están en CRAN, tienen obligatoriamente un manual en pdf, pero son mucho más didácticas las vignettes (que no son obligatorias).

  • Por ejemplo, el paquete dplyr está en CRAN en esta dirección. Como podéis ver tiene un manual en pdf y un listado de viñetas.

  • Si el paquete tiene vignettes, también puedes consultarlas desde RStudio usando cualquiera de las 2 expresiones de abajo:

help(package = "dplyr")
browseVignettes("dplyr")

  • Generalmente los paquetes, incluso los que están en CRAN, tienen una versión de desarrollo en Github. Por ejemplo, aquí tienes el link al repo de dplyr en Github.

  • Además, cada vez es más frecuente que los paquetes tengan una página web propia. Por ejemplo aquí tienes la página web de dplyr. Generalmente tienen una sección llamada “Articles” donde tienes las vignettes.

  • Aunque la verdad, muchas veces, la forma más rápida de aprender a usar un paquete es buscar en Google, y generalmente encuentras un post con una buena introducción al paquete.

Ejemplo: vamos a buscar ayuda para poder usar el paquete “explore”

Tarea: imagina que queremos usar el paquete explore ya que parece que facilita el análisis rápido de datos. Trata de usar este paquete para analizar un conjunto de datos; p.ej. el conjunto de datos iris o el conjunto de datos penguins (incluido en R desde la versión 4.5).

Diálogo ficticio en el aula:

  • Yo: Sí, ya sé que llevas poco tiempo con R y que no has usado nunca ese paquete… pero sabes que generalmente los paquetes tienen vignettes y que igual en algún post describen su uso. Venga a ello!!!

  • Tú: casi mejor me espero a que lo hagas tú.

  • Yo: No way!!

  • Tú: pero es que estoy cansado, y da pereza, y no voy a saber!!

  • Yo: Venga a buscar información de ese paquete!! Ni se te ocurra mirar la “solución”.

#- post: https://rolkra.github.io/start-to-explore/
#- CRAN: https://cran.r-project.org/web/packages/explore/index.html
#- Github: https://github.com/rolkra/explore

#- install.packages("explore")                 #- instalamos la versión de CRAN
#- pak::pak("rolkra/explore")                  #- instalamos la versión de Github

#- vamos a usar el paquete con el conjunto de datos `iris`
library(explore)
explore(iris)

#- vamos a usar explore para analizar `penguins`
library(explore)
explore(penguins)

Algunas ideas más

Cosas que nos encontraremos enseguida cuando trabajemos con datos reales

Valores perdidos: NA

  • En los datos reales casi siempre faltan valores. En R se representan con NA (Not Available)


  • Cuidado: los NA se propagan. Si operas con un NA, el resultado es NA
aa <- c(4, NA, 10)

aa + 1               #- el NA sigue siendo NA
mean(aa)             #- devuelve NA !!
mean(aa, na.rm = TRUE)   #- na.rm = TRUE: quita los NA antes de calcular


  • Para saber si hay NA se usa is.na(), no uses aa == NA
aa == NA          #- no funciona: devuelve NA, NA, NA  ¿por qué?
is.na(aa)         #- GOOD


sum(is.na(aa))    #- cuántos NA hay
aa[!is.na(aa)]    #- nos quedamos con los valores que no son NA

Funciones vectorizadas vs. funciones de resumen

  • Las funciones vectorizadas devuelven un valor por cada elemento del vector
aa <- c(4, 9, 25)
sqrt(aa)      #- devuelve 3 valores
  • Las funciones de resumen devuelven un único valor
sum(aa)
mean(aa)
max(aa)
length(aa)    #- número de elementos del vector


  • Algunos truquillos: al sumar valores lógicos, TRUE cuenta como 1 y FALSE como 0 (¡coerción!)
aa <- 1:10
aa > 5          #- vector de TRUE/FALSE
sum(aa > 5)     #- ¿cuántos elementos son mayores que 5?
mean(aa > 5)    #- ¿qué proporción de elementos son mayores que 5?

Factores

  • Los factores se usan para almacenar variables categóricas: sexo, provincia, nivel de estudios …

  • En los factores, las categorías se llaman levels

  • Los factores suelen verse como texto … pero por dentro son números enteros (cada número está asociado a una etiqueta).
aa <- c("medio", "alto", "bajo", "medio")
ff <- factor(aa)
ff
levels(ff)       #- por defecto, los levels se ordenan alfabéticamente
typeof(ff)       #- ¿?


  • ¿Para qué sirven? nos servirán principalmente para fijar el orden de las categorías (en tablas y gráficos):
ff.2 <- factor(aa, levels = c("bajo", "medio", "alto"))
levels(ff.2)
table(ff.2)        #- las categorías salen en el orden que hemos fijado
  • Los veremos de nuevo cuando hagamos gráficos con ggplot2 (y los manipularemos/usaremos principalmente con el paquete forcats)

Inspeccionar un data frame

  • Lo primero que haremos siempre al importar unos datos es echarles un vistazo
df <- data.frame(Nota = c(4, 8, 6, 3),
                 Nombre = c("Juan", "Paz", "Adrian", "Marquitos"),
                 Aprobado = c(FALSE, TRUE, TRUE, FALSE))

str(df)       #- estructura: nº de filas, columnas y tipo de cada columna
head(df, 2)   #- las primeras filas (tail() muestra las últimas)
nrow(df)      #- número de filas
ncol(df)      #- número de columnas
names(df)     #- nombres de las columnas
summary(df)   #- resumen estadístico de cada columna


  • En RStudio también puedes pinchar en el data frame en el panel Environment o usar View(df)

  • En el tidyverse, dplyr::glimpse(df) es una alternativa a str() muy cómoda

La notación paquete::funcion()

  • En las slides ha aparecido varias veces algo como stringr::str_to_sentence() o pak::pak(). ¿Qué significan los ::?

  • paquete::funcion() permite usar una función de un paquete sin cargar el paquete con library(). Eso sí, el paquete tiene que estar instalado

stringr::str_to_upper("hola")    #- funciona sin hacer library(stringr)

library(stringr)
str_to_upper("hola")             #- tras cargar el paquete ya no hace falta el ::
  • ¿Por qué usarlo?

    • Deja claro de qué paquete sale cada función

    • Evita conflictos cuando 2 paquetes tienen funciones con el mismo nombre. Por ejemplo, existe stats::filter() y dplyr::filter()

    • Si solo vas a usar una función de un paquete, no hace falta cargarlo entero

El pipe: |>

  • Muchas veces queremos aplicar varias funciones seguidas. Se pueden anidar, pero se leen mal (de dentro a fuera):
aa <- c(4, 9, 25)
sum(sqrt(aa))


  • El pipe (|>) pasa el resultado de la izquierda como primer argumento de la función de la derecha. Se lee de izquierda a derecha: “coge aa, y luego haz la raíz cuadrada, y luego súmalo”
aa |> sqrt() |> sum()

aa |> 
  sqrt() |> 
  sum()          #- lo mismo, pero en varias líneas (así lo escribiremos habitualmente)


  • No hay nada mágico: aa |> sqrt() es exactamente lo mismo que sqrt(aa)

  • Lo usaremos constantemente con el tidyverse. (Verás también el pipe %>% del paquete magrittr: funciona casi igual)

Errores típicos (y cómo leerlos)

  • Los mensajes de error parecen crípticos, pero leerlos con calma suele darnos la pista. Algunos de los más frecuentes (R los muestra en castellano o en inglés según la configuración de tu ordenador):
aa <- 4
Aa + 1                #- Error: objeto 'Aa' no encontrado (object 'Aa' not found)
                      #- R distingue mayúsculas y minúsculas 

read_csv("datos.csv") #- Error: no se pudo encontrar la función "read_csv"
                      #- el paquete no está cargado: falta library(readr)


mean(c(1, 2, 3)       #- R se queda esperando con un "+" en la consola
                      #- falta cerrar un paréntesis (pulsa Esc para salir)


  • Si no entiendes un error, copia el mensaje y búscalo en Google: es muy probable que alguien haya tenido el mismo problema

Reiniciar R en lugar de rm(list = ls())

  • Antes vimos que rm(list = ls()) borra todos los objetos del Global environment. Pero no deja R “limpio”: los paquetes cargados y las opciones que hayamos cambiado siguen ahí

  • Es mejor reiniciar la sesión de R: en RStudio, menú Session > Restart R (o Ctrl + Shift + F10)


  • ¿Por qué es importante? Porque nuestro código tiene que funcionar empezando desde cero. Si un script solo funciona porque hay objetos o paquetes que cargamos “a mano” antes, no es reproducible

  • Un buen hábito: reinicia R de vez en cuando y vuelve a ejecutar tu script desde el principio. Si funciona, vas bien


  • Además, conviene que RStudio no guarde ni recupere el Global environment al cerrar: Tools > Global Options > General y desmarca Restore .RData into workspace at startup y en Save workspace to .RData on exit elige Never