Sección 2 Introducción a R y RStudio

R es un lenguaje y un entorno de programación con un enfoque originalmente al análisis estadístico. Es uno de los lenguajes de programacón más utilizados en la investigación científica y en otras campos como el aprendizaje automático, minería de datos, bioinformática, matemáticas financieras. Está disponible para los sistemas operativos Windows, Linux y Macintosh.

Algunas características de R son las siguientes:

  • Sintaxis clara y legible.
  • Orientación a objetos intuitiva.
  • Enfocado al análisis estadístico.
  • Tipos de datos dinámicos de muy alto nivel.

Una desventaja sobre todo para los principiantes es que utiliza una consola de comandos en lugar de una interfaz gráfica por lo cual el dominio de la sintaxis se vuelve muy exigente y requiere de mucha practica.

Consola de R
Consola de R

RStudio es un Entorno de Desarrollo Integrado (IDE), es decir es un conjunto de herramientas e interfaces que facilitan la programación y que están integrados por algunos de los siguientes elementos:

  • Editor.
  • Depurador.
  • Compilador.
  • Interfaz de ejecución.
  • Gestor de componentes.
  • Control de versiones.
RStudio
RStudio

2.1 Descarga de R y Rstudio

Lo primero será instalar R según su sistema operativo. Una vez instalado R, vamos a descargar e instalar RStudio.

2.2 RStudio

En RStudio tenemos 3 paneles principales:

  • La consola interactiva de R y una Terminal a la izquierda.
  • El panel Enviroment, History y Connections, arriba a la derecha.
  • El panel Files, Plots, Packages, Help, Viewer, abajo a la derecha.

Cuando abrimos algún archivo, por ejemplo un script de R, vamos a desplegar un cuarto panel arriba a la izquierda.

Paneles de RStudio
Paneles de RStudio

Existen dos formas principales de trabajar con RStudio:

  1. Interactuar con la consola de R.

  2. Escribir en un script.

Para correr un comando en RStudio tenemos tres opciones:

  1. Dar click en el botón Run en del cuarto panel.
  2. Seleccionar Correr líneas desde el menú “Code”.
  3. Seleccionar la línea a ejecutar (o dejar el cursor en esa línea) y usar la combinación de teclas Ctrl + Enter.

2.3 R como calculadora

R permite realizar la mayoría de las operaciones matemáticas. Por ejemplo, sumas, restas, raíces cuadradas, exponenciales e incluso permite trabajar con números complejos. La jerarquía de operaciones prevalece y además la mayoría de las funciones matemáticas tienen el mismo nombre de las calculadoras científicas.

2.3.1 Ejemplos de uso de R como calculadora

  • Los comandos +, -, *, / y ^ tienen el significado usual.
1+1
## [1] 2
  • Para raíces cuadradas de números positivos se escribe sqrt(ARG), donde ARG es un real positivo.
sqrt(16)
## [1] 4
( 3 + (5 * (2 ^ 2 )))
## [1] 23
1/100000
## [1] 1e-05
2e3
## [1] 2000
  • Para el uso de funciones trigonométricas usuales (por default se calcula en radianes): sin(ARG), cos(ARG), tan(ARG) son el seno, cose y tangente usuales de ARG. Además por default tiene el valor de \(\pi\) guardador bajo el nombre de pi.
cos(2*pi)
## [1] 1
pi
## [1] 3.141593
  • Para calcular exponenciales usamos exp(ARG) y log(ARG1, base = ARG2), donde ARG2 es la base del logaritmos. El número \(e\) se optiene como exp(1).
exp(1)
## [1] 2.718282
log(exp(1))
## [1] 1
log(100, base = 10)
## [1] 2
log10(100)
## [1] 2
sinpi(2)
## [1] 0

Con los datos flotantes, podemos tener problemas de precisión. Un paquete que ayuda a esto es Rmpfr.

#install.packages("Rmpfr")
library(Rmpfr)
exp(mpfr(710, precBits = 54))
## 1 'mpfr' number of precision  54   bits 
## [1] 2.23399476616171112e+308
  • La división entera de \(\lfloor \frac{ARG1}{ARG2}\rfloor\) se obtiene escribiendo ARG1 %/% ARG2.
26 /3 ; 26 %/% 3; 26 %% 3
## [1] 8.666667
## [1] 8
## [1] 2
  • También tenemos las funciones factorial \(ARG!\) y combinaciones \(\binom{ARG1}{ARG2}\).
factorial(3)
## [1] 6
choose(3,2)
## [1] 3
  • En R, cuando hay presencia de división entre 0, nos devuelve como resultado Inf o -Inf, dependiendo del signo del numerador, o NaN cuando el numerador es 0.
3/0
## [1] Inf
-3/0
## [1] -Inf
0/0
## [1] NaN
  • También aparece NaN cuando sacamos raíces de números negativos.
sqrt(-9)
## Warning in sqrt(-9): Se han producido NaNs
## [1] NaN
  • R es capaz de trabajar con números complejos.
sqrt(-4+0i)
## [1] 0+2i
  • Los NaN tiene su propia aritmética.
# Ejercicio: explorar que sucede al operar con NaN
# NaN / 0
# NaN + 1
# NaN * 2
# NaN + Inf
# NaN /Inf
  • Para pedir ayuda con funciones, se escribe en la consola ?sin().
#?sinpi()

2.4 Operador de asignación y nombres de las variables

En el caso de RStudio, el operador de asignación de variables es <- y la sintaxis que se usa es VARIABLE <- VALOR.

x <- 2
x/2 
## [1] 1
y <- 4
x * sqrt(y)
## [1] 4

La combinación de teclas para obtener el operador <- es Alt + -.

Una buena practica es que los nombres asignados a nuestros valores sean descriptivos. En R, existen ciertos palabras reservadas que no podemos usar como variables, también no deben de empezar con números o algúnc caracter extraño.

#if <- 2
#1numero <- 5
#$numero <- 3

Algunos estilos de nombres usuales para variables son los siguientes:

  • num_de_euler
  • NumDeEuler
  • num.de.euler
  • num_de.Euler
#Ejercicio: crear dos variables y realizar una operación con ellas.

2.5 Tipos de Objetos

Existen dos tipos de datos: atómicos y estructurados. Un dato atómico es aquel que se considera unidad mínima de información, como los números enteros y un dato estructurado es una colección de datos atómicos.

Datos atómicos:

  • Lógico: Datos que solo permiten los valores lógicos TRUE y FALSE.
  • Numérico: Datos cuyos valores son números reales.
  • Complejo: Datos cuyos valores son números complejos.
  • Caracter: Datos cuyos valores son cualquier tipo de carácter o cadena.

Datos estructurados:

  • Arreglos: colecciones multidimensionales de datos.
  • Vectores: Arreglos unidimensionales. Cada uno de sus elementos es del mismo tipo.
  • Matrices: Arreglos de dos dimensiones. Todos sus datos son del mismo tipo.
  • Dataframes: Son arreglos de dos dimensiones. Los datos de una misma columna son del mismo tipo pero puede variar el tipo de dato en diferente columna.
  • Listas: colecciones unidimensionales de datos donde cada elemento puede ser de un tipo diferente.

En R, casi todo lo que se manipula son objetos. Cada objeto tiene sus propias características como tamaño, dimensiones, longitud, tipo y sus propias funciones. Los objetos más comunes en R son:

  • Vectores
  • Matrices
  • Arreglos
  • Listas
  • Dataframes

2.5.1 Vectores en R

Uno de los objetos más simples pero poderosos de R son los vectores. Los vectores son listas ordenadas de datos. Para crear un vector usamos la asignación vector <- c("dato1", "dato2"). Por ejemplo, mi_vector <- c("hola", "clase", "1"), en este caso el elemento hola es el primer elemento del vector, además todos los elementos son del mismo tipo texto que llamaremos strings.

Podemos calcular la longitud de los vectores en R usando la función length(vector).

mi_vector <- c("hola", "clase", "1")
length(mi_vector)
## [1] 3

Los elementos de los vectores los podemos llamar a través de índices. R siempre indexa desde el número 1 a diferencia de Python que indexa en 0.

mi_vector[1]
## [1] "hola"
#Ejercicio: Crea un vector de números enteros

En R podemos realizar operaciones vectorizadas, es decir se pueden aplicar las operaciones a cada elemento de nuestro vector.

#Ejercicio: Realiza la multiplicación del vector que creaste por el número 2.

En R la mayoría de las operaciones matemáticas están vectorizadas como la multiplicación, raíces, divisiones, logaritmos o exponenciales.

c(2,4,6)/2
## [1] 1 2 3
c(1,2,3)^2
## [1] 1 4 9

Se pueden combinar también las operaciones vectorizadas e índices.

mi_vector2 <- c(2,4,6)
mi_vector2[2]*5
## [1] 20

Las sumas y restas tienen un comportamiento especial.

#Ejercicio: Crea dos vectores de la misma longitud y súmalos. 
#¿Qué realiza la suma de vectores? 
#¿Qué pasa si sumas vectores de diferente longitud?

Otras operaciones vectorizadas son las comparaciones. Los operadores de comparación que podemos usar en R son los siguientes:

  • == para ver igualdad.
  • != para ver diferencia.
  • >= para ver si el lado izquierdo es mayor o igual que el derecho.
  • <= para ver si el lado izquierdo es menor o igual que el lado derecho.
  • > para ver si el lado izquierdo es mayor que el lado derecho.
  • < para ver si el lado izquierdo es menor que el lado derecho.
-1 <= 9 
## [1] TRUE
c(1,2,3) == c(1,2,4)
## [1]  TRUE  TRUE FALSE

Si tenemos dos expresiones lógicas, podemos usar también los siguientes operadores:

  • & es la conjunción.
  • | es la disyunción.
  • ! es la negación.
2 < 3 & 4> 1
## [1] TRUE
! 2 < 3
## [1] FALSE

Las sequencias regulares se pueden formar con el operador :.

x <- 1:3
x
## [1] 1 2 3

El operador : tiene prioridad sobre otros operadores.

#Ejercicio: ¿Qué obtenemos al realizar y <- 1:5-3?

Para formar una sequencia de números reales se usa la función seq, la sintaxis es como sigue: seq(from= 1, to=n, by=k, length.out = NULL ),

seq(from=1, to=40, by=5)
## [1]  1  6 11 16 21 26 31 36
seq(0, 1, by=0.1)
##  [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
#Ejercicio: ¿Qué pasa si invertimos el orden de las entradas en la función `seq`?
# seq(by=2, to=10, from=1)

La función seq se puede combianar con la creación de vectores.

x <- c(1, 2, 3, seq(4, 10, by=0.5))
#¿Cuál es la longitud del vector x?
#length(x)

Otra función que es útil para crear vectores es rep(Z,n), esta función crea un vector de n elementos todos iguales a Z.

y <- rep(2,10)
y
##  [1] 2 2 2 2 2 2 2 2 2 2
z <- c(x, y)
z
##  [1]  1.0  2.0  3.0  4.0  4.5  5.0  5.5  6.0  6.5  7.0  7.5  8.0  8.5  9.0  9.5
## [16] 10.0  2.0  2.0  2.0  2.0  2.0  2.0  2.0  2.0  2.0  2.0

Las variables se pueden reescribir.

y <- c(y, "hola")
y
##  [1] "2"    "2"    "2"    "2"    "2"    "2"    "2"    "2"    "2"    "2"   
## [11] "hola"
#Ejercicio: ¿Qué sucedió con el vector y? 
#¿De que tipo son sus elementos ahora?
#Realizar la operación y+2.

Podemos convertir objetos de un tipo a otro compatible usando las funciones as.(nombre_del_nuevo_tipo_de_objeto). Por ejemplo, nuestro vector y ahora es del tipo caracter, podemos quitar el elemento que es de tipo caracter y convertirlo a un nuevo objeto ahora de tipo numérico.

y[11]
## [1] "hola"
w <- as.numeric(y[1:10])
as.numeric(TRUE)
## [1] 1

Las funciones elementales como exp, log, sin, etc las podemos aplicar a los vectores siempre y cuando los elementos de nuestro vector estén en el dominimo de la función correspondiente.

log(c(1,2,4))
## [1] 0.0000000 0.6931472 1.3862944
(Logaritmo<-log(c(-1,2,3)))
## Warning in log(c(-1, 2, 3)): Se han producido NaNs
## [1]       NaN 0.6931472 1.0986123

Otras funciones útiles para vectores son:

  • max(x) y min(x): elemento máximo y mínimo del vector \(x\).
  • sum(x) y prod(x): nos devuelve la suma y producto de los elementos del vector \(x\).
  • mean(x) y var(x): nos devuelve la media y varianza del vector \(x\).
  • sort(x): ordena los elementos del vector \(x\) de manera creciente. Si agregamos el argumento decreasing=TRUE los ordena de mayor a menor.
  • order(x): nos da los índices correspondientes al ordenamiento de los elementos de \(x\) de menor a mayor.
sort(c(6,2,9,10,4))
## [1]  2  4  6  9 10
order(c(6,2,9,10,4))
## [1] 2 5 1 3 4
sort(c(6,2,9,10,4), decreasing = TRUE)
## [1] 10  9  6  4  2
sum(c(6,2,9,10,4)); prod(c(6,2,9,10,4))
## [1] 31
## [1] 4320
mean(c(6,2,9,10,4)); var(c(6,2,9,10,4))
## [1] 6.2
## [1] 11.2

Podemos también seleccionar elementos de un vector y cambiarlos.

x <- seq(1,10,1)
x[c(2,4,6,8,10)] <- 0
x
##  [1] 1 0 3 0 5 0 7 0 9 0
x[c(3,5)]<-c(2,4)
x
##  [1] 1 0 2 0 4 0 7 0 9 0

En el caso de vectores de caracteres, dos funciones que son útiles son substr() y substring() las cuales nos sirven para extraer cierta cantidad de caracteres de cada entrada del vector. La sintaxis es la siguiente: substr(x,inicio,final) y substring(x,inicio,last=1000000L).

clases <- c("01.Matemáticas", "02.Español", "03.Ciencias", 
            "04.Física", "05.Geografía")
substring(clases,4,last=1000000L)
## [1] "Matemáticas" "Español"     "Ciencias"    "Física"      "Geografía"
substr(clases,1,2)
## [1] "01" "02" "03" "04" "05"

La función names() nos ayuda a darle un nombre a las entradas de los vectores, es decir en lugar de índices númericos ahora podemos asignarle un nombre a cada entrada.

mis_calificaciones <- c(10,8,9,7,8)
names(mis_calificaciones)
## NULL
names(mis_calificaciones) <- c("Matemáticas", "Español", "Ciencias", "Física", "Geografía")
names(mis_calificaciones)
## [1] "Matemáticas" "Español"     "Ciencias"    "Física"      "Geografía"
mis_calificaciones
## Matemáticas     Español    Ciencias      Física   Geografía 
##          10           8           9           7           8

2.5.2 Arreglos

Un array es una colección de datos, todos del mismo tipo, indexada por varios índices, es decir son objetos multidimensionales en R.

Si \(dim=c(x_1,x_2,x_3...)\), donde \(x_1\), \(x_2\), \(x_3\), etc son enteros, entonces \(x_1\) es el número de filas, \(x_2\) es el número de columnas, \(x_3\) es el número de capas del array.

Una forma de crear arrays es primero crear un vector y después pasarle las dimensiones del arreglo.

x <- c(1:60)
# las dimensiones del array serán 6 filas y 10 columnas
dim(x) <- c(6,10)
dim(x)
## [1]  6 10

La función array() resume estas dos instrucciones. Su sintáxis es la siguiente: array(vector, dim = dimensiones).

# crea directo el array indicando vector y dimensiones
y <- array(c(1:60), dim = c(6,10))
y
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,]    1    7   13   19   25   31   37   43   49    55
## [2,]    2    8   14   20   26   32   38   44   50    56
## [3,]    3    9   15   21   27   33   39   45   51    57
## [4,]    4   10   16   22   28   34   40   46   52    58
## [5,]    5   11   17   23   29   35   41   47   53    59
## [6,]    6   12   18   24   30   36   42   48   54    60

La función class(objeto) nos permite conocer el tipo de objeto con el que estamos trabajando.

class(x)
## [1] "matrix" "array"
class(y)
## [1] "matrix" "array"
#Ejercicio: crear otro array z con el mismo vector x y 3 dimensiones y verifica el tipo de objeto que es z.

Las funciones ncol() y nrow() nos permiten conocer cuantas columnas y filas tienen los arrays en cada una de sus capas.

ncol(x)
## [1] 10
nrow(x)
## [1] 6
#ncol(z)
#nrow(z)

Como la función dim() nos dice las dimensiones de nuestro objeto, las funciones anteriores son equivalentes a lo siguiente:

# Número de filas
dim(z)[1]
## NULL
# Número de columnas
dim(z)[2]
## NULL
# Número de capas
dim(z)[3]
## NULL

Al igual que con los vectores, también podemos mandar a llamar las entradas del array indicando dentro de corchetes los índices. Si una dimensión se omite, R lo interpreta como que se piden todos los elementos de esa dimensión.

y[1,2]
## [1] 7
y[1,]
##  [1]  1  7 13 19 25 31 37 43 49 55
#Ejericio: Extrae la entrada (2,1,1) del arreglo z que creaste anteriormente.

Un array puede utilizar también otro array de índices, tanto para asignar un vector a una colección irregular de elementos de un array como para extraer una colección irregular de elementos.

indices <- array(c(1:6,1:6), dim=c(6,2))
indices
##      [,1] [,2]
## [1,]    1    1
## [2,]    2    2
## [3,]    3    3
## [4,]    4    4
## [5,]    5    5
## [6,]    6    6
# Asignamos el valor de 0 a las entradas dadas por el array indices
x[indices] <- 0
x
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,]    0    7   13   19   25   31   37   43   49    55
## [2,]    2    0   14   20   26   32   38   44   50    56
## [3,]    3    9    0   21   27   33   39   45   51    57
## [4,]    4   10   16    0   28   34   40   46   52    58
## [5,]    5   11   17   23    0   35   41   47   53    59
## [6,]    6   12   18   24   30    0   42   48   54    60

También podemos modificar manualmente las entradas del array de la siguiente forma.

x[5,7] <- 0; x[4,8]<- 0; x[3,9]<- 0; x[2,10] <- 0
x
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,]    0    7   13   19   25   31   37   43   49    55
## [2,]    2    0   14   20   26   32   38   44   50     0
## [3,]    3    9    0   21   27   33   39   45    0    57
## [4,]    4   10   16    0   28   34   40    0   52    58
## [5,]    5   11   17   23    0   35    0   47   53    59
## [6,]    6   12   18   24   30    0   42   48   54    60

La función which() nos ayuda a recuperar los índices de un array que cumplan alguna condición. Su sintaxis es which(object, arr.ind = FALSE), donde object es el objeto de donde se quiere recuperar los índices y arr.ind se cambia a TRUE si se requieren los índices multidimensionales.

which(x<1, arr.ind = TRUE)
##       row col
##  [1,]   1   1
##  [2,]   2   2
##  [3,]   3   3
##  [4,]   4   4
##  [5,]   5   5
##  [6,]   6   6
##  [7,]   5   7
##  [8,]   4   8
##  [9,]   3   9
## [10,]   2  10

Está función también se puede aplicar a vectores.

(Logaritmo<-log(c(1,-2,3)))
## Warning in log(c(1, -2, 3)): Se han producido NaNs
## [1] 0.000000      NaN 1.098612
which(Logaritmo=="NaN")
## [1] 2

Las funciones y operaciones de los arrays son similares a las de los vectores.

# Sacar raíz cuadrada de la columna 1 del vector x
raiz_x <- sqrt(x[,1])
raiz_x
## [1] 0.000000 1.414214 1.732051 2.000000 2.236068 2.449490
#Ejercicio: Cambiar la columna 3 del array x por sus cuadrados.

La función dimnames es similar a la función names() de los vectores. En el caso de arrays, dimnames será una lista que debe contener tantos vectores como dimensiones tenga el array.

mi_array <- array(c(1:12), dim=c(2,2,3),
                  dimnames = list(c("Gato","Perro"),
                                  c("Esterilizado", "No esterilizado"),
                                  c("Morelia", "Patzcuaro", "Maravatio")))
mi_array
## , , Morelia
## 
##       Esterilizado No esterilizado
## Gato             1               3
## Perro            2               4
## 
## , , Patzcuaro
## 
##       Esterilizado No esterilizado
## Gato             5               7
## Perro            6               8
## 
## , , Maravatio
## 
##       Esterilizado No esterilizado
## Gato             9              11
## Perro           10              12
# Obtener la cantidad de gatos no esterilizados en Morelia
mi_array[1,"No esterilizado", "Morelia"]
## [1] 3
mi_array["Perro",,c("Morelia","Patzcuaro","Maravatio")]
##                 Morelia Patzcuaro Maravatio
## Esterilizado          2         6        10
## No esterilizado       4         8        12
#Ejercicio: Cambia el nombre de la ciudad Maravatio por alguna otra.

Las funciones rbind() y cbind() sirven para combinar arrays vertical y horizontalmente.

mi_array1 <- array(c(1:6), dim = c(2,3))
mi_array2 <- array(c(7:18), dim = c(4,3))
mi_array3 <- array(c(19:29), dim = c(2,5))
rbind(mi_array1, mi_array2)
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
## [3,]    7   11   15
## [4,]    8   12   16
## [5,]    9   13   17
## [6,]   10   14   18
cbind(mi_array1, mi_array3)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## [1,]    1    3    5   19   21   23   25   27
## [2,]    2    4    6   20   22   24   26   28

2.5.3 Matrices

Las matrices son arreglos de dos dimensiones. Entonces, una forma de crear una matriz es usando la función array pero especificando una dimensión de la forma dim=c(x,y).

matriz1 <- array(c(1:9), dim = c(3,3))
matriz1
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

Otra forma de crear matrices es usando la función matrix() indicandole el número de columnas y/o filas.

##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
class(matriz1);class(matriz2)
## [1] "matrix" "array"
## [1] "matrix" "array"
matriz_ceros <- matrix(0, ncol=5, nrow=3)
matriz_ceros
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    0    0    0    0    0
## [2,]    0    0    0    0    0
## [3,]    0    0    0    0    0

Otro parámetro que podemos darle a la función matrix es byrow, el cual nos ayuda a llenar la matrix por filas.

matriz3 <- matrix(c(1:9), nrow = 3, byrow = TRUE)
matriz3
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9

Como las matrices son un tipo particular de los arreglos, las funciones como dimnames o extraer entradas y modificarlas funcionan de la misma forma.

#Ejercicio: Crea una matriz de tamaño 4x4 con números consecutivos ordenados 
#por filas y extrae la entrada (4,2).
#cambia los nombres de las filas y columnas por caracteres

Disponemos también de varias operaciones con matrices. La operación \(A\ast B\) donde \(A\), \(B\) son matrices en R se refiere a la multiplicación entrada a entrada, no a la multiplicación de matrices. Además esta multiplicación solo se puede realizar si se tiene el mismo número de filas y de columnas.

matriz2 * matriz3
##      [,1] [,2] [,3]
## [1,]    1    8   21
## [2,]    8   25   48
## [3,]   21   48   81

La suma y resta de matrices se refiere a sumar o restar dos matrices entrada a entrada, solo se puede realizar con matrices de las mismas dimensiones.

# Suma
matriz2 + matriz3
##      [,1] [,2] [,3]
## [1,]    2    6   10
## [2,]    6   10   14
## [3,]   10   14   18
# Resta
matriz2 - matriz3
##      [,1] [,2] [,3]
## [1,]    0    2    4
## [2,]   -2    0    2
## [3,]   -4   -2    0

El operador en R para realizar la multiplicación usual de matrices es %*%.

matriz2 %*% matriz3
##      [,1] [,2] [,3]
## [1,]   66   78   90
## [2,]   78   93  108
## [3,]   90  108  126

El operador t() se usa para calcular la transpuesta de una matriz.

t(matriz1)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9

2.5.3.1 Otras operaciones con Matrices

  • Crossproduct: es equivalente a t(A)%*% B o A %*% t(B). Las funciones que se usan son crossprod y tcrossprod respectivamente.
A <- matrix(c(10,8,5,12), ncol = 2, byrow = TRUE)
B <- matrix(c(5,3,15,6), ncol = 2, byrow = TRUE)
crossprod(A,B)
##      [,1] [,2]
## [1,]  125   60
## [2,]  220   96
tcrossprod(A,B)
##      [,1] [,2]
## [1,]   74  198
## [2,]   61  147
  • Producto exterior: El operador que se usa es %o% o la función outer().
A %o% B
## , , 1, 1
## 
##      [,1] [,2]
## [1,]   50   40
## [2,]   25   60
## 
## , , 2, 1
## 
##      [,1] [,2]
## [1,]  150  120
## [2,]   75  180
## 
## , , 1, 2
## 
##      [,1] [,2]
## [1,]   30   24
## [2,]   15   36
## 
## , , 2, 2
## 
##      [,1] [,2]
## [1,]   60   48
## [2,]   30   72
outer(A, B, FUN = "*")
## , , 1, 1
## 
##      [,1] [,2]
## [1,]   50   40
## [2,]   25   60
## 
## , , 2, 1
## 
##      [,1] [,2]
## [1,]  150  120
## [2,]   75  180
## 
## , , 1, 2
## 
##      [,1] [,2]
## [1,]   30   24
## [2,]   15   36
## 
## , , 2, 2
## 
##      [,1] [,2]
## [1,]   60   48
## [2,]   30   72
  • Producto Kronecker: si \(A\) y \(B\) son dos matrices, el producto de Kronecker se denota por $A B $ y en R el operador correspondiente es %x%.
A %x% B
##      [,1] [,2] [,3] [,4]
## [1,]   50   30   40   24
## [2,]  150   60  120   48
## [3,]   25   15   60   36
## [4,]   75   30  180   72
  • Potencia de una matriz: existen dos formas de realizarla. La primera es con el operador %^% del paquete expm. La segunda con la función matrix.power del paquete matrixcalc.
#install.packages("expm")
library(expm)
## Loading required package: Matrix
## 
## Attaching package: 'expm'
## The following object is masked from 'package:Matrix':
## 
##     expm
A %^% 2
##      [,1] [,2]
## [1,]  140  176
## [2,]  110  184
#install.packages("matrixcalc")
library(matrixcalc)
matrix.power(A,2)
##      [,1] [,2]
## [1,]  140  176
## [2,]  110  184
  • Determinante: la función de R que calcula el determinante de una matriz es det().
det(A)
## [1] 80
det(B)
## [1] -15
  • Inversa: para calcular la inversa de una matriz se usa la función solve().
solve(A)
##         [,1]   [,2]
## [1,]  0.1500 -0.100
## [2,] -0.0625  0.125
#Ejercicio: Verifica que efectivamente solve(A) es la inversa de la matriz A.

La función solve también nos ayuda a resolver un sistema de ecuaciones, por ejemplo si queremos resolver el sistema de ecuaciones \(AX = B\) lo podemos hacer de la siguiente manera.

solve(A, B)
##         [,1]    [,2]
## [1,] -0.7500 -0.1500
## [2,]  1.5625  0.5625
  • Rango: no existe una función base de R para calcular el rango pero se puede usar la función qr() que nos calcula la descomposición QR de una matriz y regresa también como argumento el rango de la matriz o la función rankMatrix del paquete Matrix.
qr(A)
## $qr
##             [,1]       [,2]
## [1,] -11.1803399 -12.521981
## [2,]   0.4472136   7.155418
## 
## $rank
## [1] 2
## 
## $qraux
## [1] 1.894427 7.155418
## 
## $pivot
## [1] 1 2
## 
## attr(,"class")
## [1] "qr"

Para solo pedir a R el rango de la matriz se hace uso del operador $ de la siguiente manera.

qr(A)$rank
## [1] 2
library(Matrix)
rankMatrix(A)[1]
## [1] 2
  • Matriz diagonal: La función diag() nos ayuda a extraer o reemplazar la diagonal de una matriz.
#extraer la diagonal
diag(A)
## [1] 10 12
# reemplazar la diagonal
#diag(A) <- c(0,2)

Si el argumento que se le da a la función diag es un vector, esto crea una matriz diagonal con las entradas del vector en la diagonal.

diag(c(1,2,3))
##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    2    0
## [3,]    0    0    3

Además, la función diag también nos permite crear una matriz identidad especificando solamente la dimensión de la matriz deseada.

diag(3)
##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    1    0
## [3,]    0    0    1
  • Eigenvalores y eigenvectores: la función de R que nos calcula tanto los eigenvalores como los eigenvectores es eigen().
eigen(A)
## eigen() decomposition
## $values
## [1] 17.403124  4.596876
## 
## $vectors
##            [,1]       [,2]
## [1,] -0.7339565 -0.8286986
## [2,] -0.6791964  0.5596952
#Para obtener solo los eigenvalores en orden decresiente 
#eigen(A)$values
#Para obtener solo los eigenvectores
#eigen(A)$vectors

2.5.4 Dataframes

Los dataframes o tablas de catos son un arreglo rectangular de datos y son los objetos más usados en R al momento de realizar análisis de datos. En los vectores, arreglos y matrices, todas las entradas tienen que ser el mismo tipo de dato pero en los dataframes no es necesario pero cada columna si debe de tener el mismo tipo de datos.

Para crear un dataframe usamos la función data.frame(), a diferencia de los arrays, uno debe especificar cada columna con su nombre. Los nombres de las columnas no deben de contener espacios.

mi_df <- data.frame(ciudad = c("Morelia", "Veracruz", "Merida"),
                    Temperatura = c(27, 26, 32),
                    Playa = c(FALSE, TRUE, FALSE))
mi_df
##     ciudad Temperatura Playa
## 1  Morelia          27 FALSE
## 2 Veracruz          26  TRUE
## 3   Merida          32 FALSE

Todas las columnas de un dataframe deben de tener la misma longitud. La función str()nos permite ver como están estructurados nuestros datos, no solamente un dataframe.

str(mi_df)
## 'data.frame':    3 obs. of  3 variables:
##  $ ciudad     : chr  "Morelia" "Veracruz" "Merida"
##  $ Temperatura: num  27 26 32
##  $ Playa      : logi  FALSE TRUE FALSE

En los dataframes, las filas también pueden tener un nombre, para darles nombre usamos la función row.names().

row.names(mi_df) <- c("A", "B", "C")
mi_df
##     ciudad Temperatura Playa
## A  Morelia          27 FALSE
## B Veracruz          26  TRUE
## C   Merida          32 FALSE

El comando row.names() se puede dar como atributo cuando se construye el dataframe.

mi_df <- data.frame(ciudad = c("Morelia", "Veracruz", "Merida"),
                    Temperatura = c(27, 26, 32),
                    Playa = c(FALSE, TRUE, FALSE),
                    row.names = c("A", "B", "C"))
mi_df
##     ciudad Temperatura Playa
## A  Morelia          27 FALSE
## B Veracruz          26  TRUE
## C   Merida          32 FALSE

Para acceder a los datos del dataframe es similar a la forma de los arreglos o vectores y además podemos mandar a llamar solo una columna usando el operador $.

mi_df$ciudad
## [1] "Morelia"  "Veracruz" "Merida"
mi_df[,2]
## [1] 27 26 32
mi_df[c("A","B"),]
##     ciudad Temperatura Playa
## A  Morelia          27 FALSE
## B Veracruz          26  TRUE
#Cambiar la temperatura de Veracruz
mi_df[2,2] <- 33
mi_df
##     ciudad Temperatura Playa
## A  Morelia          27 FALSE
## B Veracruz          33  TRUE
## C   Merida          32 FALSE

Una forma de modificar el nombre de una columna de nuestro dataframe es con la función names.

names(mi_df)[1] <- "Ciudad"
mi_df
##     Ciudad Temperatura Playa
## A  Morelia          27 FALSE
## B Veracruz          33  TRUE
## C   Merida          32 FALSE

Las funciones rbind cbind que usamos con los arreglos también se pueden usar para expandir los dataframes.

nuevo_df <- data.frame(c("Monterrey", "Cancún"), c(25, 28), c(FALSE, TRUE))
nuevo_df
##   c..Monterrey....Cancún.. c.25..28. c.FALSE..TRUE.
## 1                Monterrey        25          FALSE
## 2                   Cancún        28           TRUE
#rbind(mi_df, nuevo_df)

Al no tener los mismos nombres de columnas, no se puede usar rbind para combinarlos. Esto se puede solucionar cambiando los nombres del segundo dataframe.

colnames(nuevo_df)
## [1] "c..Monterrey....Cancún.." "c.25..28."               
## [3] "c.FALSE..TRUE."
colnames(nuevo_df) <- colnames(mi_df)
colnames(nuevo_df)
## [1] "Ciudad"      "Temperatura" "Playa"
rbind(mi_df, nuevo_df)
##      Ciudad Temperatura Playa
## A   Morelia          27 FALSE
## B  Veracruz          33  TRUE
## C    Merida          32 FALSE
## 1 Monterrey          25 FALSE
## 2    Cancún          28  TRUE

Con cbind no tenemos este problema ya que lo que hacemos es agregar columnas.

info_extra <- data.frame(Habitantes = c(849053, 8063000, 892363)) 
cbind(mi_df, info_extra)
##     Ciudad Temperatura Playa Habitantes
## A  Morelia          27 FALSE     849053
## B Veracruz          33  TRUE    8063000
## C   Merida          32 FALSE     892363

Otra forma de agregar una columna es con el operador $.

mi_df$Habitantes <- c(849053, 8063000, 892363)
mi_df
##     Ciudad Temperatura Playa Habitantes
## A  Morelia          27 FALSE     849053
## B Veracruz          33  TRUE    8063000
## C   Merida          32 FALSE     892363

El operador $ también nos sirve para eliminar una columna.

mi_df$Habitantes <- NULL
mi_df
##     Ciudad Temperatura Playa
## A  Morelia          27 FALSE
## B Veracruz          33  TRUE
## C   Merida          32 FALSE

Para guardar un dataframe usamos la función write.csv.

write.csv(mi_df, file = "data/municipios.csv", row.names = FALSE)

Para leer el csv que acabamos de guardar usamos la función reaf.csv.

municipios <- read.csv(file = "data/municipios.csv", stringsAsFactors = TRUE)
municipios
##     Ciudad Temperatura Playa
## 1  Morelia          27 FALSE
## 2 Veracruz          33  TRUE
## 3   Merida          32 FALSE
municipios$ciudad
## NULL

2.5.5 Listas

Las listas son objetos ordenados de una solo longitud y sus elementos pueden ser de distinto tipo, incluso otras listas. La función para crear listas es list().

mi_lista <- list(1,"a", TRUE)
mi_lista ; class(mi_lista) ; typeof(mi_lista)
## [[1]]
## [1] 1
## 
## [[2]]
## [1] "a"
## 
## [[3]]
## [1] TRUE
## [1] "list"
## [1] "list"

Para acceder a los elementos de una lista es similar a la de los vectores e incluso se le puede dar nombres a las entradas o modificarlos como con los vectores usando la función names().

mi_lista2 <- list(mi_vector = c(1,2,3,4),
                  mi_array = array(c(1:9),dim=c(3,3)),
                  mi_booleano = TRUE)
mi_lista2
## $mi_vector
## [1] 1 2 3 4
## 
## $mi_array
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
## 
## $mi_booleano
## [1] TRUE
names(mi_lista2)
## [1] "mi_vector"   "mi_array"    "mi_booleano"
names(mi_lista2)[3] = "mi_logico"
names(mi_lista2)
## [1] "mi_vector" "mi_array"  "mi_logico"

No es necesario que todas las entradas de la lista tengan los mismos nombres.

mi_lista3 <- list(c(1:3),letra = "a", c(TRUE,FALSE))
names(mi_lista3)
## [1] ""      "letra" ""

La función length() nos devuelve la dimensión de una lista.

length(mi_lista2) ; length(mi_lista3)
## [1] 3
## [1] 3

Con la función srt() podemos conocer la estructura de la lista.

str(mi_lista2)
## List of 3
##  $ mi_vector: num [1:4] 1 2 3 4
##  $ mi_array : int [1:3, 1:3] 1 2 3 4 5 6 7 8 9
##  $ mi_logico: logi TRUE

A diferencia de los vectores y arrays, en las listas contamos con dos niveles de indexado. Con dobles corchetes accedemos a los elementos de la lista, es decir [[n]] nos devuelve el elemento \(n\) de la lista y en caso de que se trate de un array, vector u otro objeto para acceder a los elementos de este objeto usamos otros corchetes, es decir objeto[[n]][p].

# Para acceder a la primera fila de la segunda entrada de la lista, la cual es 
# un array usamos:
mi_lista2[[2]][1,]
## [1] 1 4 7
class(mi_lista2[[2]])
## [1] "matrix" "array"
mi_lista2[2]
## $mi_array
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
class(mi_lista2[2])
## [1] "list"

Otra forma de acceder a los objetos de la lista es usando sus nombres o con el operador $ como en los dataframes.

mi_lista2["mi_vector"]
## $mi_vector
## [1] 1 2 3 4
mi_lista2[["mi_vector"]]
## [1] 1 2 3 4
mi_lista2$mi_array
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

Para añadir elementos a una lista debemos ser cuidadosos con los índices que usamos, si usamos [[k]] estaríamos añadiendo un objeto en la posición \(k\) de la lista y si usamos [[k]][j] estaríamos añadiendo el elemento \(j\) al objeto \(k\) de la lista.

mi_lista[[4]] <- c("a","b","c")
mi_lista
## [[1]]
## [1] 1
## 
## [[2]]
## [1] "a"
## 
## [[3]]
## [1] TRUE
## 
## [[4]]
## [1] "a" "b" "c"
mi_lista[[1]][2] <- 2
mi_lista
## [[1]]
## [1] 1 2
## 
## [[2]]
## [1] "a"
## 
## [[3]]
## [1] TRUE
## 
## [[4]]
## [1] "a" "b" "c"

Para eliminar elementos de una lista podemos asignar NULL a la posición de la lista, sin embargo esta asignación no hace diferencia de si usamos [[]], [] o $.

mi_lista4 <- list(c(1,2,3,4),array(c(1:4),dim = c(2,2)), c(TRUE,FALSE))
mi_lista4
## [[1]]
## [1] 1 2 3 4
## 
## [[2]]
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
## 
## [[3]]
## [1]  TRUE FALSE
mi_lista4[1] <- NULL
mi_lista4
## [[1]]
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
## 
## [[2]]
## [1]  TRUE FALSE
mi_lista4 <- list(c(1,2,3,4),array(c(1:4),dim = c(2,2)), c(TRUE,FALSE))
mi_lista4[[1]] <- NULL
mi_lista4
## [[1]]
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
## 
## [[2]]
## [1]  TRUE FALSE
mi_lista4 <- list(mi_vec = c(1,2,3,4),mi_array = array(c(1:4),dim = c(2,2)), mi_log = c(TRUE,FALSE))
mi_lista4[["mi_array"]] <- NULL
mi_lista4
## $mi_vec
## [1] 1 2 3 4
## 
## $mi_log
## [1]  TRUE FALSE
mi_lista4 <- list(mi_vec = c(1,2,3,4),mi_array = array(c(1:4),dim = c(2,2)), mi_log = c(TRUE,FALSE))
mi_lista4["mi_array"] <- NULL
mi_lista4
## $mi_vec
## [1] 1 2 3 4
## 
## $mi_log
## [1]  TRUE FALSE
mi_lista4 <- list(mi_vec = c(1,2,3,4),mi_array = array(c(1:4),dim = c(2,2)), mi_log = c(TRUE,FALSE))
mi_lista4$mi_array <- NULL
mi_lista4
## $mi_vec
## [1] 1 2 3 4
## 
## $mi_log
## [1]  TRUE FALSE
mi_lista4 <- list(mi_vec = c(1,2,3,4),mi_array = array(c(1:4),dim = c(2,2)), mi_log = c(TRUE,FALSE))
mi_lista4[c(1,3)] <- NULL
mi_lista4
## $mi_array
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
mi_lista4 <- list(mi_vec = c(1,2,3,4),mi_array = array(c(1:4),dim = c(2,2)), mi_log = c(TRUE,FALSE))
mi_lista4[-c(1,3)] 
## $mi_array
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4

Para combinar dos listas usamos el operador que se usa para concatenar vectores c().

lista1 <- list(c(1,2,3),c("a","b"))
lista2 <- list(array(c(1:4),dim=c(2,2)), c(TRUE,FALSE))
lista3 <- c(lista1, lista2)
lista3
## [[1]]
## [1] 1 2 3
## 
## [[2]]
## [1] "a" "b"
## 
## [[3]]
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
## 
## [[4]]
## [1]  TRUE FALSE
class(lista3)
## [1] "list"
#Ejercicio: Crea una lista y concatenala con la lista mi_lista3. Modifica la entrada 3,1 y el nombre de la entrada 2 de la lista.

2.5.6 Factores

Los factores nos ayudan a representar los niveles de los datos, pueden parecer caracteres pero en realidad son niveles. Por ejemplo, se pueden usar para representar el género, continentes, razas de algún animal, etc.

gatos <- c("Siames", "Calico", "Angora", "Carey")
str(gatos)
##  chr [1:4] "Siames" "Calico" "Angora" "Carey"
categorias_gatos <- factor(gatos)
class(categorias_gatos)
## [1] "factor"
str(categorias_gatos)
##  Factor w/ 4 levels "Angora","Calico",..: 4 2 1 3
typeof(gatos); typeof(categorias_gatos)
## [1] "character"
## [1] "integer"

Para conocer los niveles de nuestro objeto usamos la función levels() y cuantos niveles tenemos nlevels().

levels(categorias_gatos); nlevels(categorias_gatos)
## [1] "Angora" "Calico" "Carey"  "Siames"
## [1] 4

Los factores se ordenan alfabéticamente.

niveles <- c("alto", "medio", "bajo")
factor(niveles)
## [1] alto  medio bajo 
## Levels: alto bajo medio
factor(niveles, order = TRUE, levels = c("bajo", "medio", "alto"))
## [1] alto  medio bajo 
## Levels: bajo < medio < alto
niveles2 <- factor(niveles, order = TRUE, levels = c("bajo", "medio", "alto"))
niveles2; as.numeric(niveles2)
## [1] alto  medio bajo 
## Levels: bajo < medio < alto
## [1] 3 2 1

2.5.7 Atributos de objetos

Los atributos de los objetos los podemos obtener de la siguiente forma: - Modo: Cualquier tipo de entidad que maneja R, se usa la función mode(objeto). - Tipo: Tipo de dato: entero, caracter, double, etc. Se usa la función typeof(objeto). - Nombres: etiquetas de los elementos individuales de un vector o lista. Se usa la función names(objeto). - Dimensiones: Dimensión de los arreglos. Se usa la función dim(objeto). Esta función devuelve dos valores: el primero es el número de filas, el segundo el de columnas. - Dimnames: Nombres de las dimensiones de los arrays. Se usa la función dimnames(objeto). - Clase: Vector alfanumérico con la lista de las clases del objeto. Se usa la función class(objeto). - Longitud: Longitud de cualquier estructura. Se usa la función length(objeto).

typeof(mi_vector)
## [1] "character"

El operador ls() nos permite listar todas las variables y funciones de nuestro ambiente global, sin embargo los objetos que comienzan con . no son listados, para listar estas variables se utiliza ls(all.names = TRUE).

ls()
##  [1] "A"                  "B"                  "categorias_gatos"  
##  [4] "clases"             "gatos"              "indices"           
##  [7] "info_extra"         "lista1"             "lista2"            
## [10] "lista3"             "Logaritmo"          "matriz_ceros"      
## [13] "matriz1"            "matriz2"            "matriz3"           
## [16] "mi_array"           "mi_array1"          "mi_array2"         
## [19] "mi_array3"          "mi_df"              "mi_lista"          
## [22] "mi_lista2"          "mi_lista3"          "mi_lista4"         
## [25] "mi_vector"          "mi_vector2"         "mis_calificaciones"
## [28] "municipios"         "niveles"            "niveles2"          
## [31] "nuevo_df"           "raiz_x"             "w"                 
## [34] "workingDir"         "x"                  "y"                 
## [37] "z"

Para borrar un objeto usamos rm(objeto).

rm(mi_vector)

En el caso de querer eliminar todos los objetos de nuestro ambiente, usamos rm(list = ls() ). Es importante señalar que se debe usar el operador = para asignar al objeto list todos los objetos que estén en ls() en lugar del operador <-.

2.5.8 Ejercicios

  1. Crea una base de datos de los asistentes a la clase y dale el nombre estudiantes, almacena datos como nombre, edad, lugar de origen, grado, o algunos otros de tal forma que la base de datos tenga variables de todos los tipos, numéricos, factores, lógicos y caracteres.
  1. Usando la base de datos estudiantes, extrae las columnas de los estudiantes con edad mayor al promedio de las edades y aquellos estudiantes del mismo grado.
  2. Extrae las ciudades o regiones de aquellos estudiantes mayores a la edad promedio.
  3. Ordena la base de datos usando alguna variable cuantitativa.
  4. Crea una lisa con los elementos de la base de datos estudiantes y da un nombre a las entradas de la lista y accede a tu nombre y edad como subelementos de la lista.
  1. Usando la ayuda de R, busca como se pueden redondear los números \(2.5\), \(4.8\), \(9,2\). ¿Cuáles fueron los resultados de redondear? Ahora, trata de redondear a dos decimales los siguientes números: \(4.765\), \(3.231\), \(9.769\).

  2. Crea una vector con las letras A M A B M M B A B B, donde A significa Alto, B bajo y M medio. Convierte las entradas del vector a factores y especifica que A > M > B.

  3. Carga la base de datos CO2 del paquete datasets usando data("CO2"). Explora la base de datos y revisa que tipo de datos tiene cada columna.

  1. Calcula el promedio de las tasas de absorción de CO2 en Quebec (uptake).
  2. Obtén el máximo y mínimo de las concentraciones de CO2 para las plantas chilled.
  3. Para las plantas Ms2, ¿cuántos niveles de concentración ambiental de CO2 se midieron?.
  4. Para plantas non-chilled, cuando la concentración es 500, ¿cuáles son los niveles de absorción uptake?

2.6 Estructuras de control

Las estructuras de control se refieren a como hacemos que un algoritmo tome alguna decisión o camino dependiendo de las condiciones que se le especifiquen y realice ciclos o repeticiones.

Vamos a ver dos tipos de estructuras de control. La primera el condicional if donde ciertas instrucciones son ejecutadas dada la veracidad de la condición que actúa como un parámetro de control. La segunda se trata de los ciclos, los cuales repiten ciertas instrucciones varias veces, de este tipo de estructuras de control tenemos el ciclo for que se usa cuando las repeticiones se realizan un número fijo de veces (el parámetro de control) y el ciclo while cuando las iteraciones no se especifican a priori pero continua evaluándose mientras alguna condición no se alcance.

2.6.1 Condicional if

La palabra clave if siempre evalúa una expresión lógica y cuando dicha expresión de por resultado el valor TRUE, se ejecutará el código indicado a continuación del if entre llaves. En caso de que el resultado sea FALSE, ignorará lo que se encuentre inmediatamente del if entre llaves y continuará con la siguiente instrucción.

# if
if (condicion es TRUE) {
  instrucción
}

# if ... else
if (condicion es TRUE) {
  instrucción
} else {
  instruccion alternativa
}

# if ... else if ... else
if (condicion es TRUE) {
  instrucción
} else if (condicion es TRUE) {
  instruccion alternativa
} else {
  ultima condicion
}

Por ejemplo, vamos a crear una variable y asignarle un valor, después vamos imprimir en pantalla si la variable tiene cierto valor.

x <- 8

if (x >= 10) {
  print(" x es más grande o igual a 10")
}
x
## [1] 8

Como \(x\) no es más grande que 10, entonces no nos devuelve ningún mensaje.

x <- 8

if (x >= 10) {
  print(" x es más grande o igual a 10")
} else {
  print(" x es menor que 10")
}
## [1] " x es menor que 10"
x
## [1] 8

Para verificar varias condiciones podemos usar else if

x <- 8

if (x >= 10) {
  print(" x es más grande o igual a 10")
} else if (x > 5) {
  print("x es mayor que 5 pero menor que 10")
} else {
  print(" x es menor que 10")
}
## [1] "x es mayor que 5 pero menor que 10"
x
## [1] 8
edad <- readline(prompt = "Escribe tu edad:")

if (edad >= 30 ) {
  print("Tal vez tenemos la misma edad")
} else{
  print("Soy mayor que tu")
}
# Ejercicio: crea un ciclo if que pregunte un número y que devuelva el mensaje de si el número es positivo, negativo o cero.

También se pueden crear ciclos anidados.

dato_texto = readline(prompt="Ingresa un número: ")
dato  <- as.numeric(dato_texto)
if(is.na(dato) == FALSE){
    print('Es un número.')
    if(dato < 0){
        print('Es negativo.')
    } else if(dato > 0){
        print('Es positivo.')
    } else{
        print('Es cero')
    }
} else{
    print('No es un número.')
}
#Convierte el if anidado anterior en uno no anidado.

Existe una función adicional llamada ifelse(), la estructura de esta es ifelse(condicion is TRUE, instruccion1, instruccion alternativa).

x <- -2

ifelse(x < 0, "x es un número negativo", "x es un número positivo o cero")
## [1] "x es un número negativo"

Tres funciones que son de gran ayuda para verificar condiciones son all(), any(), which().

edades <- c(12, 11, 24, 30, 5, 27, 12)

all(edades >= 25) ; any(edades == 30); which(edades == 12)
## [1] FALSE
## [1] TRUE
## [1] 1 7

2.6.2 Ciclo for

La función for() realiza un bloque de códigos tantas veces como se indique un argumento. Los objetos de tipo iterable, es decir los que se pueden recorrer son los vectores y las listas. La sintaxis de un for es la siguiente:

for (contador in vector_indices){
  instrucciones a ejecutar
}

El vector de índices se define antes de las instrucciones entre {} o dentro de los (). Por ejemplo,

for (i in 1:10){
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10

Al terminar el ciclo for(), el valor de la varible i toma el último valor de la lista de índices.

i
## [1] 10

Vamos a crear un vector vacío y que después se rellene con la suma acumulativa de los enteros consecutivos en el vector.

vec <- c()
vec 
## NULL
s <- 0
for (i in 1:10){
  s <- s + i
  vec[i] <- s
}
vec
##  [1]  1  3  6 10 15 21 28 36 45 55
impares <- 2*(1:10)-1

for (i in impares){
  print(i)
}
## [1] 1
## [1] 3
## [1] 5
## [1] 7
## [1] 9
## [1] 11
## [1] 13
## [1] 15
## [1] 17
## [1] 19

También se pueden usar valores lógicos como sigue.

for (i in c(TRUE, FALSE, TRUE)){
  print(TRUE == i)
}
## [1] TRUE
## [1] FALSE
## [1] TRUE

Las estructuras de control se pueden combinar. Por ejemplo, vamos a crear un condicional con un for y un if que nos regrese el mensaje de si un estudiante alcanzó al menos 5 puntos en un examen.

puntos <- c(10,4, 6,2,4, 7, 5, 9, 8, 0)
for (puntaje in puntos){
  if (puntaje < 5 ){
    print("Reprobó")
  } else {
    print("Aprobó")
  }
}
## [1] "Aprobó"
## [1] "Reprobó"
## [1] "Aprobó"
## [1] "Reprobó"
## [1] "Reprobó"
## [1] "Aprobó"
## [1] "Aprobó"
## [1] "Aprobó"
## [1] "Aprobó"
## [1] "Reprobó"
# Ejercicio: crea un ciclo para calcular el factorial de un número.
# Hint: usa un if y un for anidados y define dos variables n<-número al cúal se le va a calcular el factorial y fac <- iniciala en 1 y esa será el resultado del factrorial de n.

2.6.3 Ciclo while

El ciclo while() se usa para realizar un bloque de código recursivamente mientras no se alcance cierta condición. Si el resultado de la evaluación es FALSE entonces no se realizará la instrucción. La estructura del condicional while() es como sigue.

while(expresion logica){
  instrucciones a ejecutar
}

El siguiente ejemplo imprime en pantalla un número mientras este no sea mayor a 10.

i <- 0
while (i < 10){
  print(c(i,"es menor a 10"))
  i <- i + 1
}
## [1] "0"             "es menor a 10"
## [1] "1"             "es menor a 10"
## [1] "2"             "es menor a 10"
## [1] "3"             "es menor a 10"
## [1] "4"             "es menor a 10"
## [1] "5"             "es menor a 10"
## [1] "6"             "es menor a 10"
## [1] "7"             "es menor a 10"
## [1] "8"             "es menor a 10"
## [1] "9"             "es menor a 10"

Igual que con el condicional for(), i es una variable que al finalizar el ciclo tiene el último valor con el que fue evaluada, en este caso:

i
## [1] 10

Se debe de tener cuidado de modificar el valor de la variable a iterar para no terminar con un condicional infinito.

i <- 0
while (i < 10){
  print(c(i,"es menor a 10"))
  #i <- i + 1
}

El siguiente ciclo nos devuelve el primer número cuyo cuadrado exceda el número dado.

num_dado <- 2023
numero <- 0
while (numero ^ 2 <= num_dado) {
  numero = numero + 1
}
numero
## [1] 45

Los while() se pueden emplear con caracteres.

frase <- "Hola a todos"
n=1
lista <- list()
while (n <= nchar(frase)) {
  lista[[n]] = list(recorridos = substr(frase,1, n), num_caracteres = n)
  n = n + 1
}
lista
## [[1]]
## [[1]]$recorridos
## [1] "H"
## 
## [[1]]$num_caracteres
## [1] 1
## 
## 
## [[2]]
## [[2]]$recorridos
## [1] "Ho"
## 
## [[2]]$num_caracteres
## [1] 2
## 
## 
## [[3]]
## [[3]]$recorridos
## [1] "Hol"
## 
## [[3]]$num_caracteres
## [1] 3
## 
## 
## [[4]]
## [[4]]$recorridos
## [1] "Hola"
## 
## [[4]]$num_caracteres
## [1] 4
## 
## 
## [[5]]
## [[5]]$recorridos
## [1] "Hola "
## 
## [[5]]$num_caracteres
## [1] 5
## 
## 
## [[6]]
## [[6]]$recorridos
## [1] "Hola a"
## 
## [[6]]$num_caracteres
## [1] 6
## 
## 
## [[7]]
## [[7]]$recorridos
## [1] "Hola a "
## 
## [[7]]$num_caracteres
## [1] 7
## 
## 
## [[8]]
## [[8]]$recorridos
## [1] "Hola a t"
## 
## [[8]]$num_caracteres
## [1] 8
## 
## 
## [[9]]
## [[9]]$recorridos
## [1] "Hola a to"
## 
## [[9]]$num_caracteres
## [1] 9
## 
## 
## [[10]]
## [[10]]$recorridos
## [1] "Hola a tod"
## 
## [[10]]$num_caracteres
## [1] 10
## 
## 
## [[11]]
## [[11]]$recorridos
## [1] "Hola a todo"
## 
## [[11]]$num_caracteres
## [1] 11
## 
## 
## [[12]]
## [[12]]$recorridos
## [1] "Hola a todos"
## 
## [[12]]$num_caracteres
## [1] 12

2.7 Funciones y Operadores

En R al igual que en otros lenguajes de programación podemos crear nuestras propias funciones.

La estructura de una función en R es la siguiente:

mi_funcion <- function(parametros){
  acciones
  resultado a regresar
}

Por ejemplo, supongamos que necesitamos calcular repetidamente el valor de la función \(f(x)=x^2/(x-1)\).

fx <- function(x){
  (x*x)/(x-1)
}

Entonces para evaluarla en algún número solo usamos la intrucción:

fx(5)
## [1] 6.25

Supongamos que dado un vector, queremos calcular la suma de sus entradas, restarle el elemento máximo y el mínimo.

mi_funcion <- function(vec){
  suma <- sum(vec)
  maximo <- max(vec)
  minimo <- min(vec)
  return(suma - maximo - minimo)
}

Aplicamos la función a un vector:

mi_funcion(c(1,3,6,8,9))
## [1] 17

En las funciones podemos indicar la operación a realizar como en el ejemplo uno o escribir la palabra reservada return para que nos regrese ese resultado.

Las funciones pueden recibir más de un parámetro como en el caso de funciones matemáticas en dos o más variables. Por ejemplo, supongamos que queremos crear la función \(g(x,y)= x^2 - y^2\).

gxy <- function(x,y) {
  x^2 -y^2
}
gxy(2,1)
## [1] 3

A las funciones también podemos pasarle parámetros opcionales como en otras funciones que ya hemos utilizado como matrix. Por ejemplo, supongamos que queremos crear una función que nos cree vectores o matrices dependiendo de los parámetros que le proporcionemos.

vec.mat <- function(a, b=2, flag = FALSE){
  if (flag){
    matrix(1:a, nrow = b)
  } else{
    1:a
  }
}

Por ejemplo, le podemos dar solo el parámetro a:

vec.mat(4)
## [1] 1 2 3 4

Y es lo mismo a indicar el parámetro a y flag=FALSE:

vec.mat(4, FALSE)
## [1] 1 2 3 4

En cambio, si cambiamos el parámetro de flag=TRUE:

vec.mat(8,4,TRUE)
##      [,1] [,2]
## [1,]    1    5
## [2,]    2    6
## [3,]    3    7
## [4,]    4    8

Si no queremos proporcionar el parámetro b pero si queremos una matriz debemos especificar que TRUE es el valor de flag:

vec.mat(8,flag=TRUE)
##      [,1] [,2] [,3] [,4]
## [1,]    1    3    5    7
## [2,]    2    4    6    8

Una función en R solo puede regresar un objeto pero si queremos que nos regrese más de un objeto podemos usar listas para almacenar los resultados.

elementos <- function(x) list(len=length(x),total=sum(x),
                          promedio=mean(x))
datos <- 1:10
elementos(datos)
## $len
## [1] 10
## 
## $total
## [1] 55
## 
## $promedio
## [1] 5.5
resultado <- elementos(datos)
names(resultado); resultado$len
## [1] "len"      "total"    "promedio"
## [1] 10

En el caso de que queramos obtener algún mensaje de error cuando el argumento de nuestra función no sea lo esperado podemos usar la función stop.

fxx <- function(x){
  if (!is.numeric(x)){
    stop("x debe ser un número")
  } 
  result <- (x*x)/(x-1)
  return(result)
}
fxx("a")

Otro argumento que funciona de forma similar a stop es stopifnot(), este se usa en el caso de que no se quieran verificar varias condiciones.

fxx <- function(x){
  stopifnot(is.numeric(x))
  result <- (x*x)/(x-1)
  return(result)
}
fxx("a")

2.7.1 Ejercicios

  1. Crea un vector que contenga los 7 días de la semana. Haz una función que dado un número del 1 al 7, imprima el día de la semana correspondiente.

  2. Crea una función que dado un número del 1 al 12 imprima el nombre del mes correspondiente.

  3. Crea una función que calcule las raices de un polinomio cuadrático.

  4. Considera la función

g <- function(x, y) x ^ 2 - y / 5

Aplícala a: g(1 : 2, 2 : 3) y g(1 : 4, 1 : 5). ¿Qué está realizando la función al aplicarla a datos?

  1. Escribe una función que tome cualquier dataframe con entradas numéricas y nos devuelva el mismo dataframe con un renglón con el promedio de cada columna.

2.8 Scripts

Un script es una colección de varias instrucciones de R escritas en un archivo. La extensión de los script en R es .r o .R. En los scripts podemos colocar comentarios, paquetes, instrucciones de tal forma que pueda ser ejecutado sin problemas. Para ejecutar un script usamos la instrucción source("nombre.R"), en caso de no estar el script en nuestro directorio de trabajo debemos fijarlo o poner la ruta completa al script.

Por ejemplo, vamos a crear un script llamado mi_script.R con dos variables y que calcule su producto. Para ejecutar el script vamos a escribir en la consola source("mi_script.R").

# Mi primer script

a = 5

b = 6

c = a*b

print(c)

Nota: Para desinstalar algún paquete o instalar un paquete indicando que se instalen todas las dependencias se realizar lo siguiente:

remove.packages(c("ggplot2"))
install.packages('ggplot2', dependencies = TRUE)