Capítulo 1 Introducción a objetos
Cuando hablamos de fundamentos de R nos referimos a toda la base necesaria y fundamental para, sobre ello, construir las técnicas propias del análisis de datos.
Vamos a empezar desarrollando conceptos en esta unidad y las siguientes hasta poder resolver esta primera problemática:
Queremos mudarnos de Perú a Estados Unidos y no sabemos a qué estado. Nuestra decisión estará basada únicamente en qué tan peligroso es el estado al que nos mudaremos.
Como se dan cuenta, no podemos tomar una decisión sin siquiera saber de dónde extraemos la data. La data en R que más utilizaremos estará almacenada en objetos, como por ejemplo variables, funciones o data frames.
1.1 Variables
En R no necesitamos declarar una variable, sino directamente asignarle un valor. Por ejemplo, creemos la variables: x
, y
, variable_3
y asignémosle los valores 3, 6, 4 respectivamente. Recuerda seleccionar todas las líneas de tu código antes de correr tu Script (click en Run).
Al ejecutar/correr tu Script verás en la sección consola tu Script ejecutado, pero ningún valor impreso. En la sección Environment/History verás que ya tus variables han sido creadas y qué valor tienen.
Como ves, R nos permite asignar un valor utilizando el símbolo <-
Para ver el valor o el resultado de una operación tenemos que, además de asignarle un valor, llamar a la variable que queremos observar.
Por ejemplo, calculemos y mostremos en pantalla el valor de esta resta: y - x
.
1.2 Funciones
R nos provee ya un conjunto de funciones que nos facilitan los cálculos. Algunos tan conocidos como la raíz cuadrada de un número:
Como se puede observar, tenemos que usar el nombre de la función, en este caso sqrt
y entre paréntesis el valor que queremos evaluar usando esta función.
Podemos usar una función y dentro de los paréntesis colocar una variable:
#Creamos la variable x con el valor 25 y la variable y con el valor de 36
x <- 25
y <- 36
#Calculando raíz cuadrada de ambos números:
sqrt(x)
#> [1] 5
sqrt(y)
#> [1] 6
Para crear una función utilizaremos la función llamada function()
. Por ejemplo, creemos la función que sume dos números x
y y
.
1.2.1 Funciones anidadas
Esto implica que podemos colocar entre paréntesis de una función otra función y otra dentro. Siempre se evaluará desde adentro hacia fuera. Por ejemplo, si queremos calcular la raíz cuadrada de 100 y luego al resultado queremos volver a aplicar la raíz cuadrada:
1.2.2 Manual de funciones
Para las funciones que vienen incluidas en R podemos obtener un manual de uso utilizando el símbolo ?
antes de la función. Por ejemplo, si ejecutamos este código podemos tener el manual para la función logaritmo:
Para ciertas funcines se pide más de una variable entre paréntesis. Si olvidamos los campos podemos utilizar la función args
para ver los argumentos, lo esperado por la función:
Aquí vemos que el segundo argumento tiene un =
. Eso quiere decir que ya está seteado por defecto y no es obligatorio llenarlo. Así, la función calcula logaritmo en base natural:
Sin embargo, podemos cambiar la base de esta forma:
1.3 Ejercicios
Para todos los ejercicios de los libros tendremos no solo las preguntas y respuestas, sino también píldoras de conocimiento que serán de utilidad para resolver los ejercicios.
Píldora: Si queremos calcular la suma de los n primeros números enteros, podemos hacerlo utilizando la siguiente formula: \(\frac{n(n+1)}{2}\)
- Calcula la suma de los números del 1 al 30.
- Define la variable
n
y asígnale el valor de 30. Luego calcula la suma de los 30 primeros números enteros.
- Cambia el valor de
n
y ahora calcula la suma de los primeros 100 enteros.
Píldora: Para ciertos logarítmos ya existe la fórmula directa en vez de especificar la base. Por ejemplo, la fórmula
log2(x)
calcula el logaritmo en base 2 de un númerox
. Con la misma idea podemos usarlog10(x)
.
- Calcula el logaritmo en base 2 de 32
Solución
- Calcula la raíz cuadrada del logaritmo en base 2 de 32
Solución
- Calcula el logaritmo en base 10 de la raíz cuadrada de 100.
Solución
1.4 Vectores
También podemos crear y manipular arreglos o listados de datos. Estos son conocidos como vectores.
Para crear vectores vamos a utilizar la función c
que significa concatenar. Así, si queremos crear un vector llamado distritos podemos hacerlo de la siguiente forma:
En este caso, dado que estamos ingresando caracteres los ingresamos entre comillas. Pero podemos crear vectores de otro tipo de datos. Por ejemplo, numéricos:
Si queremos saber la cantidad de datos que tiene nuestro vector, su longitud, usaremos la función length()
.
Además, la función class
que nos indica la clase del objeto, representando qué tipo de datos son almacenados en el objeto a analizar. Por ejemplo:
Existen vectores de caracteres, numéricos, lógicos (verdadero y falso), de factores, etc.
Ahora que tenemos el vector distritos
con la relación de 3 distritos y el vector poblacion
que indica su respectiva población, podemos utilizar el vector distritos como cabecera del vector población con la función names
:
distritos <- c("Lince", "Comas", "San Isidro")
poblacion <- c(52123, 464745, 55309)
names(poblacion) <- distritos
poblacion
#> Lince Comas San Isidro
#> 52123 464745 55309
Con esto, el vector población sigue siendo numérico, pero con cabeceras. Si bien los vectores aceptan palabras con espacios en el medio (p.ej. “San Isidro”), utilizaremos únicamente cabeceras sin espacios o con guiónes bajo.
1.4.1 Coerción de vectores
A diferencia de los lenguajes de programación orientados a software, R busca intepretar o cambiar un valor cuando encuentra un error. Esto se entiende más con un ejemplo. Vamos a crear el siguiente vector:
Esto nos crea un un vector de caracteres, puesto que todo está entre comillas. Aun así a este vector podemos aplicarle la función as.numeric()
para convertir los datos a números.
ejemplo <- c("3", "b", "6", "a", "puente", "4")
as.numeric(ejemplo)
#> Warning: NAs introduced by coercion
#> [1] 3 NA 6 NA NA 4
R convierte lo que puede y por coerción reemplaza lo que no puede convertir, y sería en otros lenguajes un error, colocando el valor NA
. Como data scientist es muy común que encuentres NA
insertados por coerción. Por eso es importante entendenrlo y estar preparados para verlo seguido.
1.4.2 Ordenamiento de vectores
Para ordenar los datos de un vector, por ejemplo un vector de distritos, usaremos la función sort()
:
distritos <- c("Comas", "Lince", "Miraflores", "Lurigancho", "Chorrillos")
sort(distritos)
#> [1] "Chorrillos" "Comas" "Lince" "Lurigancho" "Miraflores"
1.4.2.1 Ordenar usando índices
Así mismo, podemos acceder a los datos de un vector a través de sus índices. Por el siguiente código nos daría el primero y cuarto elementos del vector:
# Calculando el 1er distrito del vector, Comas:
distritos[1]
#> [1] "Comas"
# Calculando el 4to distrito del vector, Lurigancho:
distritos[4]
#> [1] "Lurigancho"
Dentro de los corchetes podemos pedir que nos muestre más de un valor. Para ello tendríamos que ingresar en los corchetes un vector numérico. Miremos el mismo ejemplo pero ingresando un vector numérico aux
para obtener ahora el quinto elemento:
distritos <- c("Comas", "Lince", "Miraflores", "Lurigancho", "Chorrillos")
aux <- c(5)
distritos[aux]
#> [1] "Chorrillos"
Nuestro vector numérico ahora nos muestra el quinto valor, pero podemos agregar más valores. Este código nos muestra cómo extraer el 5to y el 3er valor:
distritos <- c("Comas", "Lince", "Miraflores", "Lurigancho", "Chorrillos")
aux <- c(5, 3)
distritos[aux]
#> [1] "Chorrillos" "Miraflores"
Si colocamos todos los índices disponibles de la siguiente forma obtendremos la cadena ordenada manualmente de menor a mayor (alfabéticamente en el caso de caracteres) utilizando índices:
distritos <- c("Comas", "Lince", "Miraflores", "Lurigancho", "Chorrillos")
aux <- c(5, 1, 2, 4, 3)
distritos[aux]
#> [1] "Chorrillos" "Comas" "Lince" "Lurigancho" "Miraflores"
Esto nos ha permitido ordenar utilizando índices, pero lo hemos hecho observando hasta determinar que el 5to valor (Chorrillos) es el que debería de ir primero por ser el menor (orden alfabético), el 1er valor (Comas) debería de después, etc.
Podemos utilizar, en cambio, la función order()
para no tener que hacerlo manualmente:
distritos <- c("Comas", "Lince", "Miraflores", "Lurigancho", "Chorrillos")
aux <- order(distritos)
distritos[aux]
#> [1] "Chorrillos" "Comas" "Lince" "Lurigancho" "Miraflores"
La función order toma como argumento un vector y devuelve un vector numérico con los índices ordenados del vector agumento.
Hay que tener en cuenta que la función order
no ha cambiado para nada el vector. Se pueden percatar al ejecutar ambos:
# Este es nuestro vector original
distritos
#> [1] "Comas" "Lince" "Miraflores" "Lurigancho" "Chorrillos"
# Este es nuestro vector ordenado por índices
distritos[aux]
#> [1] "Chorrillos" "Comas" "Lince" "Lurigancho" "Miraflores"
Nuestro vector distritos sigue desordenado y el vector distritos[aux] lo muestra ordenado de menor a mayor.
1.4.3 NA en vectores
Como vimos anteriormente, encontraremos muchas veces NA
s en vectores en R. Para ver qué pasa si no los filtramos calcularemos el promedio de números del siguiente vector con la función mean()
:
Vemos que nos arroja otro NA
en vez de calcular el promedio de los otros valores del vector. Es importante, entonces saber cómo detectarlos y filtrarlos. Para detectar cuáles son NA
, R nos da la función is.na()
.
ejemplo_na <- c(28, 3, 19, NA, 89, 45, NA, 86, 5, 18, 28, NA)
is.na(ejemplo_na)
#> [1] FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE
Esta función nos arroja un vector lógico (verdadero o falso) indicando TRUE
si es que el valor es NA.
Dado que nos importa cuántos valor NO son NA, utilizaremos la negación de la función con el símbolo: !
ejemplo_na <- c(28, 3, 19, NA, 89, 45, NA, 86, 5, 18, 28, NA)
!is.na(ejemplo_na)
#> [1] TRUE TRUE TRUE FALSE TRUE TRUE FALSE TRUE TRUE TRUE TRUE FALSE
Podemos utilizar índices para extraer únicamente los valores numéricos del vector de esta forma:
ejemplo_na <- c(28, 3, 19, NA, 89, 45, NA, 86, 5, 18, 28, NA)
ejemplo_na[!is.na(ejemplo_na)]
#> [1] 28 3 19 89 45 86 5 18 28
Cuando colocamos un vector lógico dentro de los corchetes, solos nos mostrará los valores donde encuentra TRUE
.
Ahora sí, que ya filtramos a los NA
ya podemos calcular el promedio de los valores:
1.5 Ejercicios
- Crea un vector llamado
presidentes
con los nombres de los últimos 3 presidentes del Perú.
- Crea un vector llamado
inicio
con 3 valores que indiquen en qué año se convirtieron en presidentes c/u de los del ejercicio anterior.
Solución
- Relaciona los dos vectores creados anteriormente colocando al vector
inicio
las cabeceras creadas en el vectorpresidentes
.
Solución
- Crea el vector n <- c(34, 53, “hola”, 12). Luego, coerciona el vector a valores numéricos.
1.6 Data frames
Para entender un data frame podemos imaginarnoslo como una tabla en excel con varias columnas y varias filas donde puedes encontrar números, letras, etc. De hecho, si importamos datos directamente de un .csv se importan por defecto en un objeto de tipo data frame. Para ello podemos utilizar la función read.csv()
.
Para explorar la estructura de un objeto usaremos la función str()
.
str(data)
#> 'data.frame': 21 obs. of 9 variables:
#> $ inicio: Factor w/ 1 level "03/05/2020": 1 1 1 1 1 1 1 1 1 1 ...
#> $ genero: Factor w/ 2 levels "hombre","mujer": 2 1 2 1 1 1 1 1 1 1 ...
#> $ tipo : Factor w/ 1 level "Trabajo individual 1": 1 1 1 1 1 1 1 1 1 1 ...
#> $ P1 : int 5 5 5 5 2 5 2 5 4 3 ...
#> $ P2 : int 5 5 5 5 5 4 1 5 5 4 ...
#> $ P3 : int 5 5 4 5 5 5 5 5 5 5 ...
#> $ P4 : int 5 5 5 5 5 1 5 5 5 5 ...
#> $ P5 : int 5 4 5 5 5 5 2 5 5 5 ...
#> $ P6 : int 5 5 5 5 5 5 5 5 5 5 ...
También podemos encontrar paquetes donde encontraremos data frames con data lista para ser analizada. Recordemos nuestro problema inicial: > Queremos mudarnos de Perú a Estados Unidos y la decisión estará basada en qué tan peligroso es el estado al que nos mudaremos.
Un data frame que nos ayude a tomar esta decisión listaría todos los estados dentro de Estados Unidos, así como el total de asesinatos de algún determinado año.
Existe un data frame disponible con data del 2010, el cual contiene la data de asesinados con armas de fuego en EEUU en ese año y es la data que tomaremos como referencia para resolver nuestro caso/problemática. Para acceder al mismo, tenemos que instalar el paquete donde se encuentra la librería que contiene ese data frame de esta forma:
# Instalamos el paquete "dslabs":
install.packages("dslabs")
# Luego hacemos un llamado a la librería dslabs para acceder a lo cargado por el paquete:
library(dslabs)
# El data frame que buscamos se llama: murders (asesinatos en inglés)
data(murders)
str(murders)
#> 'data.frame': 51 obs. of 5 variables:
#> $ state : chr "Alabama" "Alaska" "Arizona" "Arkansas" ...
#> $ abb : chr "AL" "AK" "AZ" "AR" ...
#> $ region : Factor w/ 4 levels "Northeast","South",..: 2 4 4 2 4 4 1 2 2 2 ...
#> $ population: num 4779736 710231 6392017 2915918 37253956 ...
#> $ total : num 135 19 232 93 1257 ...
En este caso nos muestra que es un data frame con 51 filas y 5 columas:
- state: lista todos los estados de Estados Unidos
- abb: es el nombre abreviado de cada Estado
- region: es la región, puede estar al Sur, Oeste, Este, etc
- population: población de cada Estado
- total: total de asesinatos del año pasado
Podemos explorar las primeras filas de este data frame usando la función head(x)
, donde x
puede ser data frame, o también podría ser un vector, tabla, etc.
head(murders)
#> state abb region population total
#> 1 Alabama AL South 4779736 135
#> 2 Alaska AK West 710231 19
#> 3 Arizona AZ West 6392017 232
#> 4 Arkansas AR South 2915918 93
#> 5 California CA West 37253956 1257
#> 6 Colorado CO West 5029196 65
1.6.1 Extrayendo datos de un data frame
Ya hemos leído el data frame, pero para analizarlo tenemos que poder acceder a los datos. La manera que más utilizaremos en esta etapa será utilizando el símbolo $
.
Como nuestro problema es determinar a qué estado nos mudaremos, lo primero que haremos será acceder a ver el listado de todos los estados (primera columna de nuestro data frame):
murders$state
#> [1] "Alabama" "Alaska" "Arizona"
#> [4] "Arkansas" "California" "Colorado"
#> [7] "Connecticut" "Delaware" "District of Columbia"
#> [10] "Florida" "Georgia" "Hawaii"
#> [13] "Idaho" "Illinois" "Indiana"
#> [16] "Iowa" "Kansas" "Kentucky"
#> [19] "Louisiana" "Maine" "Maryland"
#> [22] "Massachusetts" "Michigan" "Minnesota"
#> [25] "Mississippi" "Missouri" "Montana"
#> [28] "Nebraska" "Nevada" "New Hampshire"
#> [31] "New Jersey" "New Mexico" "New York"
#> [34] "North Carolina" "North Dakota" "Ohio"
#> [37] "Oklahoma" "Oregon" "Pennsylvania"
#> [40] "Rhode Island" "South Carolina" "South Dakota"
#> [43] "Tennessee" "Texas" "Utah"
#> [46] "Vermont" "Virginia" "Washington"
#> [49] "West Virginia" "Wisconsin" "Wyoming"
Los números entre corchetes no los usaremos. Solo tenlos como referencia porque te indican el orden. Por ejemplo, el primer valor en la columna es “Alabama”, el 10mo valor en la columna es “Florida”, etc.
El resultado obtenido no es un solo dato, sino un listado de datos (un vector). Como estamos interesados en el estado con el mayor número de delitos ordenaremos utilizando la columna total
:
indices <- order(murders$total)
indices
#> [1] 46 35 30 51 12 42 20 13 27 40 2 16 45 49 28 38 8 24 17 6 32 29 4 48 7
#> [26] 50 9 37 18 22 25 1 15 41 43 3 31 47 34 21 36 26 19 14 11 23 39 33 10 44
#> [51] 5
Tenemos un listado de índices. El número 46
indica que en la fila 46 se encuentra el valor mínimo del vector. En la fila 35
se encuentra el siguiente valor, etc.
Ahora utilizamos estos índices para mostrar otra columna estado (state
), utilizando los índices del total
:
indices <- order(murders$total)
murders$state[indices]
#> [1] "Vermont" "North Dakota" "New Hampshire"
#> [4] "Wyoming" "Hawaii" "South Dakota"
#> [7] "Maine" "Idaho" "Montana"
#> [10] "Rhode Island" "Alaska" "Iowa"
#> [13] "Utah" "West Virginia" "Nebraska"
#> [16] "Oregon" "Delaware" "Minnesota"
#> [19] "Kansas" "Colorado" "New Mexico"
#> [22] "Nevada" "Arkansas" "Washington"
#> [25] "Connecticut" "Wisconsin" "District of Columbia"
#> [28] "Oklahoma" "Kentucky" "Massachusetts"
#> [31] "Mississippi" "Alabama" "Indiana"
#> [34] "South Carolina" "Tennessee" "Arizona"
#> [37] "New Jersey" "Virginia" "North Carolina"
#> [40] "Maryland" "Ohio" "Missouri"
#> [43] "Louisiana" "Illinois" "Georgia"
#> [46] "Michigan" "Pennsylvania" "New York"
#> [49] "Florida" "Texas" "California"
Esto nos indica que el estado de Vermont es el que reportó menor número de asesinatos, mientras que California fue el estado que reportó mayor número de estos delitos.
1.7 Ejercicios
- Accede a la variable
abb
del data framemurders
y almacena ese vector en el objetoabreviaciones
. Ordena el objeto alfabéticamente y guarda el resultado en el mismo objeto. Reporta el primer valor del vector abreviaciones.
Para calcular el mínimo valor de un vector y el máximo podemos usar la función
min()
ymax()
respectivamente
- Reporta el mínimo y el máximo valor de la variable
total
del data framemurders
.
Solución
- Accede a la variable
population
del data framemurders
y almacénalo en la variablepoblacion
. Luego crea el objetoindex_pob
donde almacenes los índices ordenados del vectorpoblacion
. Reporta el objetoindex_pob
- Usa el accesador
$
para extraer únicamente la población. Almacena el resultado en el objeto pob. Luego determina la clase del objeto pob.
Solución
La función
table(x)
toma un vectorx
como input y devuelve la cantidad de veces (qué tan frecuente) que cada valor aparece.
- Calcula el número de estados por región que tenemos en nuestro data frame.
1.8 Ejercicios integradores
- Calcula el resultado de la siguiente formula: \({a}^{2}+2{a}{b}+{b}^2\), donde
a
es igual a 31 yb
es igual a 56.
Solución
- Crea el vector c(18, 14, 19, 11) y almacénalo en la variable
notas
. Crea el vector c(0.15, 0.3, 0.10, 0.45) y almacénalo en la variablepeso_ponderado
. Esta variable nos indica el peso que tiene cada nota en la nota final de un estudiante.
Calcula la máxima nota y cuánto es el peso máximo que se le da a una nota de ese curso.
Solución
- Calcula el promedio de notas del vector
notas
y calcula el promedio ponderado utilizando los vectoresnotas
ypeso_ponderado
.
Solución
notas <- c(18, 14, 19, 11)
peso_ponderado <- c(0.15, 0.3, 0.10, 0.45)
# Promedio aritmético de las notas
mean(notas)
# Para calcular el promedio ponderado:
# 1. Primero multiplicamos lasnotas por su peso
notas_por_peso <- notas * peso_ponderado
# 2. Luego sumamos el resultado
sum(notas_por_peso)
Calculamos directamente multiplicando porque los pesos ya están expresados en porcentajes. Podemos ver que el promedio ponderado es menor al promedio aritmético porque el estudiante sacó bajas notas en examenes que tenían mayor peso (Sacó 11 en el examen que pesaba 45% de la nota).
- Explora el data frame llamado
movielens
que incluye un listado de películas estrenadas, así como sus ratings. Está incluido en el paquetedslabs
que ya instalamos, en la misma libreríadslabs
. Calcula cuántas filas hay en el data frame.
Solución
- ¿Cuál es la clase de la columna género? (género en inglés es
genres
)
Solución
- Del data frame
murders
calcula el ratio de total de homicidios por la población de cada estado. El resultado almacénalo en la variable ratio_homicidios. Reporta el resultado
- Modifica tu respuesta anterior para calcula el ratio de homicidios por cada 100 mil habitantes.