2  Empezando con R

2.1 Introducción

Para instalar una librería adicional para resolver un problema concreto, usar el comando install.packages desde consola o ir a pestaña Packages.

Ha sido aceptado como lenguaje de análisis analítico por Facebook, Google, LinkedLn, etc.

2.2 RStudio

Explicar el entorno de Rstudio: 4 paneles

  • Editor
  • Environment
  • Consola - Terminal
  • Files - Packages - Help

Puedes cambiar la disposición de estos 4 paneles. Yo uso la siguiente disposición:

View - Panes - Console on Rigth

  • Help - Resources - Manuals

  • Puedes consultar ayuda de un comando desde la Consola:

?det

help("det")
  • Consola

  • aunque trabajar en la consola no es lo habitual (mejor en un script que puedas editar, modificar, etc), puedes ejecutar en la consola lo que consideres

En la consola de R tenemos una potente calculadora.

2+1/3
[1] 2.333333
pi+pi/2
[1] 4.712389
cos(pi/3)
[1] 0.5
1/2+1
[1] 1.5
1/(2+1)
[1] 0.3333333
sqrt(2)+(5+sqrt(3))/2
[1] 4.780239

Los resultados los podemos guardar en una variable usando <-. Podríamos usar el símbolo =.

  • Los nombres de las variables deben empezar con una letra y pueden contener letras, números, _ y ..
  • Usa nombres descriptivos en tu programa.
  • Puedes usar múltiples palabras enlazadas con los símbolos.
una_variable_posible
UnaVariablePosible
una.variable.posible
mi.media
usa.siempre.el.mismo.convenio.para.tus.nombres
resul <- sqrt(2)+(5+sqrt(3))/2
resul2 = resul+5

El origen del uso de <- viene de las tuberias (pipeline) en algunos sistemas operativos y lenguajes de programación y es la usada en el lenguaje R casi por convenio.

R en la primera orden evalúa todo lo que hay a la derecha de <- (debe ser una operación válida) y el resultado se almacena en el objeto resul que será del tipo de datos del resultado de la parte derecha.

Truco:

  • Usa Alt + - (tecla Alt junto con el signo menos) para añadir <-. Además RStudio automáticamente rodea <- con espacios, lo que hará que tu programa sea más legible.

  • Editor

En editor es usual utilizar comentarios, separar-agrupar líneas, …

# Esto es un comentario

# Usar ; para separar comandos en una línea

# Usar { } para agrupar comandos

crear un script en blanco en el que vamos ejecutando algunos comandos básicos

Vamos a ver algunas características de los diferentes tipos de datos que nos podemos encontrar.

2.3 Tipos de datos

Esta sección resume lo que podemos denominar R básico, es decir, las estructuras de datos más importantes del lenguaje.

El tipo de datos de un valor nos dice qué valores puede tomar. Los datos se guardan en variables y cada variable tendrá por tanto un tipo de datos asociado.

  • Logical

  • Numeric

  • Character

  • Vector

  • data.frame, tibble

  • Double, Complex, Raw, etc.

L <- TRUE
L1 <- FALSE
L2 <- L+1
  • class() muestra la clase
  • is.xxx() comprobar tipos
class(L)
[1] "logical"
class(L1)
[1] "logical"
class(L2)
[1] "numeric"
is.logical(L)
[1] TRUE
is.logical(L1)
[1] TRUE
is.logical(L2)
[1] FALSE
  • coercion -conversión de tipos - R es muy flexible con las conversiones pero - FLEXIBILIDAD - CUIDADO
L+1
[1] 2
class(L+1)
[1] "numeric"

Ejemplo de conversiones

a <- 1
class(a)
[1] "numeric"
is.character(a)
[1] FALSE
a1 <- as.character(a)
a1
[1] "1"
is.character(a1)
[1] TRUE
class(a1)
[1] "character"
titulovariable <- "Años"
is.character(titulovariable)
[1] TRUE
is.logical(titulovariable)
[1] FALSE
# titulovariable+1  - esto da error

Conversiones de tipos: con la familia de funciones as.xxx()

años <- c(2020,2021,2022,2023,2024)
primervalor <- años[1]
class(primervalor)
[1] "numeric"
primervalor+1.0
[1] 2021
primervalor <- as.character(primervalor)
primervalor
[1] "2020"
# primervalor+1  - esto da error
  • Ejemplos de conversiones
as.numeric(TRUE)
[1] 1
as.character(4)
[1] "4"
as.numeric("2001")
[1] 2001

2.3.1 Valores especiales

  • destacamos NA - Not Available para representar valores desconocidos en un dataset
M1 <- 0/0
M2 <- 2/0
M3 <- NA
M3+2
[1] NA
0/0
[1] NaN
2/0
[1] Inf
valor_desconocido <- NA
valor_desconocido+1
[1] NA

Importante: cazar los valores NA en un dataset

Cuidado: al hacer operaciones con variables conteniendo NA

valor <- NA
valor+1
[1] NA

2.4 Vectores

Es la estructura de datos básica en R. Muchas otras estructuras de datos usan los vectores internamente. Todos los elementos que forman parte del vector deben tener el mismo tipo básico (entero, numérico, carácter, lógico,…).

El método principal para construir un vector es el operador c() (combine - combinar):

años <- c(2020, 2021, 2022, 2023, 2024)
años
[1] 2020 2021 2022 2023 2024

Los vectores atómicos son siempre de una dimensión. Si anidamos, R aplana (flat) los datos.

Ejecuta en tu ordenador:

v1 <- c(1,c(2,c(3,4,5))); v1
# es lo mismo que
v2 <- c(1,2,3,4,5);v2
v3 <- c(v1,c(v2));v3

El comando length() calcula la longitud de un vector. Calcula la longitud de v1, v2 y v3 en tu ordenador.

También podemos crear vectores usando (ejecuta en tu ordenador):

v1 <- 1:10; v1
v1a <- 10:1;v1a
v2 <- seq(1, 10, 3); v2
v2b <- seq(from=2, to=10, by=0.1); v2b
v2c <-seq(from=0, to=100,length.out=5);v2c
v3 <- rep(c(1, 2), times=3);v3
v3 <- rep(c(1, 2), 3);v3
  • del vector anterior cogemos el primer valor
años[1]
[1] 2020
años[1]==2010
[1] FALSE
class(años)
[1] "numeric"

is.vector()

str()

head(), length()

str(años)
 num [1:5] 2020 2021 2022 2023 2024
head(años)
[1] 2020 2021 2022 2023 2024
length(años)
[1] 5
is.numeric(años)
[1] TRUE
is.vector(años)
[1] TRUE
  • names()
los_años <- c(2000,2001,2002)

length(los_años)
[1] 3
class(los_años)
[1] "numeric"
str(los_años)
 num [1:3] 2000 2001 2002
is.vector(los_años)
[1] TRUE
nombres_años <- c("primero","segundo","tercero")
length(nombres_años)
[1] 3
class(nombres_años)
[1] "character"
str(nombres_años)
 chr [1:3] "primero" "segundo" "tercero"
#Darle nombres a las posiciones de un vector

names(los_años) <-nombres_años
los_años
primero segundo tercero 
   2000    2001    2002 
# acceder por posición
los_años[1]
primero 
   2000 
los_años[c(2,3)] # posiciones 2 y 3
segundo tercero 
   2001    2002 
los_años["primero"]
primero 
   2000 
los_años[c("primero","segundo")]
primero segundo 
   2000    2001 
  • Construir vectores - secuencias

Notación rango

los_años <- 2000:2022 
los_años
 [1] 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014
[16] 2015 2016 2017 2018 2019 2020 2021 2022
min(los_años)
[1] 2000
mean(los_años)
[1] 2011
sum(los_años)
[1] 46253
l1 <- los_años - 2000
exp(l1)
 [1] 1.000000e+00 2.718282e+00 7.389056e+00 2.008554e+01 5.459815e+01
 [6] 1.484132e+02 4.034288e+02 1.096633e+03 2.980958e+03 8.103084e+03
[11] 2.202647e+04 5.987414e+04 1.627548e+05 4.424134e+05 1.202604e+06
[16] 3.269017e+06 8.886111e+06 2.415495e+07 6.565997e+07 1.784823e+08
[21] 4.851652e+08 1.318816e+09 3.584913e+09

2.4.1 Reciclaje

los_años+1  
 [1] 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015
[16] 2016 2017 2018 2019 2020 2021 2022 2023
los_años+c(1,0)  
Warning in los_años + c(1, 0): longer object length is not a multiple of
shorter object length
 [1] 2001 2001 2003 2003 2005 2005 2007 2007 2009 2009 2011 2011 2013 2013 2015
[16] 2015 2017 2017 2019 2019 2021 2021 2023

Cuidado con reciclaje:

v1 <- c(1,2,3)
v2 <- 1:10
v3 <- cos(v2)
v4 <- c(v1,v1^2,0,cos(v1))
v5 <- v2+v3
# Cuidado reciclaje
v6 <- v1+1
v7 <- v1+v2 # no tienen igual tamaño
Warning in v1 + v2: longer object length is not a multiple of shorter object
length

2.4.2 Acceso a vectores

los_años <- 2020:2022
los_años[2]
[1] 2021
los_años[c(1,3)]
[1] 2020 2022
los_años[c(TRUE,FALSE,TRUE)]
[1] 2020 2022
los_años[-1]
[1] 2021 2022
los_años[-c(1,2)]
[1] 2022

¿Qué hace el siguiente comando?

los_años[c(TRUE,FALSE)]
[1] 2020 2022

Interesante: Reciclaje

2.4.3 NA en un vector

los_años <- c(los_años,NA)
mean(los_años)
[1] NA

averiguar la posición en la que está el valor NA: which

which(is.na(los_años))
[1] 4

o las posiciones en la que el vector tiene un valor que te interese

which( los_años>2020)
[1] 2 3

2.5 Factor

Es un vector con información de los valores presentes en el vector (denominados ‘levels’ - niveles). R utiliza una representación compacta para este tipo de datos. Un factor puede representar variables categóricas usadas en tablas de contingencia, regresión lineal, análisis de varianza, regresión logística, etc.

x <- c(1, -1, 1, 0, 3, 4)
f1 <- factor(x)
f1
[1] 1  -1 1  0  3  4 
Levels: -1 0 1 3 4

Como ves en Levels el factor almacena los distintos valores que hay en f1. Cuando utilicemos en el curso algunos métodos de análisis de datos necesitaremos que las variables sean factor o los métodos devolverán variables de tipo factor.

2.6 Listas

Una lista es un vector de objetos de tipos distintos que están agrupados.

alumno1 <- list(nombre = "Luis", no.asignaturas = 4, 
                 nombre.asignaturas = c("Lab1", "Lab2", "Lab3"))
# Escribe lo siguiente
alumno1
alumno1$nombre # acceder al dato nombre
alumno1$nombre.asignaturas # acceder al dato asignaturas
alumno1$nombre.asignaturas[1] # acceder a la primera asignatura
# IMPORTANTE: Ver  la diferencia entre los   siguientes comandos
alumno1[1]
alumno1[[1]]
class(alumno1[1])
class(alumno1[[1]])

Debatiremos el uso de las listas y la diferencia entre usar [ ] y [[ ]].

El comando unlist aplana una lista.

L <- list(list(c(1,2,3), 4), 5)
mean(L)  # resultado es NA, no puede calcular la media
mean(unlist(L)) # ahora si
unlist(L)

2.7 Matrices

Una matriz es un objeto de dos dimensiones que contiene a datos del mismo tipo. No solo en matemáticas se usan matrices. Cualquier área de la ciencia las utiliza como método de representación de un objeto con dos dimensiones representando algo en concreto.

Se considera que probablemente la Ciencia de Datos que podamos tener en el futuro estará fundamentada en el Álgebra Lineal, en el que el uso de matrices y la operativa matricial juegan un papel esencial.

Nota: el objeto matriz y el objeto vector son diferentes. Un vector no es una matriz de dimensión 1.

Para crear una matriz:

  • matrix()
  • array() (matrices de n-dimensiones, no las usaremos en este curso)
  • cambiando la dimensión a un vector usando dim().
  • combinando con rbind, cbind vectores.
M1 <- matrix(1:6, nrow = 2, ncol = 3)
M1 <- matrix(1:6,  2,   3);M1

#Comprobar que hace la siguiente orden (¡Cuidado: Reciclaje!)
M2 <- matrix(1:4, nrow = 2, ncol = 3);M2

#¿Qué pasa si sumamos vector con una matriz?  (¡Reciclaje!)
M3 <- c(1,2,3) + M1;M3

#¿Qué hacen las siguientes órdenes?
v1 <-M1[M1 > 3];v1

i1 <- which(M1 > 3);i1

2.7.1 Acceso a matrices

Al igual que con los vectores, se usan corchetes para acceder a los elementos de una matriz. ¿Tienes claro lo que hacen los siguientes comandos?:

M1  
M1[2,3] 
M1[2,5] 
M1[ ,3]
M1[1:2,]
M1[1:2,2:3]
M1[c(2,1),c(2,1)]

2.7.2 Crear matrices

  • Comandos rbind, cbind
  • Cambiar la dimensión.
f1 <- c( 1, 2, 3)
f2 <- c( 4, 5, 6)
f3 <- c( 7, 8, 9)
M1 <- rbind(f1,f2,f3) # combina por filas
M1 
M1 <- cbind(f1,f2,f3) # combina por columnas
M1 
v1<- 1:12
dim(v1) <- c(3,4) # cambia la dimensión de v1 
v1
dim(v1)

Comando matrix: parámetros byrow para introducir por filas o por columnas.

# por filas
A <- matrix(c( pi, sqrt(2), 0, 1, 5, 1, 1, 0 ,-1),3, 3, byrow = TRUE) 
A
# por columnas
B <- matrix(c( cos(1), sin(0), 1, 1, 0, 1,1, 0, 0),3, 3, byrow = FALSE)
B

2.7.3 Operaciones matriciales

Mostramos algunas de las operaciones matriciales más importantes:

# Suma y Multiplicación elemento a elemento
A+B; A*B
# Multiplicación matricial
A%*%B
# Traspuesta
t(A)
# Determinante
det(A)
# Devuelve la diagonal
diag(A)
# Resolver un sistema de ecuaciones (Ax=b)
b <- c(2,3,1)
x <- solve(A,b);x
# Calcular autovalores y autovectores
eigen(A)

2.8 Data set

En R se denomina data.frame a los datasets.

Es una matriz que puede almacenar datos de distinto tipo: una matriz de listas. Es decir, por columnas podemos tener distintos tipos de datos.

n1 <- c("Luis","Antonio","Daniel")
e1 <- c(21,20,22)
D1 <- data.frame(alumnos=n1,edad=e1); D1
  alumnos edad
1    Luis   21
2 Antonio   20
3  Daniel   22
D1$alumnos
[1] "Luis"    "Antonio" "Daniel" 
D1$edad
[1] 21 20 22

Podemos acceder a una columna del data frame de distintas formas:

D1$alumnos
D1[1]

Se obtienen los valores de la primera columna, pero la salida no es exactamente igual. Lo más importante es que los tipos de datos son distintos.

class(D1$alumnos)
[1] "character"
class(D1[1])
[1] "data.frame"

Con [ ] accedemos a las columnas que indiquemos entre corchetes, pero devuelve un data frame. Si queremos acceder al vector que está dentro del data frame se usará [[ ]].

D1[1]
  alumnos
1    Luis
2 Antonio
3  Daniel
D1[[1]]
[1] "Luis"    "Antonio" "Daniel" 

Es decir, los siguientes comandos devuelven lo mismo:

D1$alumnos
D1[[1]]

Data frames son parecidos a matrices, pero a la hora de acceder a ellos hay que tener cuidado. Averigua lo que hacen los siguientes comandos:

D1[1:2]
D1[2:1]
D1[1:3]
# si ponemos , dentro de corchetes 
# antes de la coma -- las filas
# despues de las comas -- las columnas
# si antes o despues no se pone nada significa 
# o todas las filas o todas las columnas
D1[1,] # fila 1
D1[1:2,]
D1[1:2,]$alumnos
D1[1:3,]
D1[2:1,]$edad
D1[,1] #columna 1
D1[,1:2]

Usaremos rbind y cbind con listas o con data frames para conseguir un nuevo data frame.

# Uniendo dos listas
alumno1 <- list(nombre = "Luis", no.asignaturas = 3, 
                  nombre.asignaturas = c("Lab1", "Lab2", "Lab3"))
df1 <- as.data.frame(alumno1);df1

alumno2 <- list(nombre = "Antonio", no.asignaturas = 3, 
                  nombre.asignaturas = c("Lab2", "Lab1", "Lab3"))
df2 <- as.data.frame(alumno2)
mi.df1 <- rbind(df1, df2) 
mi.df1
# Añadir columna a data drame
alumno1b <- list(apellido = "Fernandez",  
                  ciudad= c("Málaga", "Málaga", "Sevilla"))
df1b <- as.data.frame(alumno1b)
df1b
mi.df2 <- cbind(df1, df1b) 
mi.df2

Se pueden combinar dos data.frames con una columna igual con el comando merge.

# Construyo primer data frame
a1 <- c("Luis","Antonio","Daniel")
e1 <- c(21,20,22)
D1 <- data.frame(alumnos=a1,edad=e1)
D1
D2 <- data.frame(alumnos=c("Luis","Daniel","Ángel"),
                 ciudad=c("Madrid", "Córdoba", "Málaga"))
D2
D3 <- merge(D1,D2,by="alumnos")
D3

Consultas de valores de una columna que cumplan una condición.

Entre [ ] colocamos una condición (o varias) que cumpla algún valor del data frame.

my.dataset <- data.frame(
    ciudad=c('Málaga','Sevilla','Cádiz','Málaga', 'Cádiz'),
    Estación=c('Invierno','Verano','Otoño','Otoño','Verano'),
    temperatura = c(37.4,36.3,38.6,37.2,38.9))
my.dataset
my.dataset$ciudad

my.dataset$ciudad[my.dataset$Estación=="Verano"]

2.9 Definición de funciones

Nombre <- function(parámetrosEntrada) {
  
  cuerpo
  return(parametroSalida)
}#end function

Un ejemplo:

mi.suma<-function(x){
    s <- 0
    for (n in x) {s <- s+n  }
    return(s)
}#end function

# En la consola podemos:
x <-1:50
mi.suma(x)

Ejemplo:

mi.media<-function(x){
  sum(x)/length(x)
}#end function

# En la consola podemos:
x <-1:50
mi.media(x)

2.10 Ejercicios

2.10.1 1. Vectores - UKgas

Importar el dataset UKgas. Almacenar la columna del dataset en un vector llamado consumo.de.gas. Preparar un fichero .R con las órdenes necesarias para realizar:

  • acceder a los 10 primeros elementos del vector consumo.de.gas
  • acceder a los elementos impares del vector consumo.de.gas
  • acceder a las posiciones 1,4,7,10,… del vector consumo.de.gas
  • acceder al vector consumo.de.gas en orden inverso
  • acceder a los 50 primeros elementos del vector consumo.de.gas excepto la posición 1, 3 y 5.
  • sumarle 1 a los elementos del vector consumo.de.gas (reciclaje)
  • sumar los 10 primeros elementos del vector consumo.de.gas con el vector v2=(1,2,3)
  • obtener los índices del vector consumo.de.gas cuyos elementos son menores de 50.
  • añadir (20,21,NA,22) al vector consumo.de.gas y guardarlo en consumo.de.gas1
  • obtener los índices del vector consumo.de.gas1 con valor NA.
  • calcular la media de los valores del vector consumo.de.gas1
  • calcular la media de aquellos valores del vector consumo.de.gas1 que estén por encima de la media.
  • cambiar los valores NA del vector consumo.de.gas1 por 0.

2.10.2 2. Funciones sencillas

  • Programar una función que devuelva dado un vector cuantos números impares tiene. AYUDA: Usar %% para calcular el resto.
  • Programar una función que calcule el volumen de una esfera dado el radio \(r\) de dicha esfera.
  • Programar una función que calcule el volumen de esferas con radio \(r=1,2, \ldots, 20\) y devuelva un data.frame con las dos columnas (radio, volumen).

2.10.3 3. Matrices y funciones - divido.matriz

Implementa una función que reciba una matriz y devuelva la diagonal de la matriz \(D\), la submatriz inferior debajo de la diagonal \(R\) y la la submatriz superior encima de la diagonal \(R\).

divido.matriz <- function(M){


  return(list(D=...,R=..., L=...))
}# fin función

Nota: Hay en R funciones matriciales que realizan justo la rutina que se pide.

Probar con un ejemplo, llamar a la función y mostrar los resultados.

2.10.4 4. Data Frames HairEyeColor

Importar el dataset HairEyeColor

Preparar un fichero .R con los comandos requeridos para lo siguiente:

  • Si el dataset importado no es un dataframe convertirlo a dataframe.
  • Analizar la estructura del dataset, tipo de datos, estructura, clase, etc.
  • Obtener número de columnas, número de filas.
  • Guardar en un vector el nombre de las columnas.
  • Cambiar el nombre de la primera columna.
  • Averiguar el tipo de datos de la primera columna.
  • Comando para averiguar si hay valores NA en todo el dataframe, y lo mismo en la columna 1.
  • Practicar con el dataset para extraer un conjunto de filas y/o columnas.
  • Guardar cinco primeras filas en una variable d1 y las cinco últimas en una variable d2 y combinarlas en un nuevo dataframe llamado d12.
  • Utilizar el comando subset para extraer, eliminar, etc. un conjunto de columnas de un data set.
  • Usar subset para guardar en una variable las filas de dataset con valor para eye de Blue.
  • Guardar la primera columna en variable d y utilizar los comandos unique, table. ¿Para qué sirven estos comandos?.
  • Con la variable d usar colSums, colMeans. Explicar con ejemplos para qué sirven estos comandos.
  • Explicar con ejemplos para qué sirven los comandos rowSums, rowMeans.

2.10.5 5. Función iset

Dado una pareja de vectores mu y nu, realizar una función que haga lo siguiente:

  • Vaya cogiendo los elementos de mu y nu que estén en la misma posición y los reuna en vectores.
  • Todas las parejas se reunirán en una lista y está es la salida de la función.

De forma genérica sería

mu <- c(.....)
nu <- c(.....)
iset <- function(mu,nu){
  .....
  mi.set <- list(c(primerodemu,primerodenu), 
                 c(segundodemu,segundodemu),...)
  return(mi.iset) 
}#end function

Ejemplo de lo que debería salir

mu <- c(0.1, 0.3, 1)
nu <- c(0.7,0.5,0)
memb <- iset(mu,nu)

str(memb)
List of 3
 $ : num [1:2] 0.1 0.7
 $ : num [1:2] 0.3 0.5
 $ : num [1:2] 1 0
> 

2.10.6 6. Errores comunes

Explica por qué los siguientes comandos dan error o no hacen lo que podría ser previsible con la lectura del comando. Arreglalo.

# usa mtcars de paquete datasets
library(datasets)
data("mtcars")
mtcars[mtcars$cyl = 4, ]
mtcars[-1:4, ]
mtcars[mtcars$cyl <= 5]
mtcars[mtcars$cyl == 4 | 6, ]
mtcars[1:20]

# Errores??
x <- 1:5; x[NA]