El objetivo de este tutorial es aprender a procesar datos en R. Desde importar y exportar archivos, hasta el manejo interno de datos y el ajuste a distribuciones.
Para importar archivos de datos de extensión: csv, xlsx, stata, spss o sas podemos ayudarnos de la barra de herramientas de RStudio siguiendo los siguientes pasos:
1.File.
2.Import Dataset.
3.Seleccionamos la extensión que nos sirva.
Otra forma de importar datos es utilizar algunos paquetes de R. Por ejemplo, podemos importar un archivo xlsx utilizando el paquete “xlsx”. Queremos importar la base de datos “AAPL.csv” que encuentra en SICUA+. Al correr el código recuerden cambiar la ruta del archivo por la ruta en la que se encuentra el archivo en su computador.
data <- read.csv(file = "AAPL.csv", sep = ",")
Estos datos incluyen la información de las acciones de Apple. Para cada fecha se conoce el precio al que abrió la acción ese día, el máximo y mínimo valor del precio, el precio de cierre de la acción así como el precio ajustado y finalmente el volumen de acciones.
Nota: Para conocer el directorio actual dónde está trabajando en R puede utilizar la función “getwd()”, si desea cambiar el directorio de trabajo puede usar la función “setwd(dir)” ingresando entre los paréntesis la dirección que quiere asignar, por ejemplo: setwd(“/Users/modelos/complementarias”).
Ahora bien, para guardar esta tabla de información utilizaremos un Data Frame. La línea superior del Data Frame, llamada el encabezado, contiene los nombres de columna. Cada línea horizontal después denota una fila de datos, que comienza con el nombre de la fila y, a continuación, los datos reales. Para convertir nuestros datos “data” en un Data frame utilizamos el siguiente código:
data1 <- data.frame(data)
Podemos ver el resultado en la pestaña de variables globales. Un Data Frame es útil para almacenar datos porque podemos almacenar vectores de diferente tipo (por ejemplo numéricos y characters). También es útil porque podemos acceder a la información de cierta columna sin saber el número de la columna, sólo con el nombre con el que lo guardamos.
Para traer los datos de una celda, introducimos sus coordenadas de fila y columna en el operador de corchetes “[]”. Las dos coordenadas están separadas por una coma (número de fila, número de columna). Por ejemplo, queremos traer el dato que se encuetra en la fila 3 y columna 4.
data1[3,4]
## [1] 149.95
También, podemos utilzar los nombres de las columnas y de las filas para traer los valores dentro del Data Frame:
data1[3,"Low"]
## [1] 149.95
De igual forma, podemos conocer el número de filas y columnas de un Data Frame con las funciones:
nrow(data1)
## [1] 21
ncol(data1)
## [1] 7
Mas aún, podemos acceder a la información básica del Data Frame utilizando:
summary(data1)
## Date Open High Low
## 2017-07-17: 1 Min. :148.8 Min. :150.1 Min. :147.3
## 2017-07-18: 1 1st Qu.:150.0 1st Qu.:150.9 1st Qu.:148.9
## 2017-07-19: 1 Median :153.4 Median :153.9 Median :151.8
## 2017-07-20: 1 Mean :153.9 Mean :155.0 Mean :152.6
## 2017-07-21: 1 3rd Qu.:157.1 3rd Qu.:158.9 3rd Qu.:156.1
## 2017-07-24: 1 Max. :159.9 Max. :161.8 Max. :159.1
## (Other) :15
## Close Adj.Close Volume
## Min. :148.7 Min. :148.1 Min. :15781000
## 1st Qu.:150.3 1st Qu.:149.7 1st Qu.:19845900
## Median :152.7 Median :152.1 Median :22028200
## Mean :153.8 Mean :153.3 Mean :26571690
## 3rd Qu.:157.1 3rd Qu.:156.5 3rd Qu.:27097300
## Max. :161.1 Max. :160.4 Max. :69936800
##
Allí encontramos las estadísticas básicas (media, cuartiles, mediana, moda, mínimo y máximo) para cada variable (columna) dentro del Data Frame.
Para acceder a una columna podemos utilizar diferentes formas:
data1[["Volume"]]
data1[[7]]
data1$Volume
data1[,"Volume"]
data1[,7]
## [1] 23793500 17868800 20923000 17243700 26252600 21493200 18853900
## [8] 15781000 32476300 17213700 19845900 35368600 69936800 27097300
## [15] 20559900 21870300 36205900 26131500 40804300 26257100 22028200
También, podemos acceder a la información de las filas de diferentes formas:
data1["nombre fila",]
data1[3,]
## Date Open High Low Close Adj.Close Volume
## 3 2017-07-19 150.48 151.42 149.95 151.02 150.4293 20923000
Podemos traer información de múltiples filas o columnas. En este caso queremos traer la información de las filas 5 y 12 al mismo tiempo:
data1[c(5,12),]
## Date Open High Low Close Adj.Close Volume
## 5 2017-07-21 149.99 150.44 148.88 150.27 149.6822 26252600
## 12 2017-08-01 149.10 150.22 148.41 150.05 149.4631 35368600
Por último, podemos recuperar filas con un vector de operadores lógicos. El siguiente vector K, toma valor de TRUE si el precio de valor mínimo de la acción en esa fecha es mayor a 155, tomará valor de FALSE en caso contrario.
K <- data1$Low < 155
data1[K,]
## Date Open High Low Close Adj.Close Volume
## 1 2017-07-17 148.82 150.90 148.57 149.56 148.9750 23793500
## 2 2017-07-18 149.20 150.13 148.67 150.08 149.4930 17868800
## 3 2017-07-19 150.48 151.42 149.95 151.02 150.4293 20923000
## 4 2017-07-20 151.50 151.74 150.19 150.34 149.7519 17243700
## 5 2017-07-21 149.99 150.44 148.88 150.27 149.6822 26252600
## 6 2017-07-24 150.58 152.44 149.90 152.09 151.4951 21493200
## 7 2017-07-25 151.80 153.84 151.80 152.74 152.1425 18853900
## 8 2017-07-26 153.35 153.93 153.06 153.46 152.8597 15781000
## 9 2017-07-27 153.75 153.99 147.30 150.56 149.9711 32476300
## 10 2017-07-28 149.89 150.23 149.19 149.50 148.9152 17213700
## 11 2017-07-31 149.90 150.33 148.13 148.73 148.1482 19845900
## 12 2017-08-01 149.10 150.22 148.41 150.05 149.4631 35368600
## 19 2017-08-10 159.90 160.00 154.63 155.32 155.3200 40804300
Ahora bien, también podemos añadir columnas a un Data Frame. Por ejemplo podemos crear una columna que sea el logaritmo del precio ajustado de cierre:
data1$LogAdj <- log(data1$Adj.Close,10)
También podemos crear un vector del logaritmo del precio ajustado y juntarlo al Data Frame de la siguiente forma:
LogAdj2 <- log(data1$Adj.Close,10)
data1 <- cbind(data1,LogAdj2)
Ahora tenemos 2 variables del logaritmo del precio ajustado de cierre en nuestro Data Frame, vamos a eliminar una de las variables pues es repetitiva, para hacerlo utilizamos el siguiente código:
data1 <- data1[,-ncol(data1)]
Ahora bien, ¿qué pasaría si quisieramos traer un subconjunto de datos dentro del Data Frame que cumpla ciertas condiciones?, ¿cómo lo haríamos? Para ello utilizamos la función “subset”. Por ejemplo, queremos traer el subconjunto de datos que cumple con que el valor máximo es menor a 152 y el precio ajustado está entre 148 y 151. Esto lo podamos hacer de la siguiente forma:
data2 <- subset(data1,data1$High<152 & data1$Adj.Close <= 151 & data1$Adj.Close >= 148)
Ahora, podemos utilizar gráficas para hacer exploración de datos dentro del Data Frame. Por ejemplo, utilizando la función “hist()” creamos un histograma de una variable de interés (recordemos que para ver la documentación y los parámetros que recibe una función podemos utilzar la ayuda de R “?hist”):
hist(data1$High,main = "Histograma de la variable High")
También podemos hacer gráficos de dispersión, en este caso queremos crear un gráfico de dispersión del logaritmo de los precios ajustados en el tiempo t y en el tiempo t-1.
x <- log(data1$Adj.Close[-nrow(data1)],10)
y <- log(data1$Adj.Close,10)[-1]
plot(x,y,type = "p", main = "Gráfico de dispersión del logarItmo del precio ajustado en t vs t-1", ylab = "Logaritmo de t", xlab = "Logaritmo t-1")
R ofrece varias opciones para tratar datos de fecha. La función “as.Date”" maneja las fechas (sin tener en cuenta la zona horaria); mientras que, las clases POSIXct y POSIXlt permiten fechas y horas con diferenciación de la zona horaria. Para la fecha, la función “as.Date” es una buena opción. Si necesitamos manejar fechas y horas sin información de zona horaria podemos utilizar la biblioteca de “chron”.
Las fechas se almacenan internamente como el número de días o segundos desde una fecha de referencia (excepto la clase POSIXlt). POSIXlt almacena los valores de fecha/hora como una lista de componentes (hora, min, seg, mon, etc.).
Ahora bien, la función “as.Date” convierte una fecha en el formato fecha que utiliza R. La fecha que se ingresa puede tener múltiples parámetros. Por ejemplo:
as.Date('1915-6-16')
## [1] "1915-06-16"
as.Date(data1[5,1])
## [1] "2017-07-21"
Cuando las fechas no vienen en un formato estándar (o reconocido), podemos ponerle el formato dentro de la función “as.Date” utilizando la siguiente tabla de convenciones:
| Código | Significado |
|---|---|
| %d | día del mes (en número) |
| %m | mes (en número) |
| %b | mes abreviado (en letras) |
| %B | nombre completo del mes |
| %y | año en dos dígitos |
| %Y | año en cuatro dígitos |
Por ejemplo:
as.Date('1/15/2001',format='%m/%d/%Y')
## [1] "2001-01-15"
as.Date('Abril 26, 2001',format='%B %d, %Y')
## [1] NA
as.Date('22JUN01',format='%d%b%y')
## [1] "2001-06-22"
Con las fechas convertidas ahora podemos hacer comparaciones entre ellas, por ejemplo queremos saber si una fecha es mayor a otra:
fecha1 = as.Date('22/07/1995', format = '%d/%m/%Y')
fecha2 = as.Date('30/04/1998', format = '%d/%m/%Y')
if(fecha1 > fecha2){
return(paste0(fecha1," es mayor a ",fecha2))
} else{
return(paste0(fecha2," es mayor a ",fecha1))
}
## [1] "1998-04-30 es mayor a 1995-07-22"
¿Qué pasa cuando se tiene dos Data Frame y se quieren unir por alguna variable? y ¿si se tienen dos Data Frames y se quieren añadir filas de un Data Frame al otro? Para realizar estas acciones podemos utilizar la función “merge”. Primero creemos nuestros datos:
Clientes <- data.frame(CustomerID=c(1,2,3,4,5),NombreCliente = c("María Fernanda", "Daniela","Carlos", "Juan José","Carlos"), Ciudad= c("Bogotá","Bogot?", "Cartagena","Cartagena", "Quibdó"),CodigoPostal = c(1290,1292,8470,8569,294),Pais = c("Col","Col","Col","Col","Col"))
Clientes
## CustomerID NombreCliente Ciudad CodigoPostal Pais
## 1 1 María Fernanda Bogotá 1290 Col
## 2 2 Daniela Bogot? 1292 Col
## 3 3 Carlos Cartagena 8470 Col
## 4 4 Juan José Cartagena 8569 Col
## 5 5 Carlos Quibdó 294 Col
Ordenes <- data.frame(OrderID = c(2,37,54,12,36,45),CustomerID=c(4,5,1,3,1,2),EmpleadoID = c(5,4,7,6,4,2), EnvioID = c(3,4,59,2,24,31), Producto = c("Zapato","Camisa","Pantalón","Camisa","Joyas","Zapato"))
Ordenes
## OrderID CustomerID EmpleadoID EnvioID Producto
## 1 2 4 5 3 Zapato
## 2 37 5 4 4 Camisa
## 3 54 1 7 59 Pantalón
## 4 12 3 6 2 Camisa
## 5 36 1 4 24 Joyas
## 6 45 2 2 31 Zapato
En este caso tenemos dos tablas de datos. La primera, Clientes, contiene la información de los clientes (Id, nombre, ciudad, codigo postal y país) que han comprado en una tienda. La segunda, Ordenes, tiene la información de las órdenes que se han realizado en la tienda (el número de orden, el código del cliente que realizó la orden, el código del empleado que atendió la orden, el código de envío y finalmente, el producto que se envía). Si queremos unir las dos tablas por alguna variable podemos utilizar la función “merge”.
CompiladoTablas <- merge(Clientes,Ordenes, by = "CustomerID")
CompiladoTablas
## CustomerID NombreCliente Ciudad CodigoPostal Pais OrderID EmpleadoID
## 1 1 María Fernanda Bogotá 1290 Col 54 7
## 2 1 María Fernanda Bogotá 1290 Col 36 4
## 3 2 Daniela Bogot? 1292 Col 45 2
## 4 3 Carlos Cartagena 8470 Col 12 6
## 5 4 Juan José Cartagena 8569 Col 2 5
## 6 5 Carlos Quibdó 294 Col 37 4
## EnvioID Producto
## 1 59 Pantalón
## 2 24 Joyas
## 3 31 Zapato
## 4 2 Camisa
## 5 3 Zapato
## 6 4 Camisa
Podemos ver que el resultado muestra una tabla que contiene la información de Clientes y Ordenes unidas por la variable “CustomerID”. Otra opción para unir estas dos tablas es utilizar la función “join” del paquete “plyr”.
install.packages("plyr",repos = "http://cran.us.r-project.org")
##
## The downloaded binary packages are in
## /var/folders/x0/9bypjmn96pgdxf1lzfqtqm8c0000gp/T//RtmpWuEEPm/downloaded_packages
library("plyr")
CompiladoTablas2 <- join(Clientes,Ordenes,type="inner", by = "CustomerID")
CompiladoTablas2
## CustomerID NombreCliente Ciudad CodigoPostal Pais OrderID EmpleadoID
## 1 1 María Fernanda Bogotá 1290 Col 54 7
## 2 1 María Fernanda Bogotá 1290 Col 36 4
## 3 2 Daniela Bogot? 1292 Col 45 2
## 4 3 Carlos Cartagena 8470 Col 12 6
## 5 4 Juan José Cartagena 8569 Col 2 5
## 6 5 Carlos Quibdó 294 Col 37 4
## EnvioID Producto
## 1 59 Pantalón
## 2 24 Joyas
## 3 31 Zapato
## 4 2 Camisa
## 5 3 Zapato
## 6 4 Camisa
A diferencia de la función “merge”“, la función”join" conserva el orden del primer Data Frame sin importar qué tipo de unión se utiliza.
LeftCompiladoTablas <- join(Clientes,Ordenes,type = "left", by = "CustomerID")
LeftCompiladoTablas
## CustomerID NombreCliente Ciudad CodigoPostal Pais OrderID EmpleadoID
## 1 1 María Fernanda Bogotá 1290 Col 54 7
## 2 1 María Fernanda Bogotá 1290 Col 36 4
## 3 2 Daniela Bogot? 1292 Col 45 2
## 4 3 Carlos Cartagena 8470 Col 12 6
## 5 4 Juan José Cartagena 8569 Col 2 5
## 6 5 Carlos Quibdó 294 Col 37 4
## EnvioID Producto
## 1 59 Pantalón
## 2 24 Joyas
## 3 31 Zapato
## 4 2 Camisa
## 5 3 Zapato
## 6 4 Camisa
RightCompiladoTablas <- join(Clientes,Ordenes,type = "right", by = "CustomerID")
RightCompiladoTablas
## CustomerID NombreCliente Ciudad CodigoPostal Pais OrderID EmpleadoID
## 1 4 Juan José Cartagena 8569 Col 2 5
## 2 5 Carlos Quibdó 294 Col 37 4
## 3 1 María Fernanda Bogotá 1290 Col 54 7
## 4 3 Carlos Cartagena 8470 Col 12 6
## 5 1 María Fernanda Bogotá 1290 Col 36 4
## 6 2 Daniela Bogot? 1292 Col 45 2
## EnvioID Producto
## 1 3 Zapato
## 2 4 Camisa
## 3 59 Pantalón
## 4 2 Camisa
## 5 24 Joyas
## 6 31 Zapato
También, quisiera conocer si los datos que tengo se ajustan a una distribución de probabilidad. Para realizar un ajuste de distribución se puede utilizar el paquete “rriskDistributions” o el paquete “MASS” y debo saber si mis datos son de naturaleza discreta o contínua. ##Contínuas Algunas de las distribuciones contínuas son: exponencial, Gamma, Weibull, normal, lognormal, uniforme, entre otras. Para conocer si un vector de datos se ajusta a alguna de estas distribuciones puede utilizar el paquete “rriskDistributions”. Suponga que tiene un vector que contiene el tiempo entre llegadas de clientes a una tienda “tClientes”. Utilizando la función “fit.cont()” se evaluarán automáticamente un conjunto de distribuciones contínuas para conocer si alguna de estas se ajusta a los datos ingresados.
library(rriskDistributions)
tClientes=rexp(300,2)
fit.cont(tClientes)
## Warning: running command ''/usr/bin/otool' -L '/Library/Frameworks/
## R.framework/Resources/library/tcltk/libs//tcltk.so'' had status 1
##
## Begin fitting distributions ---------------------------------------
## * fitting normal distribution ... OK
## * fitting Cauchy distribution ... OK
## * fitting logistic distribution ... OK
## * fitting beta distribution ... failed
## * fitting exponential distribution ... OK
## * fitting chi-square distribution ... OK
## * fitting uniform distribution ... OK
## * fitting gamma distribution ... OK
## * fitting lognormal distribution ... OK
## * fitting Weibull distribution ... OK
## * fitting F-distribution ... OK
## * fitting Student's t-distribution ... OK
## * fitting Gompertz distribution ... OK
## * fitting triangular distribution ... failed
## End fitting distributions -----------------------------------------
## logL AIC BIC Chisq(value) Chisq(p) AD(value)
## Normal -208.57 421.13 428.54 191.37 0.00 13.44
## Cauchy -211.9 427.8 435.21 166.88 0.00 18.29
## Logistic -196.36 396.72 404.12 169.05 0.00 10.33
## Exponential -88.19 178.39 182.09 11.89 0.69 0.70
## Chi-square -151.29 304.58 308.28 98.12 0.00 18.46
## Uniform NULL NULL NULL Inf 0.00 Inf
## Gamma -87.85 179.71 187.11 10.60 0.72 0.40
## Lognormal -113.38 230.76 238.17 41.23 0.00 3.47
## Weibull -87.96 179.92 187.32 10.87 0.70 0.44
## F -137.56 279.12 286.53 81.98 0.00 30.56
## Student -347.78 697.56 701.26 469.34 0.00 72.80
## Gompertz -88.14 180.28 187.68 12.10 0.60 0.82
## H(AD) KS(value) H(KS)
## Normal rejected 0.15 rejected
## Cauchy rejected 0.21 rejected
## Logistic rejected 0.16 rejected
## Exponential not rejected 0.05 not rejected
## Chi-square NULL 0.17 rejected
## Uniform NULL 0.21 rejected
## Gamma NA 0.03 not rejected
## Lognormal rejected 0.09 rejected
## Weibull not rejected 0.03 not rejected
## F NULL 0.21 rejected
## Student NULL 0.50 rejected
## Gompertz NULL 0.05 not rejected
## Warning: running command ''otool' -L '/Library/Frameworks/R.framework/
## Resources/modules/R_X11.so'' had status 1
##
## Chosen continuous distribution is: Exponential (exp)
## Fitted parameters are:
## rate
## 2.025911
A partir de los resultados anteriores se puede notar que la distribución que mejor se ajusta a los datos es la exponencial.
Algunas de las distribuciones discretas son: Poisson, geométrica, binomial, hipergeométrica y binomial negativa, entre otras.
library(rriskDistributions)
#A continuación generamos un vector de datos que siguen una distribución Poisson
x2 <- rpois(50, lambda = 3)
#Evaluamos si los datos siguen la distribución Poisson
rriskMMEdist(x2, "pois")
## lambda
## 2.92
#Evaluamos si los datos siguen la distribución Binomial negativa
rriskMMEdist(x2, "nbinom")
## size mu
## 9.760073 2.920000
#Evaluamos si los datos siguen la distribución geométrica
rriskMMEdist(x2, "geom")
## prob
## 0.255102
También podemos utilizar el paquete “fitdistrplus”, el cual nos permite conocer con mayor facilidad el p-value.
library(fitdistrplus)
## Loading required package: MASS
## Warning: package 'MASS' was built under R version 3.4.4
## Loading required package: survival
## Warning: package 'survival' was built under R version 3.4.4
fit<-fitdist(x2, "pois",method="mle")
summary(fit)
## Fitting of the distribution ' pois ' by maximum likelihood
## Parameters :
## estimate Std. Error
## lambda 2.92 0.2416609
## Loglikelihood: -101.9217 AIC: 205.8434 BIC: 207.7554
plot(fit)
estFit<-gofstat(fit)
estFit$chisqpvalue
## [1] 0.4051977
Como pudimos observar, se obtuvo un p-value mayor a 0.05, lo cual nos indica que con una significancia del 5% no rechazamos la hipótesis nula y nuestros datos siguen la distribución Poisson.