Profesor del programa de Ingeniería Industrial, Universidad Sergio Arboleda. Candidato a doctor en Ingeniería de la Universidad de los Andes.
R es un entorno y lenguaje de programación con un enfoque al análisis estadístico. A través de esta clase veremos cuáles son las funcionalidades y herramientas con las cuales podrás desarrollar tareas tan sencillas como sumas y restas hasta modelos de analítica de mercados que usan compañías como Airbnb, Uber o Twitter.
En este curso haremos una introducción a los conceptos básicos para el manejo de datos y el desarrollo de análisis estadísticos básicos. Así pues, ¡empecemos!
En su forma más sencilla, R puede ser utilizado como una calculadora interactiva.
5+7
## [1] 12
R simplemente imprime el resultado 12 por defecto. Sin embargo, R es un lenguaje de programación y, en ocasiones, la utilizamos porque queremos automatizar procesos o evitar repeticiones innecesarias.
En este caso, queremos usar este resultado más adelante. En lugar de volver a escribir todo el código, crearemos una variable que guarde el resultado. La expresión que utilizaremos para esto es <-
.
x <- 5 + 7
Notarán que R no imprime el resultado en este momento. Cuando se asigna información, R asume que no necesita mostrar el resultado. Para ver el resultado, solamente hay que nombrar la variable.
x
## [1] 12
Con R puedes realizar la mayoría de las operaciones básicas. Estas expresiones van a depender del tipo de datos que utilicemos, lo cual lo veremos a lo largo de esta sesión. Cualquier objeto que contenga datos en R se llama estructura de datos y la primera que veremos serán los vectores numéricos.
La forma más sencilla de crear vectores es con la función c()
que significa concatenar o combinar. Probemos unir las expresiones x+3, 5, 23
y asignarlo a la variable z
z <- c (x + 3, 5, 23)
Los vectores numéricos, como en la primera expresión, tambien pueden incluir expresiones y podemos realizar operaciones con ellas. Probemos multiplicar el vector por 2 y sumarle 100.
z*2 + 100
## [1] 130 110 146
Como pueden ver, R aplicó las operaciones a cada elemento del vector. Otras operaciones disponibles son +
, -
, /
, and ^
. Para realizar una raíz cuadrada, use la función sqrt(). Probemos la raíz cuadrada de z -1 y asignarlo a la variable rc_z
rc_z <- sqrt(z-1)
rc_z
## [1] 3.741657 2.000000 4.690416
¿Y qué pasa si dividimos vectores entre si? Probemos que pasa si dividimos z entre su raíz cuadrada.
z/rc_z
## [1] 4.008919 2.500000 4.903616
En efecto, divide el valor de cada elemento de z por el de la misma posición. ¿ Y qué pasa si son de diferente longitud? Recicla los elementos! Probemos un ejemplo.
a <- c (1, 2, 3, 4)
b <- c (0, 10)
c <- a + b
c
## [1] 1 12 3 14
Probemos otro ejemplo:
a <- c (1, 2, 3, 4)
b <- c (0, 10, 100)
c <- a + b
## Warning in a + b: longer object length is not a multiple of shorter object
## length
c
## [1] 1 12 103 4
En el caso de que no sean de igual longitud, el sistema sacará una alerta. Finalmente, si queremos hacer operaciones con los elementos dentro de un vector. Por ejemplo, podemos sumar sus elementos o contar sus elementos. Veamos un ejemplo:
sum(a)
## [1] 10
length(a)
## [1] 4
Otras funciones que podrían ser útiles son min(), max(), mean(), median(), unique()
y sort()
###Listas en R
La siguiente estructura de datos que nos interesa son las listas. Las listas contienen valores de cualquier tipo simple (numerico o no numérico), y podrían ser estructuras completas (lista de listas). Si usamos como referencia a una hoja de calculo con datos sobre individuos, una lista podria ser una fila que tiene los datos de los individuos. Para crear una lista, el comando que utilizaremos es list()
. Veamos un ejemplo:
DetailStudent=list(fullName="Fred Meyers", age=40,female=FALSE)
El objeto ‘DetailStudent’ almacena temporalmente la lista en la computadora. Los nombres de las variables pueden contener letras del alfabeto y números (y algunos caracteres de puntuación), pero no debe comenzar con un número.
En el codigo anterior, solo se ha pedido crear la lista. R lo ejecuta y nada mas, no tienes que esperar ningun mensaje ni resultado. Si quieres ver lo que has creado, escribelo de manera explicita, así:
DetailStudent
## $fullName
## [1] "Fred Meyers"
##
## $age
## [1] 40
##
## $female
## [1] FALSE
Nota que hay varios tipos de datos en la lista:
fullName es texto o caracteres. age es un numero. female es un valor lógico.
Para acceder a cada uno de los elemento tu lista:
#Opción 1: La posición del dato
DetailStudent[[1]]
## [1] "Fred Meyers"
#Opción 2: El nombre de la variable
DetailStudent[['fullName']]
## [1] "Fred Meyers"
#Opción 3: Usar el signo de dolar (o peso)
DetailStudent$fullName
## [1] "Fred Meyers"
Hasta el momento creamos y consultamos una lista. ¿Cómo cambiamos la información de una lista? Si queremos cambiar un valor de la lista, solamente debemos asignar el valor
DetailStudent$fullName='Camilo Pinto'
¿Y si queremos es añadir un elemento a nuestra lista? Funciona igual que nuestro caso anterior, asignando el valor a este elemento
DetailStudent$city = 'Seattle'
Si queremos dejarlo vacío debemos asignar el comando NA
o eliminarlo con NULL
. ¿Y si ya no necesito la lista? Para eliminar una lista necesio usar rm()
list1=list(1,2,3,4)
rm(list1)
EJERCICIO Como parte de su práctica en la escuela de Ingeniería, el decano le solicite que organice la información de los casos disciplinarios a revisar en el próximo comité. Es necesario que la información que :
Crea un objeto tipo lista con los datos de los estudiantes. Los nombres son Freddy Patiño, Luis Ferrucho, Danna Rodriguez y Pedro Meléndez. Cada uno está en un semestre mayor que el anterior, empezando en tercer semestre. Además, todos están acusados de fraude y el estado del proceso es activo.
Antes de llegar al comité se decidió que a todos se les agregaría si hubo confesión. En los estudiantes que hay, solamente Pedro confesó su pena.
3.Después del comité se decidió que todos los estudiantes que no confesaron serán suspendidos por un semestre y los que confesaron recibirán una amonestación escrita.
###Vectores
Los vectores deben contener un único tipo de datos. En un archivo de Excel, un vector puede ser una columna.
names=c("Fred Meyers","Sarah Jones", "Lou Ferrigno","Sky Turner")
ages=c(40,35, 60,77)
female=c(F,T,T,T)
Los tres objectos almacenas temporalmente listas. Los nombre pueden contener letras del alfabeto y números (y algunos caracteres de puntuación), pero no debe comenzar con un número.
Si quieres acceder a ciertos elementos solamente debemos usar corchetes cuadrados simples:
names[1]
## [1] "Fred Meyers"
# o también
ages[1]
## [1] 40
# o también
female[1]
## [1] FALSE
Podemos alterar el vector al asignar nueva información de esta manera (igual que en las listas):
names[1]='Alfred Mayer'
Para añadir un nuevo elemento, usaremos una estructura recursiva:
elements=c(1,2,3)
elements=c(elements,40)
Sin embargo, para eliminar los datos no podemos utilizar la operación Null
que usamos en las listas. Para eliminar el elemento debemos encoger el vector usando la siguiente expresión:
elements= elements[-4]
¿Y qué podemos hacer si tenemos valores repetidos en nuestro vector? En este caso, podemos usar la función unique
:
weekdays=c('M','T','W','Th','S','Su','Su')
weekdays
## [1] "M" "T" "W" "Th" "S" "Su" "Su"
unique(weekdays)
## [1] "M" "T" "W" "Th" "S" "Su"
###Vectores versus Listas
¿Y cómo hacemos para saber qué tipo de datos tenemos? ¿Es un vector o es una lista? Para esto, la función que nos interesa es str
. Dependiendo del tipo de datos que tengamos, podremos obtener:
str(elements)
str(DetailStudent)
str(rc_z)
Además, cuando crees y uses operaciones debes considerar cuáles aplican para cada estructura. Probemos la operación length
:
listTest=list(1,2,3,3)
vectorTest=c(1,2,3,4,4)
length(listTest)
length(vectorTest)
###Data Frames
Los Data frames pueden interpretarse como estructuras compuestas a partir de las estructuras simples. Si partieramos de usar vectores, cada uno corresponde a las columnas. Para crear un data frame, el comando es `data.frame:
# Usaremos cuatr vectores sobre estudiantes extranjeros
names=c("Qing", "Françoise", "Raúl", "Bjork")
ages=c(32,33,28,30)
country=c("China", "Senegal", "Spain", "Norway")
education=c("Bach", "Bach", "Master", "PhD")
#DF es una composición de vectores:
DF_vectors=data.frame(names,ages,country,education)
DF_vectors
## names ages country education
## 1 Qing 32 China Bach
## 2 Françoise 33 Senegal Bach
## 3 Raúl 28 Spain Master
## 4 Bjork 30 Norway PhD
¿Y si tenemos listas? Usaremos el comando data.list
en conjunto con do.call
. La forma de aplicarla es así:
# Listas por fila
row1=list(name="Qing", age=32, country="China", deg="Bach")
row2=list(name="Françoise", age=33, country="Senegal", deg="Bach")
row3=list(name="Raúl", age=28, country="Spain", deg="Master")
row4=list(name="Bjork", age=30, country="Norway", deg="PhD")
# lista de listas
dataList=list(row1,row2,row3,row4)
#DF es una composición de listas:
DF_lists=do.call(rbind.data.frame,dataList)
row.names(DF_lists)=NULL
DF_lists
## name age country deg
## 1 Qing 32 China Bach
## 2 Françoise 33 Senegal Bach
## 3 Raúl 28 Spain Master
## 4 Bjork 30 Norway PhD
Y ¿qué tipo de cosas nos interesa saber de un data frame?
#Conocer si es un Data Frame
str(DF_vectors)
str(DF_lists)
#Dimensiones del Data Frame
dim(DF_vectors)
#Filas del Data Frame
nrow(DF_vectors)
#Columnas del Data Frame
length(DF_vectors)
#Ver las primeras filas
head(DF_vectors,2)
#Ver las últimas filas
tail(DF_vectors,2)
#¿Qué variables tenemos?
names(DF_vectors)
Al leer los datos, la estructura que deben tener en cuenta es [Filas, columnas]
. Para leer las columnas, tenemos varias opciones:
#Puedo tomar una columna si sé la columna
DF_vectors$names
## [1] "Qing" "Françoise" "Raúl" "Bjork"
#Puedo tomar una columna si sé su posición
DF_vectors[,1]
## [1] "Qing" "Françoise" "Raúl" "Bjork"
#Varias columnas (con posiciones)
DF_vectors[,c(1,4)]
## names education
## 1 Qing Bach
## 2 Françoise Bach
## 3 Raúl Master
## 4 Bjork PhD
#Varias columnas (con nombres)
DF_vectors[,c('names','education')]
## names education
## 1 Qing Bach
## 2 Françoise Bach
## 3 Raúl Master
## 4 Bjork PhD
Además, para la lectura de las filas tenemos dos opciones:
#una fila
DF_vectors[2,]
## names ages country education
## 2 Françoise 33 Senegal Bach
#varias filas
DF_vectors[c(2,3),]
## names ages country education
## 2 Françoise 33 Senegal Bach
## 3 Raúl 28 Spain Master
Nótese en los casos anteriores, que si no indicabas filas, tenías toda la fila; y que si no indicas columnas, vienen todas las columnas. Si solo quieres un valor:
students=DF_vectors[1,3]
A veces nos va interesar tomar una parte del Data Frame, esto lo llamaremos subset y lo haremos asignando esta información que obtuvimos:
studentsCopy= DF_vectors
Ahora haremos las modificaciones a los valores que obtenemos:
# cambio el valor de una edad:
studentsCopy[1,2]=23
# No hay advertencia, el cambio ya se hizo:
studentsCopy[1,]
## names ages country education
## 1 Qing 23 China Bach
Podemos tener una nueva columna con valores vacios:
studentsCopy$lastName=NA
studentsCopy
## names ages country education lastName
## 1 Qing 23 China Bach NA
## 2 Françoise 33 Senegal Bach NA
## 3 Raúl 28 Spain Master NA
## 4 Bjork 30 Norway PhD NA
Y puedo eliminarla con NULL:
studentsCopy$lastName=NULL
studentsCopy
## names ages country education
## 1 Qing 23 China Bach
## 2 Françoise 33 Senegal Bach
## 3 Raúl 28 Spain Master
## 4 Bjork 30 Norway PhD
###Lectura y cargue de datos
Aunque las estructuras de datos son útiles para trabajar en R, los datos que vamos a utilizar vienen en diferentes formatos de datos. Por tanto, es vital establecer una conexión entre la máquina y R. Este espacio en el cual estaremos trabajando se denomina Workspace y varía entre máquina y máquina. Sin embargo, R hace que funcione en diferentes tipos de computadores.
Lo primero que nos interesa es conocer nuestro actual directorio con la función getwd()
.
getwd()
## [1] "/cloud/project"
Una vez sabemos dónde estamos, queremos saber qué tenemos. Para esto, usamos el comando dir()
.
dir()
## [1] "Clase 1.nb.html" "Clase 1.Rmd" "Clase 10.Rmd" "Clase 2.Rmd"
## [5] "Clase_2.html" "Clase-10.html" "Clase-10.Rmd" "Clase10.csv"
## [9] "project.Rproj" "test.R" "testdir"
Si queremos guardar nuestra ubicación actual, solamente debemos asignarlo a una variable.
old.dir <- getwd()
Ahora, sabemos que ahí no está el archivo que necesitamos. Vamos a crear un nuevo directorio que nos lleve a dónde está la información que necesito. Para eso, voy a usar la función dir.create()
dir.create("testdir")
## Warning in dir.create("testdir"): 'testdir' already exists
Recuerden que queremos cambiar tan poco como sea posible la información, o como dicen los creadores de R “Solamente toma foto, deja únicamente huellas”. Por eso, asignaremos nuestro trabajo a esta carpeta con el comando setwd()
setwd("testdir")
Ahora, crearemos y agregaremos archivos a esta carpeta con el comando file.create()
. Para empezar crearemos un script de R al que llamaremos test.
file.create("test.R")
## [1] TRUE
En general, pueden revisar todas las funciones asociadas con file
como exists, rename, copy, path
Ahora, lo que necesitamos hacer ahora es conseguir la información que tenemos en este directorio. Con el archivo de excel llamado “Clase 10” cargaremos esta información. Carguen este archivo en su directorio.
Hay una serie de formatos de datos comunes que se pueden leer dentro y fuera de R. Esto incluye archivos de texto en formatos como csv, txt, html y json. También incluye archivos de salida de aplicaciones estadísticas como SAS y SPSS. Los recursos en línea que incluyen servicios web y páginas HTML también se pueden leer en R.
La primera función que examinaremos es read.table()
. Esta es una función incorporada en R que puede utilizarse para leer varios formatos de archivo en un Data Frame. Esta es probablemente la función interna más común utilizada para leer archivos simples en R.
df = read.table("Clase10.csv", header = TRUE, sep=",")
## Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, :
## EOF within quoted string
## Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, :
## number of items read is not a multiple of the number of columns
La función read.csv()
también es una función incorporada en R que es casi idéntica a la read.table()
, con la excepción de que los argumentos de encabezado y relleno se establecen en TRUE de forma predeterminada. En este paso, verás lo fácil que es cargar un archivo csv utilizando read.csv()
.
df2 = read.csv("Clase10.csv")
En R, la unidad fundamental de código compartible es el paquete. Un paquete agrupa código, datos, documentación y pruebas, y es fácil de compartir con otros. A partir de enero de 2015, había más de 6,000 paquetes disponibles en Comprehensive R Archive Network, o CRAN, la cámara de compensación pública para paquetes de R. Esta gran variedad de paquetes es una de las razones por las que R es tan exitosa: lo más probable es que alguien ya haya resuelto un problema en el que estás trabajando, y puedes beneficiarte de su trabajo al descargar su paquete.
Y ¿cómo los consigo?:
Los instalas desde CRAN con install.packages("X")
. Los usas en R con library("x")
. *Recibes ayuda con package?X
y help(package = "x")
.
Como vimos hace unos minutos, algunos de los comandos que podemos utilizar para cargar datos son read.table()
y read.csv()
. Estas funciones están cargadas en R y RStudio. Sin embargo, también hay paquetes que nos ayudan a cargar los datos que recibimos.
El día de hoy vamos a trabajar con el paquete readr
para hacer el cargue de los datos. Readr
nos permite no solamente leer archivos en .csv sino, por ejemplo, logs de páginas web. Todas las funciones de empiezan por read_
más la extensión del archivo. Para cargar el paquete y los datos haremos lo siguiente:
#Llamar el paquete para que funcione
library('readr')
#Leer los datos
data1 <- read_csv("Clase10.csv")
## Warning: Missing column names filled in: 'X1' [1]
## Parsed with column specification:
## cols(
## X1 = col_double(),
## item_gender = col_character(),
## item_category = col_character(),
## item_name = col_character(),
## item_price = col_double(),
## item_colors = col_double()
## )
Como podemos observar, tenemos una gran cantidad de información en esta base de datos. Hagámonos una idea del tamaño usando la función dim()
dim(data1)
## [1] 700 6
De las 6 variables que tenemos, necesitamos saber qué información recogen. Para ello, la función str()
que vimos la clase pasada seguirá aplicando. Miremos los datos que acabamos de cargar:
str(data1)
## tibble [700 × 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ X1 : num [1:700] 0 1 2 3 4 5 6 7 8 9 ...
## $ item_gender : chr [1:700] "womens" "womens" "womens" "womens" ...
## $ item_category: chr [1:700] "jackets" "jackets" "jackets" "jackets" ...
## $ item_name : chr [1:700] "W's Los Gatos 1/4-Zip" "W's Better Sweater® 1/4-Zip" "W's Better Sweater® Jacket" "W's Re-Tool Snap-T® Pullover" ...
## $ item_price : num [1:700] 99 99 139 119 149 199 119 249 229 149 ...
## $ item_colors : num [1:700] 6 9 10 8 10 8 8 5 7 6 ...
## - attr(*, "spec")=
## .. cols(
## .. X1 = col_double(),
## .. item_gender = col_character(),
## .. item_category = col_character(),
## .. item_name = col_character(),
## .. item_price = col_double(),
## .. item_colors = col_double()
## .. )
¿Notaron algo en los datos que acabamos de cargar? . Para eso, iremos al primer paso de la analítica de mercado, el preprocesamiento de los datos.
Lo primero que hemos de detectar es qué información está incluida en las columnas que parece haber problemas. Para eso utilizaremos una función que vimos la clase pasada, unique()
. Miremos cómo nos va:
# Los datos en Item Category
unique(data1$item_category)
#Los datos en Height
unique(data1$item_gender)
Dado que no hemos visto que, por lo menos, en estas dos variables tenemos datos que son NA, no debemos eliminar datos. De ser necesario, usaríamos la función na.omit()
. Esta función eliminará todos los registros que sean NA de cualquiera de las variables.
data2 <- na.omit(data1)
¿Y qué podemos hacer ya cuándo los datos están limpios? Fácil, nos empezaremos a hacer las preguntas importantes sobre nuestros datos.