Capítulo 2 Introducción a R

2.1 Primeros pasos

Para interactuar con R se dispone de una potente línea de comandos y en un principio, la manera más sencilla de ver R es que puede ser usado como una calculadora:

Como sumar:

10+5 
## [1] 15

O dividir:

10/5 
## [1] 2

Sin embargo, su potencial va más allá…

Principalmente porque este documento ha sido diseñado en R y RMarkdown ;)

2.1.1 Establecer directorios de trabajo

Al ejecutar R, este establece un directorio de trabajo, es decir, establece una carpeta donde guardar los datos ejecutados en R, misma que será la carpeta que usara para buscar, leer y escribir los archivos (de ser requerido) durante la sesión (es decir, mientras se mantiene el programa abierto), por ello, para obtener el directorio de trabajo actual basta con usar el siguiente comando:

getwd()
## [1] "/home/frahik/Documentos/R-project/DiplomadoR"

Dicho directorio va a variar dependiendo del sistema, por ello, más de una vez será necesario modificar esta ruta, para lo cual se usara el comando setwd("Ruta"), el cual varía dependiendo del Sistema Operativo, como buena práctica del programador, se recomienda establecer el directorio de trabajado dentro de la carpeta de Documentos, además de que es más sencillo encontrar los proyectos de trabajo, si se usa la ruta ruta relativa y no la ruta física, si se requiere mover todos los archivos para trabajar en otra computadora, no se tendrá que volver a modificar todo el directorio de trabajo.

Ejemplo usando la Ruta relativa en Linux

setwd("~/Documentos/Curso") #Linux

Ejemplo usando la Ruta física y la ruta relativa en Windows

setwd("C:\\Usuario\\Documentos\\Curso") #MALA PRACTICA (Ruta física)
setwd("~/Curso") #BUENA PRACTICA (Ruta relativa del comando anterior)

2.1.2 Creación de objetos/variables

En R podemos crear y manipular objetos asignándole valores, cadenas de texto, funciones y un largo etc. Por ser el primer contacto con R, crearemos un objeto (izquierda del símbolo =), asignándole como valor la cadena de texto “Hola mundo”. Es importante aclarar que es necesario que se pongan dobles comillas " " o comillas simples ' ' al escribir una cadena de texto, de otra manera será interpretado como uno o varios objetos, ejemplo:

saludo = Hola
## Error in eval(expr, envir, enclos): objeto 'Hola' no encontrado

Por lo que, para insertar la cadena de texto “Hola mundo” en la variable saludo, se deberá hacer como se mencionó anteriormente:

saludo = "Hola mundo" 

Ahora para mostrar en consola lo que contiene la variable u objeto saludo, lo escribiremos tal cual y obtendremos una salida muy similar a la siguiente.

## [1] "Hola mundo"

NOTAS IMPORTANTES:

R es sensible a las MAYÚSCULAS y minúsculas, por lo que saludo no es igual a Saludo, ni a SALUDO.

R NO requiere explicitar que tipo de valores van a contener las variables,

Otra manera de asignar valores a las variables es mediante el símbolo <- que se compone de un menor que y el signo de menos.

x <- 10 + 5 

«Podemos ver a las variables como una persona, cada persona tiene su nombre para poder ser identificadas sobre el resto de las personas, pero bajo la manera de ordenar del lenguaje R, si dos personas quieren llamarse de la misma manera, la nueva persona tiene que ‘matar’ a la persona ya existente para poder tomar su lugar.»

Se recomienda incluir un espacio simple a cada lado del operador de asignación para incrementar la legibilidad. Pero NO coloques un espacio entre el < y el - que forman la flecha, recuerda que a pesar de estar compuesto por dos caracteres es un único símbolo.

Es posible reasignar un valor a la variable que hemos creado, así como reutilizar el valor de la variable para realizar un cálculo:

y <- x + 5 
y

Ahora reutilizaremos el valor de la variable y:

## [1] 20

Recuerde que aunque pareciera algo matemático, los símbolos <- y = no funcionan como un «igual», si no, como un «equivale a» o una «asignación», porque a partir de ese momento, el valor de la derecha se le asigna al de la izquierda.

2.1.3 Instalar librerías

Los paquetes en R, son como «Extensiones» y nos sirven para evitar reinventar la rueda, existen muchos paquetes disponibles en el CRAN de R o GitHub y para instalarlos basta un comando en la propia terminal de R:

Para paquetes oficiales de CRAN

install.packages("NombreDelPaquete")
library(NombreDelPaquete) #Para usar el paquete

Para paquetes de GitHub

install.packages("devtools") #Correr solo si no se tiene el paquete "devtools" instalado.
devtools::install_github("usuario/repositorio")

Al agregar nuevos paquetes podremos expandir el potencial de R y a la vez facilitarnos el trabajo de «hacerlo por nosotros mismos».

2.1.4 Ayuda y documentación

R Nos proporciona toda la documentación de sus paquetes, así que si se nos olvida para que funciona un comando o por que la función no hace lo que uno escribe, revisar la documentación podrá evitar que pases horas frente al ordenador buscando el «punto y coma» que te falta, cuando en R los códigos no lo llevan.

help(nombre)

Donde nombre puede ser cualquier función o librería instalada de R.

Ejemplos:

help(help)  #Sí, es posible
help(sum)   #Documentación de una función
help(slidify) #Documentación de un paquete

2.2 Clases de datos

Existen 4 tipos de clases de objetos con las que tendremos que trabajar en R, cada uno tiene sus ventajas y desventajas, así que se verá de manera detalla cómo crear cada uno de ellos, acceder a sus valores, así como posibles problemas.

2.2.1 Vector

Desde que empezamos con la variable saludo, estábamos trabajando con vectores, sin embargo, era un vector de índice 1, dado que en R no existen como en otros lenguajes las variables individuales, todas a las que se les asigna un valor o más, son tratados inicialmente como vectores.

La manera de representar un vector es de la siguiente forma:

Valor1 Valor2 Valor3 Valorn

Una forma de ver a los vectores, es como la fila de espera del banco, todos tienen un turno único, pero que puede ser transferible, por lo que si mando a llamar el primer turno, solo el cliente con ese turno será el que pasará a ventanilla, pero mientras, el cliente con turno 10, puede ser que esté guardando el lugar para un amigo y cuando el amigo llegue, el nuevo cliente sustituirá al actual cliente con el turno 10.

Una vez entendido el mensaje anterior, existen varias formas de declarar un vector de más de un valor, la manera más sencilla es a través de la función concatenar c(...); la cual es una función genérica que combina los valores separado por comas en un vector.

Ejemplos: Vector con varios datos y un NA:

vector <- c(1:9,NA,10:15)
vector
##  [1]  1  2  3  4  5  6  7  8  9 NA 10 11 12 13 14 15

Vector de nombres de personas:

vectorNombres <- c("Francisco","Claudia","Valeria","Fernando","Julia")
vectorNombres
## [1] "Francisco" "Claudia"   "Valeria"   "Fernando"  "Julia"

Vector con los datos de otros vectores:

vec1 <- 1
vec2 <- 20:30
vecFinal <- c(vec1,vec2)
vecFinal
##  [1]  1 20 21 22 23 24 25 26 27 28 29 30

Ya que hemos visto como se crea un vector ahora veremos cómo acceder y trabajar con los valores de un vector.

2.2.1.1 Acceder a uno o varios datos del vector.

Tenemos el siguiente vector que tiene almacenado el nombre de 6 clientes.

vector <- c("Francisco","Claudia","Valeria","Fernando","Julia", "Osval")
Francisco Claudia Valeria Fernando Julia Osval

En R a diferencia de otros lenguajes de programación como C o Java, los índices de un vector o una matriz siempre inician en 1 y no en 0 como en esos otros lenguajes, por lo que la tabla anterior se podría observar de la siguiente manera:

1 2 3 4 5 6
Francisco Claudia Valeria Fernando Julia Osval

Donde el primer índice, hace referencia al primer elemento del vector, el segundo índice al segundo elemento y así de manera consecutiva.

Por lo que para acceder a uno o varios elementos se pueden utilizar los siguientes códigos:

  • Un elemento en específico
vector[3]
## [1] "Valeria"
  • Varios elementos en secuencia.
vector[2:4]
## [1] "Claudia"  "Valeria"  "Fernando"
  • Un elemento especificado anteriormente.
n <- 3
vector[n]
## [1] "Valeria"
  • Varios elementos especificados
vector[c(1,2,5)]
## [1] "Francisco" "Claudia"   "Julia"
  • Todos los elementos, excluyendo uno específico.
vector[-3]
## [1] "Francisco" "Claudia"   "Fernando"  "Julia"     "Osval"
  • Todos los elementos, excluyendo varios.
vector[-c(4:6)]
## [1] "Francisco" "Claudia"   "Valeria"
  • Almacenar los datos extraídos en otra variable.
grupo1 <- vector[-c(4:6)]
grupo1
## [1] "Francisco" "Claudia"   "Valeria"
  • Modificar un elemento específico de un vector
vector[4] <-  "Alberto"
vector
## [1] "Francisco" "Claudia"   "Valeria"   "Alberto"   "Julia"     "Osval"
  • Modificar varios elementos de un vector
vector[4:6] <- NA
vector
## [1] "Francisco" "Claudia"   "Valeria"   NA          NA          NA
  • Encontrar las posiciones de los valores NA (Not Available) en un vector
is.na(vector)
## [1] FALSE FALSE FALSE  TRUE  TRUE  TRUE
  • Encontrar las posiciones de los valores que no sean NA en un vector
!is.na(vector)
## [1]  TRUE  TRUE  TRUE FALSE FALSE FALSE
  • Extraer los elementos de las posiciones en los que los valores NO son NA
which(!is.na(vector) == TRUE)
## [1] 1 2 3
# Alternativa
which(is.na(vector) == FALSE)
## [1] 1 2 3
  • Extraer las posiciones del vector que cumplan con una consulta
which(vector == "Francisco")
## [1] 1
  • Modificar las posiciones del vector que cumplan con una consulta
vector[which(vector == "Francisco")] <- "Francisco Javier"

2.2.1.2 Ordenar los datos de un vector

Para ordenar los datos existe la función sort(...).

  • Ordenar un vector de forma creciente
sort(vector)
## [1] "Claudia"          "Francisco Javier" "Valeria"
  • Ordenar un vector de forma decreciente
sort(vector, decreasing = T)
## [1] "Valeria"          "Francisco Javier" "Claudia"
  • Ordenar un vector y conocer sus antiguas posiciones.
sort(vector, decreasing = T, index.return = TRUE)
## $x
## [1] "Valeria"          "Francisco Javier" "Claudia"         
## 
## $ix
## [1] 3 1 2

Este último método retorna dos listas, la primera es $x que representa la lista de los valores ordenados y la segunda es $ix que representa las antiguas posiciones de los valores.

2.2.1.3 Tratar los datos de un vector

Tenemos un vector con los gastos de la última semana:

gastos <- c(150,120,300,250,400,380,100)

Que se pueden representar de la siguiente manera:

150 120 300 250 400 380 100

En R ya existen varias funciones para ser utilizadas, se mostrará el funcionamiento de algunas de ellas y otras más podrán ser encontradas en el Capítulo 5 (Apéndices).

  • El menor gasto en la semana
min(gastos)
## [1] 100
  • El mayor gasto en la semana
max(gastos)
## [1] 400
  • Obtener el promedio de gasto en la semana.
mean(gastos)
## [1] 242.8571
  • Obtener el total del gasto de la semana, (Sumar todos los elementos).
sum(gastos)
## [1] 1700
  • Obtener el total del gasto de una semana laboral (Lunes-Viernes), (Sumar elementos específicos)
sum(gastos[1:5])
## [1] 1220
  • Obtener la varianza del gasto semanal
var(gastos)
## [1] 15157.14
  • Obtener la desviación estándar del gasto semanal
sd(gastos)
## [1] 123.1143
  • Obtener un resumen de los datos
summary(gastos)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   100.0   135.0   250.0   242.9   340.0   400.0

Este último comando muestra mucha información de utilidad, el valor mínimo, el primer cuantil, la mediana, el promedio, el tercer cuantil y el valor máximo dentro del vector. Con el cuál, se puede ahorrar tiempo a que si se utiliza de manera separada como se ve en los primeros tres comandos.

2.2.1.4 Problemas comunes

2.2.1.4.1 Mayúsculas y minúsculas

Como ya se mencionó anteriormente, R es sensible a las Mayúsculas y Minúsculas, por lo que las funciones no funcionaran si se ponen total o parcialmente en Mayúsculas, para comprender esto veremos dos ejemplos:

Crear un vector: MAL [X]

vector <- C(1,2,3)
## Error in C(1, 2, 3): object not interpretable as a factor

BIEN [O]

vector <- c(1,2,3)

Sumar los datos de un vector: MAL [X]

vector <- c(1,2,3)
SUM(vector)
## Error in eval(expr, envir, enclos): no se pudo encontrar la función "SUM"

BIEN [O]

vector <- c(1,2,3)
sum(vector)
## [1] 6

2.2.2 Matriz

Para crear una matriz en R se utiliza la función

matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL)

Donde matrix() corresponde al nombre de la función y todo lo que está dentro de los paréntesis son los argumentos de dicha función.

Argumentos Significado del argumento
data Son los datos a ingresar en la matriz.
nrow Número deseado de filas.
ncol Número deseado de columnas.
byrow Valor lógico. Si es falso (valor por defecto), la matriz se llena por orden columna, de otra manera se llenará primero por filas.
dimnames Utilizado para darles nombres a las filas y a las columnas, respectivamente.

2.2.2.1 Crear una matriz

Algunos ejemplos de cómo crear una matriz:

  • Una matriz de NA de 5 * 5:
m <- matrix(NA, nrow = 5, ncol = 5)
  • Una matriz desde los datos de un vector:
vector <- c("Francisco", 500, "Alberto", 200, "Enrique", 650, "Juan", 300)
m <- matrix(vector, ncol = 2, byrow = T)
m
  • Una matriz desde los datos de dos o más vectores:
Nombre <- c("Francisco", "Alberto", "Enrique", "Juan")
Puntos <- c(500, 200, 650, 300)
m <- matrix(c(Nombre, Puntos), ncol = 2)
m
##      [,1]        [,2] 
## [1,] "Francisco" "500"
## [2,] "Alberto"   "200"
## [3,] "Enrique"   "650"
## [4,] "Juan"      "300"
  • Una matriz desde los datos de dos o más vectores con cbind:
Nombre <- c("Francisco", "Alberto", "Enrique", "Juan")
Puntos <- c(500, 200, 650, 300)
m <- cbind(Nombre, Puntos)
m
##      Nombre      Puntos
## [1,] "Francisco" "500" 
## [2,] "Alberto"   "200" 
## [3,] "Enrique"   "650" 
## [4,] "Juan"      "300"
  • Una matriz desde los datos de dos o más vectores con rbind:
Cliente1 <- c("Francisco", 500)
Cliente2 <- c("Alberto", 200)
Cliente3 <- c("Enrique",  650)
m <- rbind(Cliente1, Cliente2, Cliente3)
m
##          [,1]        [,2] 
## Cliente1 "Francisco" "500"
## Cliente2 "Alberto"   "200"
## Cliente3 "Enrique"   "650"

2.2.2.2 Trabajar con matrices

Continuaremos trabajando con la siguiente matriz, es necesario recordar que se puede llamar de cualquier forma, en este caso se llamará de manera genérica, matriz :

Nombre <- c("Francisco", "Alberto", "Enrique", "Juan", "Francisco", "Alberto", "Enrique", "Juan")
Puntos <- c(500, 200, 650, 300, 300, 350, 600, 400)
matriz <- cbind(Nombre, Puntos)
matriz
##      Nombre      Puntos
## [1,] "Francisco" "500" 
## [2,] "Alberto"   "200" 
## [3,] "Enrique"   "650" 
## [4,] "Juan"      "300" 
## [5,] "Francisco" "300" 
## [6,] "Alberto"   "350" 
## [7,] "Enrique"   "600" 
## [8,] "Juan"      "400"
  • Nombrar las columnas de la matriz
colnames(matriz) <- c("Cliente", "Puntos")
matriz
##      Cliente     Puntos
## [1,] "Francisco" "500" 
## [2,] "Alberto"   "200" 
## [3,] "Enrique"   "650" 
## [4,] "Juan"      "300" 
## [5,] "Francisco" "300" 
## [6,] "Alberto"   "350" 
## [7,] "Enrique"   "600" 
## [8,] "Juan"      "400"
  • Nombrar las filas de la matriz
rownames(matriz) <- c("Compra1", "Compra2", "Compra3", "Compra4", "Compra5", "Compra6", "Compra7", "Compra8")
matriz
##         Cliente     Puntos
## Compra1 "Francisco" "500" 
## Compra2 "Alberto"   "200" 
## Compra3 "Enrique"   "650" 
## Compra4 "Juan"      "300" 
## Compra5 "Francisco" "300" 
## Compra6 "Alberto"   "350" 
## Compra7 "Enrique"   "600" 
## Compra8 "Juan"      "400"
  • Nombrar las columnas y las filas de la matriz
dimnames(matriz) <- list(c("C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8"),c("Cliente", "Puntos"))
matriz
##    Cliente     Puntos
## C1 "Francisco" "500" 
## C2 "Alberto"   "200" 
## C3 "Enrique"   "650" 
## C4 "Juan"      "300" 
## C5 "Francisco" "300" 
## C6 "Alberto"   "350" 
## C7 "Enrique"   "600" 
## C8 "Juan"      "400"
  • Obtener los primeros valores de una matriz (tres en este caso):
head(matriz,3)
##    Cliente     Puntos
## C1 "Francisco" "500" 
## C2 "Alberto"   "200" 
## C3 "Enrique"   "650"
  • Obtener los últimos valores de una matriz (tres en este caso):
tail(matriz,3)
##    Cliente   Puntos
## C6 "Alberto" "350" 
## C7 "Enrique" "600" 
## C8 "Juan"    "400"
  • Obtener los nombres de los clientes:
matriz[,1]
##          C1          C2          C3          C4          C5          C6 
## "Francisco"   "Alberto"   "Enrique"      "Juan" "Francisco"   "Alberto" 
##          C7          C8 
##   "Enrique"      "Juan"
  • Obtener los nombres ordenados:
sort(matriz[,1])
##          C2          C6          C3          C7          C1          C5 
##   "Alberto"   "Alberto"   "Enrique"   "Enrique" "Francisco" "Francisco" 
##          C4          C8 
##      "Juan"      "Juan"
  • Obtener los nombres de los clientes sin repetir:
unique(matriz[,1])
## [1] "Francisco" "Alberto"   "Enrique"   "Juan"
  • Obtener los nombres de los clientes sin repetir y ordenados:
sort(unique(matriz[,1]))
## [1] "Alberto"   "Enrique"   "Francisco" "Juan"
  • Obtener la matriz ordenada según la cantidad de Puntos (ascendente):
matriz[order(matriz[, 2]), ]
##    Cliente     Puntos
## C2 "Alberto"   "200" 
## C4 "Juan"      "300" 
## C5 "Francisco" "300" 
## C6 "Alberto"   "350" 
## C8 "Juan"      "400" 
## C1 "Francisco" "500" 
## C7 "Enrique"   "600" 
## C3 "Enrique"   "650"
  • Obtener la matriz ordenada según la cantidad de Puntos (descendente):
matriz[order(matriz[, 2], decreasing = TRUE), ]
##    Cliente     Puntos
## C3 "Enrique"   "650" 
## C7 "Enrique"   "600" 
## C1 "Francisco" "500" 
## C8 "Juan"      "400" 
## C6 "Alberto"   "350" 
## C4 "Juan"      "300" 
## C5 "Francisco" "300" 
## C2 "Alberto"   "200"

Note que la matriz NO queda ordena debido a que los datos están saliendo a consola, si buscamos que se queden ordenados, tendríamos que asignarlos a la variable misma o en su defecto a una nueva variable, por ejemplo, matriz <- matriz[order(matriz[, 2], decreasing = TRUE), ].

  • Obtener al primer cliente y sus puntos:
matriz[1,]
##     Cliente      Puntos 
## "Francisco"       "500"
  • Obtener la suma de los puntos (ver problemas comunes):
sum(as.numeric(matriz[,2]))
## [1] 3300

2.2.2.3 Problemas comunes

Estos son algunos de los problemas más comunes al momento de intentar trabajar con una matriz:

2.2.2.3.1 No puedo hacer la suma de números.

Es ocasiones R tiende a asignar nuestros datos de otra forma que no es la que nosotros esperamos, en este caso tenemos el siguiente error:

sum(matriz[,2])
## Error in sum(matriz[, 2]): 'type' (character) de argumento no válido

El error que retorna R es que el tipo ‘character’ no es un argumento válido, esto significa que los datos que nosotros ingresamos son del tipo carácter, para comprobar esto, usaremos la función typeof(…):

typeof(matriz[,2])
## [1] "character"

Se puede observar que efectivamente, los datos que intentamos ingresar R los tiene almacenados como tipo carácter, por lo que, para poder sumar los datos utilizaremos la función as.numeric (existen otras funciones como as.integer, as.double() que también podrían funcionar):

typeof(as.numeric(matriz[,2]))
## [1] "double"
sum(as.numeric(matriz[,2]))
## [1] 3300
2.2.2.3.2 Los nombres en dimnames(...) no concuerdan con las dimensiones de la matriz.

Al intentar nombrar una matriz, puede surgir este tipo de errores al usar la función dimnames(...):

dimnames(matriz) <- list(c("Cliente", "Puntos"),
                         c("C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8"))
## Error in dimnames(matriz) <- list(c("Cliente", "Puntos"), c("C1", "C2", : la longitud de 'dimnames' [1] no es igual a la extensión del arreglo

El error en está ocasión se debe a que estamos intentar poner los nombres de las columnas en las filas y viceversa, así que cambiando el orden de los vectores de nombres es suficiente para que funcione:

dimnames(matriz) <- list(c("C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8"),
                         c("Cliente", "Puntos"))
matriz
##    Cliente     Puntos
## C1 "Francisco" "500" 
## C2 "Alberto"   "200" 
## C3 "Enrique"   "650" 
## C4 "Juan"      "300" 
## C5 "Francisco" "300" 
## C6 "Alberto"   "350" 
## C7 "Enrique"   "600" 
## C8 "Juan"      "400"

Pero ¿Qué pasa si no se busca nombrar las filas o las columnas?, lo recomendable sería usar las funciones respectivas colnames(...) o rownames(...).

2.2.2.3.3 Los datos no concuerdan con las dimensiones de la matriz

Tenemos los siguientes vectores:

Cliente <- c("Francisco", "Alberto", "Juan")
Puntos <- c(10,2030)

Observe que el vector Puntos a pesar de que le faltó una coma para separar el valor 20 de 30, R lo sigue tomando como válido por que no rompe con la sintaxis del código, sin embargo, esto nos causará problemas más adelante.

Ahora intentaremos crear una matriz con esos datos:

matriz <- matrix(c(Cliente, Puntos), ncol=2)
## Warning in matrix(c(Cliente, Puntos), ncol = 2): la longitud de los datos
## [5] no es un submúltiplo o múltiplo del número de filas [3] en la matriz
matriz
##      [,1]        [,2]       
## [1,] "Francisco" "10"       
## [2,] "Alberto"   "2030"     
## [3,] "Juan"      "Francisco"

¿Qué pasó?, al no tener los datos completos, al querer crear una matriz de dos columnas por el tamaño del vector (en este caso, el más largo) no coinciden los datos ingresados (5 datos) con el “espacio disponible” en la matriz (6 datos), por lo que, el primer valor se repite para llenar el vació.

La solución consiste en agregar la coma que nos hizo falta en el primer vector e intentar de nuevo.

Otro problema puede ser que, supongamos que tenemos un vector en secuencia del 1 hasta el 31 y queremos representar solo el mes de mayo del 2017

vector <- 1:31
matrix(vector, nrow = 5, ncol=7, byrow=T)
## Warning in matrix(vector, nrow = 5, ncol = 7, byrow = T): la longitud de
## los datos [31] no es un submúltiplo o múltiplo del número de filas [5] en
## la matriz
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,]    1    2    3    4    5    6    7
## [2,]    8    9   10   11   12   13   14
## [3,]   15   16   17   18   19   20   21
## [4,]   22   23   24   25   26   27   28
## [5,]   29   30   31    1    2    3    4

Vemos que R nos ha devuelto un error que nos indica que el vector de datos no es un submúltiplo o múltiplo del número de filas y columnas de la matriz, en otras palabras, la matriz es de 5 renglones por 7 columnas, es decir, tendrá un espacio para ingresar 35 valores y nosotros estamos ingresando solo 31, por lo que R intentará completar la matriz repitiendo el vector hasta completar los 35 valores. Si nosotros no queremos que suceda esto debemos de completar la cantidad de datos, existen varias maneras de solucionar este problema, este es uno de varias de ellas:

vector <- 1:31
matrix(
    c(vector, NA, NA, NA, NA),
    nrow = 5,
    ncol = 7,
    byrow = T
)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,]    1    2    3    4    5    6    7
## [2,]    8    9   10   11   12   13   14
## [3,]   15   16   17   18   19   20   21
## [4,]   22   23   24   25   26   27   28
## [5,]   29   30   31   NA   NA   NA   NA

Lo que sucede aquí es que al vector le agregamos 4 valores NA que significa que no están disponibles y ahora tenemos un vector de longitud 35, la cual entra exactamente en la matriz de 5*7.

2.2.3 Data Frame

Los dataframes, son una clase parecida a las matrices, sin embargo, poseen determinadas características que las hacen más útiles en ciertas ocasiones.

Al igual que los vectores y matrices, existen varias formas de crear data frames, una forma sencilla de crearlos es especificar los datos de las columnas como en el ejemplo siguiente:

data.frame(
    columna1 = 1,
    columna2 = 1:5,
    columnay = LETTERS[1:5],
    z = runif(5)
)
##   columna1 columna2 columnay          z
## 1        1        1        A 0.71004536
## 2        1        2        B 0.93508764
## 3        1        3        C 0.18977092
## 4        1        4        D 0.01928205
## 5        1        5        E 0.99139633

2.2.3.1 Crear un Data frame

  • Crear un data frame a partir de varios vectores:
vec1 <- c("Francisco", "Alberto", "Enrique", "Juan")
vec2 <- c(500, 200, 650, 300)

datos <- data.frame(Clientes = vec1, Puntos = vec2)
datos
##    Clientes Puntos
## 1 Francisco    500
## 2   Alberto    200
## 3   Enrique    650
## 4      Juan    300
  • Crear un data frame a partir de una matriz:
Nombre <- c("Francisco", "Alberto", "Enrique", "Juan")
Puntos <- c(500, 200, 650, 300)
m <- matrix(c(Nombre, Puntos), ncol = 2)
datos <- as.data.frame(m)
datos
##          V1  V2
## 1 Francisco 500
## 2   Alberto 200
## 3   Enrique 650
## 4      Juan 300

2.2.3.2 Trabajar con Data frames

Continuaremos trabajando con el siguiente data frame, es necesario recordar que se puede llamar de cualquier forma, en este caso se llamará de manera genérica, df :

Nombre <- c("Francisco", "Alberto", "Enrique", "Juan", "Francisco", "Alberto", "Enrique", "Juan")
Puntos <- c(500, 200, 650, 300, 300, 350, 600, 400)
df <- data.frame(Clientes = Nombre, Puntos = Puntos) 
df
##    Clientes Puntos
## 1 Francisco    500
## 2   Alberto    200
## 3   Enrique    650
## 4      Juan    300
## 5 Francisco    300
## 6   Alberto    350
## 7   Enrique    600
## 8      Juan    400
  • Nombrar las columnas del data frame
colnames(df) <- c("Cliente", "Puntuación")
df
##     Cliente Puntuación
## 1 Francisco        500
## 2   Alberto        200
## 3   Enrique        650
## 4      Juan        300
## 5 Francisco        300
## 6   Alberto        350
## 7   Enrique        600
## 8      Juan        400
  • Nombrar las filas del data frame
rownames(df) <- c("C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8")
df
##      Cliente Puntuación
## C1 Francisco        500
## C2   Alberto        200
## C3   Enrique        650
## C4      Juan        300
## C5 Francisco        300
## C6   Alberto        350
## C7   Enrique        600
## C8      Juan        400
  • Nombrar las columnas y las filas de la matriz
dimnames(df) <- list(c("C-1", "C-2", "C-3", "C-4", "C-5", "C-6", "C-7", "C-8"),c("Cliente", "Puntos"))
df
##       Cliente Puntos
## C-1 Francisco    500
## C-2   Alberto    200
## C-3   Enrique    650
## C-4      Juan    300
## C-5 Francisco    300
## C-6   Alberto    350
## C-7   Enrique    600
## C-8      Juan    400
  • Obtener los primeros valores de un data frame (tres en este caso):
head(df,3)
##       Cliente Puntos
## C-1 Francisco    500
## C-2   Alberto    200
## C-3   Enrique    650
  • Obtener los últimos valores de una matriz (tres en este caso):
tail(df,3)
##     Cliente Puntos
## C-6 Alberto    350
## C-7 Enrique    600
## C-8    Juan    400
  • Obtener los nombres de los clientes:
df$Cliente
## [1] Francisco Alberto   Enrique   Juan      Francisco Alberto   Enrique  
## [8] Juan     
## Levels: Alberto Enrique Francisco Juan

Una alternativa poco recomendada

df[,1]
## [1] Francisco Alberto   Enrique   Juan      Francisco Alberto   Enrique  
## [8] Juan     
## Levels: Alberto Enrique Francisco Juan
  • Obtener los nombres ordenados:
sort(df$Cliente)
## [1] Alberto   Alberto   Enrique   Enrique   Francisco Francisco Juan     
## [8] Juan     
## Levels: Alberto Enrique Francisco Juan
  • Obtener los nombres de los clientes sin repetir:
unique(df$Cliente)
## [1] Francisco Alberto   Enrique   Juan     
## Levels: Alberto Enrique Francisco Juan
  • Obtener los nombres de los clientes sin repetir y ordenados:
sort(unique(df$Cliente))
## [1] Alberto   Enrique   Francisco Juan     
## Levels: Alberto Enrique Francisco Juan
  • Obtener el dataframe ordenado según la cantidad de Puntos (ascendente):
df[order(df$Puntos), ]
##       Cliente Puntos
## C-2   Alberto    200
## C-4      Juan    300
## C-5 Francisco    300
## C-6   Alberto    350
## C-8      Juan    400
## C-1 Francisco    500
## C-7   Enrique    600
## C-3   Enrique    650
  • Obtener el dataframe ordenado según la cantidad de Puntos (descendente):
df[order(df$Puntos, decreasing = TRUE), ]
##       Cliente Puntos
## C-3   Enrique    650
## C-7   Enrique    600
## C-1 Francisco    500
## C-8      Juan    400
## C-6   Alberto    350
## C-4      Juan    300
## C-5 Francisco    300
## C-2   Alberto    200

Note que el data frame NO queda ordena debido a que los datos están saliendo a consola, si buscamos que se queden ordenados, tendríamos que asignarlos a la variable misma o en su defecto a una nueva variable, por ejemplo, df <- df[order(df$Puntos, decreasing = TRUE), ].

  • Obtener al primer cliente y sus puntos:
df[1,]
##       Cliente Puntos
## C-1 Francisco    500
  • Obtener la suma de los puntos:
sum(df$Puntos)
## [1] 3300

2.2.4 Lista

Hasta ahora hemos visto vectores, matrices y data frames para organizar la información dentro del entorno de R. Existe otro tipo de clase que también será de utilidad, en R la clase list (lista) y es parecido a un vector, sin embargo, dentro de ella puede contener varios objetos, donde cada objeto puede ser de un tipo diferente.

Debido a la flexibilidad de las listas, su estructura permite crear e integrar objetos de esta clase con suma facilidad, así que no es raro encontrar listas dentro de otras listas.

2.2.4.1 Crear una lista

Observe que para crear una lista, es necesario usar la función list(...), donde cada parámetro que se ingrese será parte de un índice.

Recordando la forma de ver de un vector, era como la fila del banco, una lista es como tren, donde en cada vagón tiene una cantidad finita \(n\) de objetos de la misma clase, en el primer vagón puede estar \(x\) materia prima sin procesar, en el segundó vagón puede estar algo similar o algún otro tipo de cargamento y así sucesivamente.

lista <- list(1:10, c("A", "B", "C"))
lista
## [[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## [[2]]
## [1] "A" "B" "C"

En este caso, para saber lo que contiene cada vagón, usaremos el doble corchete [[i]] donde i representa un número de los “vagones” de la lista.

lista[[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
lista[[2]]
## [1] "A" "B" "C"

También es posible crear listas nombradas, es decir para facilitar el acceso e interacción, las listas pueden tener nombres para sus objetos (O sus “vagones”" haciendo referencia a la explicación pasada).

Tren <- list(vagon1 = 1:10, vagon2 = c("A", "B", "C"))

Ahora el acceso a la lista nombrada “Tren”, se vuelve más sencilla

Tren$vagon1
##  [1]  1  2  3  4  5  6  7  8  9 10
Tren$vagon2
## [1] "A" "B" "C"

2.2.4.2 Trabajar con listas

  • Para conocer la cantidad de elementos (vagones) en la lista:
length(lista)
## [1] 2

El caso es el mismo para una lista nombrada:

length(Tren)
## [1] 2
  • Para conocer la cantidad de objetos dentro de un elemento (vagón) en la lista:
length(lista[[1]])
## [1] 10

Y para la lista nombrada se puede acceder la misma manera que en una lista no nombrada o a través de su nombre:

length(Tren[[1]])
## [1] 10
length(Tren$vagon1)
## [1] 10
  • Acceder a un elemento específico dentro de un índice de la lista:
lista[[1]][5]
## [1] 5

O lo que es equivalente en una lista nombrada:

Tren$vagon1[5]
## [1] 5
  • Añadir más elementos a la lista:
lista[[3]] <- c(10, 20, 30, 40, 50)
lista
## [[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## [[2]]
## [1] "A" "B" "C"
## 
## [[3]]
## [1] 10 20 30 40 50

O en una lista nombrada

Tren$vagon3 <- c(10, 20, 30, 40, 50)
Tren
## $vagon1
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## $vagon2
## [1] "A" "B" "C"
## 
## $vagon3
## [1] 10 20 30 40 50
  • Modificar un nombre (o agregar un nombre en caso de que no tenga):
names(lista)[1] <- "vagon1"
lista
## $vagon1
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## $<NA>
## [1] "A" "B" "C"
## 
## $<NA>
## [1] 10 20 30 40 50
  • Modificar todos los nombres (o agregarle nombres en caso de que no tenga):
names(lista) <- c("vagon1", "vagon2", "vagon3")
lista
## $vagon1
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## $vagon2
## [1] "A" "B" "C"
## 
## $vagon3
## [1] 10 20 30 40 50

2.3 Manejo de datos

2.3.1 Salvar datos

En algún momento, tendremos la necesidad de guardar o leer algo en un formato determinado, sea .csv o .Rdata, veamos unos ejemplos que podrán ser de utilidad.

2.3.1.1 CSV (Comma-separated values)

Un formato muy utilizado en R aparte de los .RData (que son archivos especiales de R), para exportar los datos en dicho formato:

df = data.frame(runif(10), runif(10), runif(10)) 
names(df) = c("dato1", "dato2", "dato3")

write.table(df, file = "dataframe1.csv", sep = ",",
            col.names = NA, qmethod = "double") 

En caso de que no se quisiera exportar el nombre de las filas, basta con modificar un poco el código, como en el siguiente ejemplo:

write.table(df, file = "dataframe2.csv", sep = ",",
            row.names = FALSE, qmethod = "double")

2.3.1.2 .RData

Si tienes objetos que te gustaría guardar como tal para luego procesarlos o simplemente se te hace más sencillo comprenderlo sobre un .csv, los comandos serán los siguientes:

foo = "bar"
save(foo, file="nombre.RData")

2.3.2 Leer datos

2.3.2.1 CSV

read.table("dataframe1.csv", header = TRUE, sep = ",",
           row.names = 1) 

Y si no se quieren importar los nombres de las filas optaremos por el siguiente comando:

read.table("dataframe2.csv", header = TRUE, sep = ",")

Aunque, la forma más sencilla de importar un .csv es a través del comando read.csv(...), cuya implementación es la siguiente:

read.csv(file, header = TRUE, sep = ",", dec = ".", ...)

Dónde:

Argumentos Significado o uso
file Ruta al archivo, en caso de estar en el mismo directorio de trabajo poner solo el nombre del archivo, de otro modo ingresar la ruta completa
header Valor lógico para determinar si el archivo incluye encabezados en la primera línea.
sep Este campo sirve para especificar el carácter de separación.
dec El carácter usado para los puntos decimales
... Ver la documentación para argumentos extras

Un ejemplo seria el siguiente:

csv <- read.csv("dataframe1.csv")

2.3.2.2 .RData

Para volver a cargar los datos:

load("nombre.RData")

Para llamar el objeto, basta con volver a introducir su variable, que, aunque no haya sido creada antes de usar la función load(), esta se encarga de crear el objeto y asignarle el valor que decidimos guardar en un principio, ver 2.3.1.2.

foo
## [1] "bar"
2.3.2.2.1 Problemas comunes
2.3.2.2.1.1 Error al cargar los datos

R marca un error sobre los datos se tratan de cargar no existen pero yo veo que sí existen en mi carpeta.

Lo más probable es que el directorio de trabajo de R no sea el mismo que donde están los datos, la función getwd() sirve para revisar cuál es el directorio de trabajo actual, será necesario revisar nuevamente los primeros pasos de esté capitulo para corregir el problema con el directorio de trabajo.

2.3.2.2.1.2 ¿Dónde están los datos?

Cuando se utilizan las funciones read.table(...) o load(...) utilizan la ruta del directorio de trabajo actual para guardar los datos, es decir, que si esa ruta apunta a tus documentos, los datos se guardaran en esa carpeta, será necesario revisar nuevamente los primeros pasos de esté capitulo para ver cómo funciona el directorio de trabajo.

2.3.2.2.1.3 ¿Cuáles son los datos que cargué con .RData?

Si por algún motivo se desconoce cuáles son los datos que se están cargando (No vienen documentados de alguna manera, etc.), la función load(...) incluye el parámetro verbose que por default el FALSE, pero si cambiamos dicho parámetro a TRUE, nos dirá que el nombre del objeto que estamos cargando al entorno de R, así podremos llamarlo y ver qué es lo que contiene.

load("nombre.RData", verbose = TRUE)
## Loading objects:
##   foo
foo
## [1] "bar"

2.4 Tratamiento de datos

Es momento de empezar a trabajar los datos para poder obtener más información sobre ellos, R incluye funciones bastante útiles, los cuales se pueden encontrar al final de documento, por el momento, conoceremos más sobre la función apply.

2.4.1 Función Apply

La función apply(...) permite realizar un cálculo (como el promedio) por fila ó por columna (sin importar si es una matriz o un dataframe), el resultado de dicha operación será un vector de longitud \(p\) con el resultado de la operación realizada, ya sea por filas o por columnas.

Su implementación es la siguiente:

apply(X, MARGIN, FUN)

Donde apply() corresponde al nombre de la función y todo lo que está dentro de los paréntesis son los argumentos de dicha función.

Argumentos Significado
X Es el vector o matriz original
MARGIN Indica donde se aplicara la función (1 indica fila, 2 indica columna)
FUN Es la función a aplicar (Suma, promedio, entre muchas otras)

Para ver un ejemplo, crearemos una matriz con 9 valores y sacaremos el promedio por columna.

x <- matrix(data = 1:9, nrow=3, ncol=3, byrow = TRUE)
x
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9
apply(x,2,mean)
## [1] 4 5 6

El argumento 2 en apply(x,2,mean) indica que el cálculo del promedio debe realizarse en la segunda dimensión, es decir, en las columnas.

2.4.2 Libreria dplyr

Dicha librería no se encuentra instalada por defecto en R para instalarla, como se vio en los primeros pasos de este capítulo, se usará el comando:

install.packages("dplyr")

Para aprender a usar esta librería usaremos el comando:

Y utilizaremos los siguientes datos:

v1 <- c("Perro", "Gato", "Lagarto", "Orca", "Águila", "Jirafa")
v2 <- c("Mamífero", "Mamífero", "Reptil", "Mamífero", "Ave", "Mamífero")
v3 <- c("Carnívoro", "Carnívoro", "Carnívoro", "Carnívoro", "Carnívoro", "Herbívoro")
v4 <- c(20,15,25,29,20,25)
Animales <- data.frame(Nombre = v1, Especie = v2, Alimentacion = v3, Tiempo_Vida = v4)

Los datos se detallan a continuación:

Nombre Especie Alimentacion Tiempo_Vida
Perro Mamífero Carnívoro 20
Gato Mamífero Carnívoro 15
Lagarto Reptil Carnívoro 25
Orca Mamífero Carnívoro 29
Águila Ave Carnívoro 20
Jirafa Mamífero Herbívoro 25

2.4.3 Filtrar datos

filter() permite seleccionar una serie de filas en un data frame, el primer argumento es el nombre del data frame (en este caso Animales), el segundo y resto de los argumentos son las expresiones a filtrar en el data frame:

Por ejemplo, filtraremos por los animales mamíferos:

Mamiferos <- filter(Animales, Especie == "Mamífero") 
Mamiferos
Nombre Especie Alimentacion Tiempo_Vida
Perro Mamífero Carnívoro 20
Gato Mamífero Carnívoro 15
Orca Mamífero Carnívoro 29
Jirafa Mamífero Herbívoro 25

Ahora filtraremos por los animales mamíferos y reptiles que sean carnívoros y tengan un tiempo de vida mayor a 19 años:

filtrados <- filter(Animales, Especie == "Mamífero" | Especie == "Reptil", Alimentacion == "Carnívoro", Tiempo_Vida > 19) 
filtrados
Nombre Especie Alimentacion Tiempo_Vida
Perro Mamífero Carnívoro 20
Lagarto Reptil Carnívoro 25
Orca Mamífero Carnívoro 29

Para seleccionar datos por su posición dplyr provee la función slice(...)

Por ejemplo, seleccionaremos los primeros dos animales.

seleccionados <- slice(Animales, 1:2)
seleccionados
Nombre Especie Alimentacion Tiempo_Vida
Perro Mamífero Carnívoro 20
Gato Mamífero Carnívoro 15

2.4.4 Ordenar datos

La función arrange(...) funciona de manera similar a filter(...) solo que, en vez de filtrar los datos, los ordena.

Por ejemplo, ordenaremos los animales por su especie y luego por su tiempo de vida

ordenados <-  arrange(Animales, Especie, Tiempo_Vida)
ordenados
Nombre Especie Alimentacion Tiempo_Vida
Águila Ave Carnívoro 20
Gato Mamífero Carnívoro 15
Perro Mamífero Carnívoro 20
Jirafa Mamífero Herbívoro 25
Orca Mamífero Carnívoro 29
Lagarto Reptil Carnívoro 25

Para ordenarlos de manera descendente usaremos la función desc(...)

ordenados <-  arrange(Animales, Especie, desc(Tiempo_Vida))
ordenados
Nombre Especie Alimentacion Tiempo_Vida
Águila Ave Carnívoro 20
Orca Mamífero Carnívoro 29
Jirafa Mamífero Herbívoro 25
Perro Mamífero Carnívoro 20
Gato Mamífero Carnívoro 15
Lagarto Reptil Carnívoro 25

2.4.5 Seleccionar columnas específicas

De manera seguida tendremos que trabajar con grandes cantidades de datos con varias columnas, pero en el momento, solo algunas podrán ser de tu interés la función select(...) permite un rápido trabajo para seleccionar dichas columnas, por ejemplo, queremos conocer el tiempo de vida de cada animal, entonces:

Tiempo_vida_por_Animal <- select(Animales, Nombre, Tiempo_Vida)
Tiempo_vida_por_Animal
Nombre Tiempo_Vida
Perro 20
Gato 15
Lagarto 25
Orca 29
Águila 20
Jirafa 25

2.4.6 Renombrar una columna

Para renombrar una columna, la librería dplyr provee también una útil función llamada rename(...), con ella cambiaremos el nombre de la columna Nombre del data frame Animales por Animal:

Animales <- rename(Animales, Animal = Nombre)
Animales
Animal Especie Alimentacion Tiempo_Vida
Perro Mamífero Carnívoro 20
Gato Mamífero Carnívoro 15
Lagarto Reptil Carnívoro 25
Orca Mamífero Carnívoro 29
Águila Ave Carnívoro 20
Jirafa Mamífero Herbívoro 25

2.4.7 Extraer los valores únicos

Otra útil función dentro de esta librería es la función distinct(...) que encuentra los valores distintos en una tabla, por ejemplo las Especies de los animales:

Especies <- distinct(Animales, Especie)
Especies
##    Especie
## 1 Mamífero
## 2   Reptil
## 3      Ave

O también las especies y alimentación

Especie_Alimentacion <- distinct(Animales, Especie, Alimentacion)
Especie_Alimentacion
Especie Alimentacion
Mamífero Carnívoro
Reptil Carnívoro
Ave Carnívoro
Mamífero Herbívoro

2.4.8 Agregar nuevas columnas

Es posible modificar las columnas existentes o agregar nuevas columnas con la función mutate(...) de la librería dplyr, por ejemplo, agregaremos dos años al tiempo de vida de los animales y añadiremos también otra columna con datos NA.

Animales2 <- mutate(Animales, Tiempo_Vida = Tiempo_Vida + 2, Otra_Columna = NA)
Animales2
Animal Especie Alimentacion Tiempo_Vida Otra_Columna
Perro Mamífero Carnívoro 22 NA
Gato Mamífero Carnívoro 17 NA
Lagarto Reptil Carnívoro 27 NA
Orca Mamífero Carnívoro 31 NA
Águila Ave Carnívoro 22 NA
Jirafa Mamífero Herbívoro 27 NA

2.4.9 Procesar datos

La función summarise(...). Colapsa un data frame en una fila, por ejemplo el tiempo de vida en promedio de los animales.

Vida_Promedio <- summarise(Animales, Tiempo_Vida = mean(Tiempo_Vida, na.rm = TRUE))
Vida_Promedio
##   Tiempo_Vida
## 1    22.33333

2.4.9.1 Datos agrupados

group_by(...) aunque no modifica los datos, sirve para trabajar en conjunto con la función summarise(...), por ejemplo, el tiempo de vida promedio entre las especies.

Agrupados <- group_by(Animales, Especie)
Especie_Vida_Promedio <- summarise(Agrupados, Tiempo_Vida = mean(Tiempo_Vida, na.rm = TRUE))
Especie_Vida_Promedio
Especie Tiempo_Vida
Ave 20.00
Mamífero 22.25
Reptil 25.00

O el tiempo de vida en promedio por Especie y su alimentación:

Agrupados <- group_by(Animales, Especie, Alimentacion)
EspecieAlimentacion_Vida_Promedio <- summarise(Agrupados, Tiempo_Vida = mean(Tiempo_Vida, na.rm = TRUE))
EspecieAlimentacion_Vida_Promedio
Especie Alimentacion Tiempo_Vida
Ave Carnívoro 20.00000
Mamífero Carnívoro 21.33333
Mamífero Herbívoro 25.00000
Reptil Carnívoro 25.00000