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 aSaludo
, ni aSALUDO
.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 valor20
de30
, 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 |