Split-Apply-Combine-Parte 2

Parte 2.-Procesando los datos y analizando otras posibles relaciones.

En la primera parte solo puse algunos ejemplos de gráficas que se pueden generar de manera directa de los datos sin hacer ningún procesamientos sobre la información.

Existen varias librerías para procesar datos en R project, las que aparecen en mayor cantidad de referencias son reshape2, dplyr y data.table. Para realizar un procesa SAC en los datos, no basta con solo revisar las variables de manera directa, es recomendable hacer un poco de procesamiento de los datos para realizar una exploración más sutil sobre la información.

En la entrada “Algo de procesamiento de datos” compartí algunos ejemplos sencillos del uso de las tres librerías de R y sobre el procesamiento de datos en Python con Pandas. Por lo cual no explico todos los detalles sobre las funciones, para más detalles se puede revisar esa entrada o las referencias que dejé en esa entrada.

Algo más

Usando dplyr y reshape2, se pueden explorar otro tipo de relaciones entre los datos. Ejemplo, la información de los vuelos cuenta con 16 variables de las cuales 3 de ellas indican el año, mes y día. Estas tres variables pueden permitir construir la variable de fecha la cual nos permite preguntarnos sobre la información desde un punto de vista de series de tiempo.

Una serie de tiempo es analizar el comportamiento de un indicador con respecto a la variación del tiempo, esto si bien no es claro lo muestro en el ejemplo. Formalmente es un proceso estocástico que tienen un parámetro t de tiempo.

La intención con ciertas transformaciones y agrupamientos de los datos es permitir explorar la información de manera diferente a lo que podemos hacer directamente desde la tabla de datos.

Tratamiento 1

#Se cargan los datos y las librerías requeridas para el análisis
#Se cargan las librerías
library(nycflights13)
library(dplyr)
library(reshape2)
library(ggplot2)

#Revisión de los datos
data("flights")
dim(flights)
#[1] 336776 16
#missing value
#Se eliminan las filas sin datos completos

sum(is.na(flights))
#[1] 60593
flights2=na.omit(flights)
head(flights2,10)
str(flights2)
dim(flights2)
#[1] 327346 16

#Agrupamos por fechas y aeropuerto de origen
a1<-flights2%>%
 group_by(year,month,day,origin)%>%
 summarise(count=n(),retrasos=sum(dep_delay+arr_delay),distancia=mean(distance))

#Se revisan el tipo de datos con los siguientes comenados
head(a1)
dim(a1)
#[1] 1095 7
str(a1)

#Agrego una variable para la fecha

a2=mutate(a1,fechas=as.Date(paste(month,day,year,sep="/"),"%m/%d/%Y"))
dim(a2)
#1095 8
str(a2)

head(a2)
#Source: local data frame [6 x 8]
#Groups: year, month, day

 #year month day origin count retrasos distancia fechas
#1 2013 1 1 EWR 300 11455 1039.8033 2013-01-01
#2 2013 1 1 JFK 295 5944 1297.1424 2013-01-01
#3 2013 1 1 LGA 236 2617 843.6695 2013-01-01
#4 2013 1 2 EWR 341 17242 1010.3900 2013-01-02
#5 2013 1 2 JFK 317 3641 1281.3502 2013-01-02
#6 2013 1 2 LGA 270 3589 841.9519 2013-01-02

Lo que se hizo con el código anterior fue construir desde los datos originales un data.frame o una tabla de datos con la información ordenada de otro modo y lista para poder explorarla como serie de tiempo. Lo que se hizo fue contabilizar la cantidad de vuelos por día, sumar los minutos de retraso al despegar y al arribar y calcular la distancia media recorrida por día.

Se pueden hacer algunas cosas con esta información, primero visualizar el comportamiento de los datos por cada aeropuerto de origen y después explorar si existe alguna relación entre las 3 series de tiempo.

 #Serie de tiempo 1
ggplot(a2,aes(x=fechas,y=count))+geom_line(aes(colour=factor(origin)))+scale_x_date()+facet_grid(.~origin)+geom_smooth(col="black")+
 ggtitle("Número de vuelos por año")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Cantidad de vuelo")+xlab("Fecha de Vuelos")

La gráfica es la siguiente:

Serie_T1

#Serie de tiempo 2
ggplot(a2,aes(x=fechas,y=retrasos))+geom_line(aes(colour=factor(origin)))+scale_x_date()+facet_grid(.~origin)+geom_smooth(col="black")+
 ggtitle("Minutos de retrasos por vuelo en el año")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Minutos de retraso")+xlab("Fecha de Vuelos")

La gráfica es la siguiente:

Serie_T2

#Serie de tiempo 3
ggplot(a2,aes(x=fechas,y=distancia))+geom_line(aes(colour=factor(origin)))+scale_x_date()+facet_grid(.~origin)+geom_smooth(col="black")+
 ggtitle("Media de la distancia de vuelo por año")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Media de la distancia de vuelo")+xlab("Fecha de Vuelos")

La gráfica es la siguiente:

Serie_T3

Revisando el “cruce” entre la cantidad de vuelos, la distancia media y el total de minutos de retraso se obtienen las siguientes gráficas.

#Cruce 1
ggplot(a2,aes(count,retrasos))+geom_point(aes(colour=origin))+facet_grid(.~origin)+geom_smooth(col="black")
 ggtitle("Scatter plot de Cantidad de vuelos vs retrasos ")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Cantidad de Vuelos")+xlab("Retrasos por Aeropuertos")

La gráfica que se obtiene es la siguiente:

SC1

#Cruce 2
ggplot(a2,aes(count, distancia))+geom_point(aes(colour=origin))+facet_grid(.~origin)+geom_smooth(col="black")+
 ggtitle("Scatter plot de cantidad de vuelos vs distancia media por año")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Cantidad de Vuelos")+xlab("Distancia media por Aeropuertos")

La gráfica es la siguiente:

SP2

#Cruce 3
ggplot(a2,aes(y=distancia,x=retrasos))+geom_point(aes(colour=origin))+facet_grid(.~origin)+geom_smooth(col="black")+
 ggtitle("Scatter plot entre la distancia media y los retrasos por año")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Media de la distancia de vuelo")+xlab("Retrasos por Aeropuertos")

La gráfica es la siguiente:

SC3

El único fin de las 6 gráficas anteriores es tratar de detectar alguna información o relación entre la información que con los datos originales no sea visible.

Analizando someramente las gráficas se puede observar en la primera gráfica que en los dos primeros aeropuertos el comportamiento es “similar”, ya que incremente la cantidad de vuelos de primavera hasta verano y posteriormente decrece cuando el año llega al invierno.La diferencia con el aeropuerto LGA que muestra un incremento conforme el año se acerca al invierno.

En la segunda gráfica se aprecia que para los 3 aeropuerto los retrasos incrementan en verano, con un poco de cuidado se aprecia que entre los meses de Febrero e inicio de Marzo se muestra un pico en los retrasos, el cual puede deberse a la temporada de cierre de nevadas.

El tercero resulta claro cual aeropuerto es requerido para vuelos con distancias mayores, JFK, y cual parece para vuelos cercanos. Revisando esto con la gráfica 1 se puede tener sospechas de que el incremento en la cantidad de vuelos en el aeropuerto LGA al cierre de año está relacionado con que se realizan vuelos cortos, lo cual puede estar relacionado con los festejos de cierre de año y periodos vacacionales.

Las últimas 3 gráficas son más sutiles, ya que se requeriría revisar la correlación y el coeficiente de información mutua para explorar si existe alguna relación interesante en los cruces. Por ejemplo la gráfica 5 muestra ciertas relaciones lineales negativa entre la cantidad de vuelos y la media de distancia en el aeropuerto LGA, pero en los otros dos no se muestra que exista dicha relación.

La gráfica 4 y 6 no muestran relaciones lineales, pero es posible que si tengan relaciones no lineales para lo cual se podría usar el índice de información mutual para tener algún indicio.

 Lo que debe de estar claro es que con unas agrupaciones y transformaciones se pudo explorar la información desde otra perspectiva y permite pensar en hacer cierto tipo de análisis, ejemplo las tres primeras gráficas permiten incitar en realizar un análisis de series de tiempo de los datos y con ellos crear un modelo predictivo de la cantidad de vuelos por mes o el comportamiento de los retrasos por mes.

Tratamiento 2

El siguiente ejemplo son dos partes, la primera es elegir el número de cola del avión con mayor cantidad de vuelos realizados y analizar sus comportamiento con respecto al año. Por último tomo un ejemplo que resulta similar al presentado en la página de referencia de la librería dplyr, con algunas ligeras variaciones.

Para elegir la cola de avión con mayor cantidad de vuelos, es decir; la variable tailnum agrupo la información con respecto a esa variable y resumo la información para conocer el registro con mayor número de vuelos.

#Agrupación
plane1<-flights2%>%
   group_by(tailnum,origin)%>%
   summarise(count=n(),retrasos=sum(arr_delay),med_distancia=mean(distance))

head(plane1)
#Source: local data frame [6 x 5]
#Groups: tailnum

 #tailnum origin count retrasos med_distancia
#1 D942DN JFK 1 2 944.0000
#2 D942DN LGA 3 124 824.6667
#3 N0EGMQ EWR 48 531 719.0000
#4 N0EGMQ JFK 27 361 517.6667
#5 N0EGMQ LGA 277 2622 688.2816
#6 N10156 EWR 144 1706 758.6458

max(plane1$count)
#536
filter(plane1,count==536)
#Source: local data frame [1 x 5]
#Groups: tailnum

#tailnum origin count retrasos med_distancia
#1 N725MQ LGA 536 2508 561.4515

De este modo tenemos que N725MQ es el registro que tienen mayor cantidad de vuelos. Entonces filtro la información original para analizar solo los datos correspondientes a este registro.

#Filtro
Plane_N725MQ=filter(flights2,tailnum=="N725MQ")
#Observo en breve la información
head(Plane_N725MQ)
#Source: local data frame [6 x 16]

#year month day dep_time dep_delay arr_time arr_delay carrier tailnum
#1 2013 1 1 832 -8 1006 -24 MQ N725MQ
#2 2013 1 1 1305 -10 1523 3 MQ N725MQ
#3 2013 1 1 1840 -5 2055 25 MQ N725MQ
#4 2013 1 2 1205 0 1349 4 MQ N725MQ
#5 2013 1 2 1805 -5 1946 1 MQ N725MQ
#6 2013 1 3 1131 -4 1314 -16 MQ N725MQ
#Variables not shown: flight (int), origin (chr), dest (chr), air_time (dbl),
# distance (dbl), hour (dbl), minute (dbl)

#Agrego dos variables nuevas
Plane_N725MQ1=mutate(Plane_N725MQ,velocidad=distance/air_time*60,fechas=as.Date(paste(month,day,year,sep="/"),"%m/%d/%Y"))

Con lo anterior puedo seleccionar las columnas que deseo analizar y por medio de la librería Reshape2 puedo cambiar su estructura para apreciar su comportamiento con respecto al tiempo, es decir; como serie de tiempo.

#Explorando el comportamiento de su velocidad media y la media de retrasos al arribar

#Se procesan los datos para construir otra estructura de datos 

B1<-Plane_N725MQ1%>%
 group_by(fechas,origin, dest)%>%
 summarise(count=n(),retrasos=mean(arr_delay),vel_media=mean(velocidad))

head(B1)
Source: local data frame [6 x 6]
Groups: fechas, origin

 fechas origin dest count retrasos vel_media
1 2013-01-01 LGA CRW 1 25 277.5000
2 2013-01-01 LGA DTW 1 3 295.2941
3 2013-01-01 LGA RDU 1 -24 335.8442
4 2013-01-02 LGA BNA 1 1 342.0896
5 2013-01-02 LGA RDU 1 4 300.6977
6 2013-01-03 LGA CLE 1 -16 318.2278

#Gráficas para explorar el comportamiento en el año

ggplot(B1,aes(x=fechas,y=vel_media,colour=dest))+geom_line()+scale_x_date()+geom_smooth(col="black")+
 ggtitle("Comportamiento de la velocidad en el año")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Velocidad media de vuelo")+xlab("Fecha de Vuelos")

ggplot(B1,aes(x=fechas,y=retrasos,colour=dest))+geom_line()+scale_x_date()+geom_smooth(col="black")+
 ggtitle("Comportamiento de los retrasos en el año")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Media de los retraos en los vuelos")+xlab("Fecha de Vuelos")

Las gráficas que se obtienen son las siguientes:

N725MQ

N725MQ_retrasos

En las dos gráficas se aprecian comportamiento peculiares para ciertos destinos de vuelo, cada sigue un comportamiento. En la primera gráficas resalta el comportamiento de BNA y CLE, el primero está sobre la línea de tendencia y el segundo tiene bajas de media de velocidad considerables para el periodo de Abril a Julio.

En la segunda gráfica se aprecia un comportamiento de mayor media en los retrasos entre los meses de Abril-Mayo y en otro momento en los meses de Junio-Julio.

En resumen, esta exploración permite centralizar el análisis en los destinos que resultan con comportamiento más extraños, con esta sospecha se puede procesar la información para analizar como se comportan el resto de vuelos con respecto a esos destinos.

Otro modo de procesar los datos  y realizar el análisis es revisar como se comportan los retrasos pero dividida por aeropuerto de origen de vuelo, esto se puede hacer fácil haciendo uso de la función melt de la librería Reshape2.

#Separación del análisis

#Se procesan lo datos originales
B2<-Plane_N725MQ1%>%
 group_by(fechas,origin, dest)%>%
 summarise(retrasos_arr=mean(arr_delay),retrasos_dep=mean(dep_delay))

#Construyo una table que permita el análisis de los datos de manera sencilla

datos=melt(B2,id=c("fechas","origin","dest"))

#Con el comando head() se visualiza como se ordena la información
head(datos)
#     fechas origin dest variable value
#1 2013-01-01 LGA CRW retrasos_arr 25
#2 2013-01-01 LGA DTW retrasos_arr 3
#3 2013-01-01 LGA RDU retrasos_arr -24
#4 2013-01-02 LGA BNA retrasos_arr 1
#5 2013-01-02 LGA RDU retrasos_arr 4
#6 2013-01-03 LGA CLE retrasos_arr -16

#Se analizan los datos gráficamente

ggplot(data=datos,aes(x=fechas,y=value,colour=dest,group=variable))+geom_line()+scale_x_date()+
 ggtitle("Comportamiento de los retrasos en el año")+theme(plot.title=element_text(lineheight = 1,face='bold'))+ylab("Media de los retraos en los vuelos")+xlab("Fecha de Vuelos")+
 facet_grid(.~origin)

La gráfica es la siguiente:

Retrasos_origen-destino

En este último ejemplo queda claro cual es el aeropuerto que se usa para despegar y el comportamiento de las medias de retrasos muestra ciertos picos, una ligera alza en los meses de Junio-Julio-Agosto. Este último gráfico se puede obtener desde la primera estructura de datos analizada, la única finalidad de hacer este último ejemplo era mostrar como melt() modifica la información no regresa algo parecido a una tabla pivot de Excel.

La última es prácticamente equivalente a la que se puede consultar en la página de referencia de dplyr, lo único que agregué fue mostrar la referencia de origen de vuelo.

#Última clasificación
#Se agrupan por 2 columnas
by_tailnum <- group_by(flights, tailnum,origin)
head(by_tailnum)
#Se construye el resumen de los datos
 
delay <- summarise(by_tailnum,
 count = n(),
 dist = mean(distance, na.rm = TRUE),
 delay = mean(arr_delay, na.rm = TRUE))

delay <- filter(delay, count > 20, dist < 2000)

#Se genera la gráfica para ver el cruce

ggplot(delay, aes(dist, delay)) +
 geom_point(aes(size = count,colour=origin), alpha = 1/2) +
 geom_smooth() +
 scale_size_area()+
 xlab('Media de la Distancia')+
 ylab('Media de los Retrasos')+
 ggtitle('Cruce de la media de las distancia vs media de los retrasos')+
 theme(plot.title=element_text(lineheight = 1,face='bold'))

La gráfica que se obtiene es la siguiente:

Cruce_dist_vs_retrasos

El patrón que se muestra posiblemente pueda ser estudiado con alguna técnica de clasificación la cual indicaría un aproximado de como se aglomera la información, pensando burdamente en usar cluster supongo que jugando con 5 cluster podría obtenerse un modelo simple sobre los datos.

En Python

PENDIENTE

Anuncios

Algo de procesamiento de datos

Algunas herramientas de manipulación de datos

En general la intención de esta categoría es  comentar sobre las técnicas de exploración, pero revisando y diseñando las entradas me di cuenta que dejé de lado una cosa que creo es fundamental, el procesamiento de datos o pre-procesamiento.

Creo que es central el tema, ya que con un poco de suerte uno tienen la información ordenada y mal que bien lista para poderla usar y explorar.

Ejemplo, ingresando a la siguiente liga yahoo uno puede extraer datos de yahoo fincance sobre el el indicador S&P, tiene varios formatos y la información está lista para analizarse, todo se encontrará bien ordenado. Pero no pasa lo mismo si uno quiere analizar algún texto, ejemplo; si uno ingresa la http://www.gutenberg.org puede descargar algún texto en formato HTML, el cual requiere procesarse para posteriormente poder analizarse con técnicas de Procesamiento de Textos o Text Mining, pero peor aún si uno construye un corpus que es un conjunto de textos, procesarlos requiere todo un labor.

Por otro lado, si se tienen la información ordenada lo que uno en ocasiones requiere es ver la relación entre algunas variables o estimar la media o conocer los máximos o mínimos. Para esto se requiere saber como manipular los datos.

 La exploración y construcción de algún modelo según sea el interés u objetivo, requiere de aprender o conocer los datos. Si bien para esto están los procesadores de bases de datos, lo que uno trata con herramientas como R o Python, es hacer uso de otro tipo de algoritmos que posiblemente requieren manipular bases considerablemente grandes antes de implementar el algoritmo.

Tratando de limitar la entrada comentaré sobre algunas librerías para procesamiento de datos en R y sobre el procesamiento de datos en Python. Por último agrego algunos comentarios sobre el procesamiento con Julia.

Librerías en R.

Es posible que existan más librerías que hacen manipulación de datos en R, pero las recomendadas y sobre todo reconocidas en varios cursos como en DataCamp, son reshape2, dplyr y data.table.

Comento sobre las tres y dejo los artículos donde pueden consultar información al respecto en la lista de  referencias.

Reshape2….después de reshape

La librería fue desarrollada por Hadley Wickham, la última versión se llama reshape2 la cual sufrió algunos cambios con respecto a la primera versión, como toda librería actualizada. La utilidad de la librería la trato de explicar con los ejemplos y estos son tomados del artículo [1].

Los datos para los ejemplos se cargan dentro de la misma librería. Este código lo corrí en RStudio.

#Cargamos las librerías para el ejemplo

library(reshape2)
library(ggplot2)

#En caso de que se quiera ver la información de la libreria se puede poner el comando
#library(help='reshape2')

#Primer ejemplo
data("smiths")

#Exploramos los datos

head(smiths)
dim(smiths)

#Se observa que solo cuenta con dos filas y 5 columnas
#La primera función importante "melt"
#para ver información de la función se puede usar
#?melt o help(melt)

#Se definen los id y las medidas

melt(smiths,id=c("subjects","time"),measured=c("age","weight","height")
#R regresa algo como esto:
# subject time variable value
#1 John Smith 1 age 33.00
#2 Mary Smith 1 age NA
#3 John Smith 1 weight 90.00
#4 Mary Smith 1 weight NA
#5 John Smith 1 height 1.87
#6 Mary Smith 1 height 1.54

#Obtenemos el mismo resultado de la siguiente forma

melt(smiths,id=1:2,measured=c("age","weight","height")

#Se hace la misma petición pero evitando los datos NA

melt(smths,id=1:2,measured=c("age","weight","height"),na.rm=TRUE)

# subject time variable value
#1 John Smith 1 age 33.00
#2 John Smith 1 weight 90.00
#3 John Smith 1 height 1.87
#4 Mary Smith 1 height 1.54

La función melt lo que hace es elegir de la pequeña tabla de datos las variables que considera id y el resto las considera como variables sobre las cuales muestra sus valores para cada id. Si se solicita la dimensión o tamaño de la tabla al usar melt se observa que hay un cambio en la estructura de la tabla. Es decir, en una petición por melt, pedir dim(melt(….)) deja ver que se cambio la forma de la tabla, de allí el origen del nombre.

La razón de su utilidad es que se pueden elegir varias variables que se desean explorar como una sola, en este caso subject y time y para cada una de sus posibles combinaciones se observan los valores de las variables age, weight y height.

Esto a primera vista no tienen relevancia o no se aprecia, pero con una tabla de datos poder modificar su estructura facilida un  rápido el análisis tanto gráfico como exploratorio. En el último ejemplo se usa una base de tamaño mayor. Pero antes comento sobre otra función.

#Función cast
Se observa a forma orginal del data.frame smiths

# subject time age weight height
#1 John Smith 1 33 90 1.87
#2 Mary Smith 1 NA NA 1.54

#Se construye una nuevo data.frame con la función melt

smithsm=melt(smiths,id=1:2,measured=C("age","weight","height"),na.rm = TRUE,value.name="Valores")

#Se observa el data.frame construido

smithsm 

#subject time variable value
#1 John Smith 1 age 33.00
#2 John Smith 1 weight 90.00
#3 John Smith 1 height 1.87
#4 Mary Smith 1 height 1.54

dcast(smithm,subject+time~variable)
#Se recupera el data.frame orgianal
 subject time age weight height
1 John Smith 1 33 90 1.87
2 Mary Smith 1 NA NA 1.54

Lo que se observa del código anterior es que se recupera el arreglo original, pero no solo eso hace la función dcast. Con algo de cuidado se observa que dentro de la función se ingresó una expresión Col1+Col2~Fila1+Fila2+….+Filan=variable.

Esta expresión indica la relación entre las columnas y las filas de los datos, que es lo que mostrará esta función. Se puede agregar un elemento más a la función dcast y hace parecer que melt y esta función funcionan de manera inversa. El siguiente ejemplo muestra como usarla para estimar cierto valores.

Para el ejemplo hice uso de una base que está en la librería reshape2, french_fries.

#Cargamos los datos french_fries 
data(french_fries)
ffm<-melt(french_fries,id=1:4,na.rm = TRUE)
#Se eligen solo los datos que no contienen NA
#Se explora la información
head(ffm)
dim(ffm)
#Se calcula con la función cast la media de cada variable, en este caso los valores de variable son:potato,buttery,grassy,rancid y painty

dcast(ffm,rep~variable,mean)
# Se obtiene una table como la siguiente:
# rep potato buttery grassy rancid painty
#1 1 6.956196 1.863663 0.5752161 3.916427 2.361383
#2 2 6.948851 1.784195 0.7528736 3.788218 2.682133

dcast(ffm,.~variable,mean)
# . potato buttery grassy rancid painty
#1 . 6.952518 1.823699 0.6641727 3.85223 2.521758

Lo que hace el código anterior es primero cargar los datos, después modificar sus estructura original para obtener una tabla con las primeras 4 variables como id, esto mediante la función melt. Usando la función dcast, se estima primero desde ffm la relación entre rep y las variables, se calcula su media. En la segunda petición de la función dcast se estima la media en general de las variables, sin separarse por rep como en el primer ejemplo.

El último ejemplo es equivalente al que se muestra en las referencias [1,2].

#Caso de estudio de la base de datos french_fries

data(french_fries)
dim(french_fries)
#[1] 696   9

#Se modifica la estructura de los datos por medio de melt
ffm<-melt(french_fries,id=1:4,na.rm=TRUE)
head(ffm)
# time treatment subject rep variable value
#1 1 1 3 1 potato 2.9
#2 1 1 3 2 potato 14.0
#3 1 1 10 1 potato 11.0
#4 1 1 10 2 potato 9.9
#5 1 1 15 1 potato 1.2
#6 1 1 15 2 potato 8.8

dim(ffm)
#[1] 3471    6

#Se revisan los valores de subject y de time
summary(ffm$time)
# 1 2 3 4 5 6 7 8 9 10 
#360 360 360 360 355 360 359 357 300 300 
summary(ffm$subject)
# 3 10 15 16 19 31 51 52 63 78 79 86 
#270 300 295 299 300 270 300 300 300 300 267 270

#Se hace un cruce entre subject y time para determinar analizar entre la pareja de datos entre los cuales no se tienen información

#Se agregan inicialmente los margenes y en el segundo comando no.
dcast(ffm,subject~time,length,margins=T)
dcast(ffm,subject~time,length)

#Se pueden analizar los valores máximos de cada una de las variables por medio de dcast

dcast(ffm,variable~.,max)

#Construye la gráfica de los valores de las variables
library(ggplot2)
qplot(value,data=ffm,geom="histogram",facets=.~variable,bindwidth=1,main="Histogramas de las variables")

La gráfica que se obtienen es la siguiente:

Histo_ejem_da

La idea general del ejemplo anterior es, construir un data.frame , explorar el comportamiento de los campos sin valor entre dos variables y revisar sus valores máximos. Por último construir una herramienta gráfica, en este caso un histograma; para revisar el comportamiento de las variables. En las referencias se explican más detalles sobre el ejemplo.

La librería reshape2 cuenta con más funciones, sobre las cuales no menciono nada, pero melt y cast son las más destacadas. Para conocer como usar el resto de funciones se puede revisar el manual de uso, referencia[3].

Librería dplyr…antes plyr

Esta librería también fue diseñada por Hadley Wickham, es fundamental debido a que los data.frame son usados como objetos y en general se usa para grandes tablas de datos.

La importancia de este paquete está ligada a la metodología de trabajo “split-apply-combine”, que fue planteada como una metodología similar a mapReduce que fue la solución de manipulación y procesamiento de grandes volúmenes de datos en Google, sobre este tema se puede revisar la referencia [4,5].

Para ser breve comparto un ejemplo publicado en parte en  [6] y trato de comentar de modo breve lo que se hace con esta librería.

Tiene alta relevancia con el procesamiento de datos, por lo cual invito a que se consulte en otros blog con algún tutorial amplio o en algunas de las referencias que dejo.

Cuando se manejan datos uno espera dos cosas, que sea rápido y que sea intuitivo, es decir; que sea fácil para uno pueda recordar los nombres de algunas funciones o la lógica al programar con los comandos. Para replicar el código se requiere una librería hflights que contiene solo una base considerablemente grande para mostrar como se usan las funciones principales de dplyr, o en su defecto se puede usar la librería nycflights13.  Este código lo corrí en RStudio.

#Se se cargan las librerías.

library(dplyr)
library(hflights)

#Cargamos los datos del ejemplo
#Se exploran el tipo de datos y las dimensiones de la tabla.
data(hflights)
head(hflights)
dim(hflights)
#[1] 227496 21

#Data frame local, mediante la función tbl_df()

flights<-tbl_df(hflights)
flights

#Para ver más registros de los dados por default 

print(flights,n=15)

#Convertir en un data frame normal y ver toda la información de manera normal en R

data.frame(head(flights))

###################################################
#Uso de la función filter()

#Método clásico en R
#Eligiendo vuelos de Enero 1

flights[flights$Month==1 & flights$DayofMonth==1,]

#Usando filter para elegir valores del dataframe

filter(flights,Month==1,DayofMonth==1)

#Usando filter y la pipe para condiciones "or"

filter(flights,UniqueCarrier=="AA"|UniqueCarrier=="UA")
#Uso del operador %in%

filter(flights,UniqueCarrier %in% c("AA","UA"))

###################################################
#Función slice
slice(flights,1:13)

###################################################
#Función arrange()
arrange(flights,Year,Month,DayofMonth)
arrange(flights,desc(FlightNum))

###################################################
#Selección de tres columnas
#Método clásico
flights[,c("DepTime","ArrTime","FlightNum")]
#Por medio de dplyr
select(flights,DepTime,ArrTime, FlightNum)

#Otras opciones para seleccinoar
select(flights, Year:DayofMonth,contains("Taxi"),contains("Delay"))

#Asignando títulos a los valores de algunas columnas
select(flights,Mes=Month,Vuelo=FlightNum)

El código anterior, si uno va revisando las salidas en R no resulta nada extraño, pero se pueden observar ciertas comodidades al seleccionar o al filtrar la información, que al hacerlo de manera normal en R resultaría más engorroso.

La siguiente parte del código se hace uso de comandos u operadores propios de la librería.

#Usos de operadores
#Anidación

#Método 1-por filtro
filter(select(flights, UniqueCarrier, DepDelay), DepDelay > 60)

#Método 2-por cadena
flights%>%
 select(UniqueCarrier, DepDelay)%>% 
 filter(DepDelay > 60)

#Distancia Euclideana entre dos vectores

x1<-1:5;x2<-2:6
sqrt(sum((x1-x2)^2))

#Método de cadena para para la distancia Euclideana
(x1-x2)^2%>%sum()%>%sqrt()

##################################################
#Reordernar filas-arrange
#Método estándas en R

flights[order(flights$DepDelay),c("UniqueCarrier","DepDelay")]

#Método en dplyr

flights%>%
 select(UniqueCarrier,DepDelay)%>%
 arrange(DepDelay)

#Método en dplyr en orden descendente

flights%>%
 select(UniqueCarrier,DepDelay)%>%
 arrange(desc(DepDelay))

####################################################
#Mutate
#Creando nuevas variables en los datos
#Método clásico por R

flights$Speed<-flights$Distance/flights$AirTime*60
#Visualización de la nueva variable
flights[,c("Distance","AirTime","Speed")]

#Método 2-Aproximación por dplyr

flights%>%
 select(Distance,AirTime)%>%
 mutate(Speed=Distance/AirTime*60)

flights<-flights%>%mutate(speed=Distance/AirTime*60)

####################################################
#summarise: Reduce variables a valores

#Método estándar en R

head(with(flights, tapply(ArrDelay, Dest, mean, na.rm=TRUE)))
head(aggregate(ArrDelay ~ Dest, flights, mean))

#Método por dplyr

flights %>%
 group_by(Dest) %>%
 summarise(avg_delay = mean(ArrDelay, na.rm=TRUE))

#Se calcula el porcentaje de vuelos cancelados o desviados para cada aerolínea

flights %>%
 group_by(UniqueCarrier) %>%
 summarise_each(funs(mean), Cancelled, Diverted)

Se observa que los operadores permiten tener mejor legibilidad sobre las operaciones pedidas en el data.frame. Por otro lado al contar con nombres intuitivos permite que sea claro al leer el código.

Por último, solo agrego un ejemplo de la referencia [6] de construir subconjuntos y graficar el comportamiento medio de retrasos.

#Procesamiento y gráfica de datos procesados
#Cargamos las librerías necesarias

library(ggplot2)

by_tailnum <- group_by(flights, TailNum)
delay <- summarise(by_tailnum,
 count = n(),
 dist = mean(Distance, na.rm = TRUE),
 delay = mean(ArrDelay, na.rm = TRUE))
delay <- filter(delay, count > 20, dist < 2000)

#Se visualiza el data.frame

delay
dim(delay)

#Distancia media por vuelo

ggplot(delay, aes(dist,delay)) +
 geom_point(aes(size = count), alpha = 1/2,colour='purple') +
 geom_smooth() +ggtitle("Variación de los retrasos contra distancia")+xlab("Distancia")+ylab("Retraso")


La gráfica que se obtiene es la siguiente:

Retrasos_vuelos

 

A primera vista no parece del todo relevante la librería, pero algunas de las cosas que no comento es la conexión con bases de datos, esto permite hacer un análisis con herramientas más ricas de estadística y mejores gráficas propias de R, que las que cuenta un gestos de bases de datos.

Al final, cuando se hace un análisis de datos dos piezas son importantes, el enfoque de la investigación que se realice y las herramientas con las cuales se haga. En este caso, explotar el uso de esta librería dependerá del proyecto que se aborde.

Nota: Para procesar algunas tablas también se puede hacer mediante la librería plyr, la cual es un poco más lenta para tablas grandes pero es igual de amigable que dplyr.

Librería data.table

La librería es de años recientes y poco a poco gana popularidad, se ha mejorado para que sea aún más rápida. Prácticamente sus uso es para procesar datos en R. En buena medida la sintaxis es similar a SQL.

En un base como las que se encuentran en las librerías de R no se notará su utilidad, pero en particular para bases grandes permite hacer manipulación de los datos. Existen varias comparaciones en cuanto al rendimiento contra tiempo al comparar  operaciones similares entre dplyr y data.table, la ventaja de la primera es la facilidad de operar con sus funciones y la segunda resulta ser más eficiente ante volúmenes considerablemente muy grandes.

Solo comento algo breve sobre la creación de tablas en esta librería, la definición de key’s y un poco sobre la agrupación. Se puede ver más detalles en las referencias [7,8]

#Código de data.table
#Se carga la librería

library(data.table)

#Se compara la creación de un data.frame y una tabla 
DF<-data.frame(x=c("b","b","b","a","a"),v=rnorm(5))
DF

class(DF)

#Generado con data.frame de data.table

DT<-data.table(x=c("b","b","b","a","a"),v=rnorm(5))

DT
class(DT)

#Importan datos de  R project

data(cars)
head(cars)

#Se transforman a una data.table

CARS=data.table(cars)
CARS

#La observación es sobre el indicador MB
#Muestra las tablas creadas con data.table
tables()

#Se se pueden aplicar las funciones estándar sobre el data.table

sapply(DT,class)


El código anterior muestra solo como crear tablas con data.table, al observarlas resultan prácticamente iguales a un data.frame estándar y heredas el tipo de funcionalidades o aplicaciones de funciones comunes en R, como sapply.

#Key en data.table

#Se usa DT del código pasada

setkey(DT,x)
DT

#Se observa en tables() que ahora key tienen "x" respecto a DT

#Ejemplo para seleccionar filas
DT[2,]
DT[x=='b',]
#Despues de definir la key se tienen
DT["b",]

Las key puedes ser definidas por varias columnas, al observar las tablas definidas en data.table resultan tener comportamientos similares a los data.frame normales.

Un modo de comparar los procesos normales de R con respecto a los procesos de data.table es comparando los tiempos requeridos para seleccionar partes de una tabla de tamaño, la tabla contendrá 10 millones de filas y 3 columnas.

El siguiente código son solo 3 ejemplos comparativos del tiempo que requiere R y del tiempo que se requiere en data.table para seleccionar o procesar la misma muestra de datos.

#Ejemplos comparativos

#Comparación de busqueda vector scan y binary search

grpsize = ceiling(1e7/26^2)
#Valor
grpsize

#Definición y tiempo de creación d eun data.frame
tt=system.time( DF <- data.frame(
 x=rep(LETTERS,each=26*grpsize),
 y=rep(letters,each=grpsize),
 v=runif(grpsize*26^2),
 stringsAsFactors=FALSE))
#Se revisan las propiedades generales del data.frame
head(DF)
tail(DF)
dim(DF)

tt=system.time(ans1 <- DF[DF$x=="R" & DF$y=="h",]) # 'vector scan'
tt
#Se revisan los datos obtenidos de la selección de valores
head(ans1)
tail(ans1)
dim(ans1)

#Se crea una data.table
DT=as.data.table(DF)
system.time(setkey(DT,x,y))

ss=system.time(ans2 <- DT[list("R","h")])
ss
head(ans2)
tail(ans2)
dim(ans2)

############################
#Otro ejemplo de velocidad entre R y data.table

#Por data.table
system.time(ans1 <- DT[x=="R" & y=="h",])

#Por R 
system.time(ans2 <- DF[DF$x=="R" & DF$y=="h",])

#Validamos que son la misma tabla
mapply(identical,ans1,ans2)

#########################################
#Ejemplo de aplicación de una función sobre las columnas

#Por medio de R
ttt=system.time(tt <- tapply(DT$v,DT$x,sum)); ttt

head(tt)

#Por medio de data.table
sss=system.time(ss <- DT[,sum(v),by=x]); sss

head(ss)

Los resultados que se obtendrán al replicar al código dan una idea de las mejoras que se obtienen al manipular datos con data.table, pero hay recientes estudios donde se compara con dplyr y pandas( de Python). Pero aún así se está mejorando parte de los algoritmos para que sea aún más eficiente. Otra opción es revisar los ejemplos que cuenta la librería , basta con poner en R el comando example(data.table).

Un ejemplo de las ventajas se puede ver en la siguiente liga:

http://stackoverflow.com/questions/11054208/lapply-and-do-call-running-very-slowly

Espero las 3 librerías den una idea en general de lo que se puede hacer en R para procesar datos, unos cursos breves pero que dan una idea global se encuentran en DataCamp, de los cuales la plataforma permite realizar algunos de manera libre y otros tienen costo.

Pandas-Python

La librería para realizar análisis de datos en Python es Pandas, la cual en casi todas las distribuciones de paquetes de librerías o módulos, como Anaconda; viene por default.

Existe mucha referencia respecto al manejo de dicho módulo. Los objetos principales son Series y DataFrame, los cuales son nombres similares a los usados en R project. 

El módulo fue creado por Wes McKinney y la documentación, casos de estudio y todo lo relacionado con pandas se puede consultar en la referencia[9], la cual es sumamente amplia y cuanta con ligas a otras referencias de manuales breves, ejemplos de uso y actualizaciones. El texto clásico y base para aprender sobre este módulo fue escrito por el mismo Wes, es la referencia [10]. Por supuesto es altamente recomendable y los datos para realizar los ejemplos, se encuentran en el repositorio:

https://github.com/pydata/pydata-book

Para el uso del código siguiente considero que se tiene instalado Python 2.7.9 y de preferencia con el paquete de módulos de Anaconda.

El ejemplo para verificar que funciona adecuadamente la el conjunto de módulos con panda, se corre el siguiente código en ipython.

#Prueba 
%pylab
plot(arange(10))

 El código debe de arrojar la siguiente imagen.

Pandas_1

Lo que se hizo fue probar que %pylab, las librerías básicas de desarrollo en ipython se encuentran funcionando. Los módulos base son numpy, matplotlib y pandas.

En los ejemplos solo muestra el uso de pandas para manipulación de datos, con la finalidad de mostrar ejemplos similares a los de R project. En el código de ejemplo considero en general la estructura de datos DataFrame y solo al final doy un breve ejemplo del uso de la estructura Series.

Creación de DataFrame y manipulación básicas.

#Uso de Pandas
#Considerando que se inicio ipython 

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from pandas import DataFrame

#Se definen datos para creas un DataFrame

data={'Estado':['Jalisco','Sonora','Guanajuato',Veracruz'],'Población':['7838010','2892464','5769524','7985893'],'clave':['09','13','14','23']}

Estados=DataFrame(data)

En Ipython se obtendrá una tabla de datos, sobre la cual se puede manipular la columnas, las filas, agregar nuevas columnas y filas. Si se desea conocer aspectos básicos o métodos que  la estructura de datos DataFrame tienen por default, se puede hacer lo siguiente para conocerlos:

#Datos
Estados.<tabs>

Se presentará una lista de todos los métodos disponibles, ejemplo:

#Métodos
Estado.shape
#Dará el número de columnas y filas que tienen el DataFrame

Estado.head()
#Mostrará solo la cabecera, es decir; una muestra de los primeros 4 registros o filas del DataFrame

Estado.describe()
#En caso de tener una tabla con muchos datos, da un resumen estadístico de la información 

#Si se desea sabes para que sirve cierto método se hace uso de los siguiente.
help(Estados.*)
#Donde en lugar de * se pone el método que se desea conocer

Varios aspectos no menciono, pero en caso de no estar familiarizado con estructuras de datos, recomiendo la referencia [11]. Lo que se oculta al construir el DataFrame por este método es que se asigna data={}, estos paréntesis indican que es un diccionario y [] indica que es una lista.

En R project se hace uso de ciertas librerías para manipular los datos y poder procesarlos de mejor manera, como reshape o dplyr, en python todas esa operaciones se hacen solo con pandas.

Más aún, una postura ante el análisis de datos es la metodología “Split-Apply-Combine”, la cual fue descrita y ejemplificada por Hadley Wickham en la referencia [12]. Esta metodología fue considerada por Wes para el desarrollo de algunos aspectos de pandas, sobre todo en este tema comparto una entrada en esta categoría.

Ejemplo es sencillo y solo muestro algunas operaciones o procesos simples, para mayor detalle y sobre todo para revisar ejemplos de como hacer usos de pandas se puede consultar en la referencia [9].

En el siguiente código se extraen datos desde yahoo finance de los indicadores AAPL e IBM. Se obtiene  un DataFrame de datos, los cuales para mostrar algunas cosas básicas se agregan algunas columnas, de piden algunos datos básicos para explorar la información y se utilizan los dos DataFrame solo para mostrar una operación simple de “Muchos a Muchos”.Se hacen algunas operaciones para agrupar y transformar los datos y por ultimo una gráfica simple sobre el comportamiento de los cierres de los dos indicadores.

#Ejemplo Pandas
#Se cargan las librerias necesarias

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pandas import DataFrame
import pandas.io.data
import datetime

#Se cargan datos desde yahoo para AAPL y IBM
aapl=pd.io.data.get_data_yahoo('AAPL',start=datetime.datetime(2010,1,1),end=datetime.datetme(2015,1,1))
ibm=pd.io.data.get_data_yahoo('IBM',start=datetime.datetime(2010,1,1),end=datetime.datetme(2015,1,1))
 
#Se exploran los datos, aspectos básicos solo para aapl

type(aapl)
aapl.describe()
aapl.columns
aapl.shape
aapl.head()

#Las dimensiones de los datos

aapl.shape
ibm.shape

Un podo de Missing Values.

#Ejemplo Pandas
#Para trabajar con los Missin Value se toman datos de aapl

aapl_Close=aapl.Close
type(aapl_Close)
#Se oservará que es una estructura de datos serie
#Se toman 200 enteros de entre 0 y 1258 como ejemplo de Missing Value

ind=np.random.randint(1258,size=(200))
aapl_Close[ind]=np.nan

#Para identificar que se cuentan con Missin Value
aapl_Close.isnull()
aapl_Close[aapl_Close.isnull()]
aapl_Close[aapl_Close.notnull()]

#Para elegir solo los datos sin nan
aapl_Close.dropna()
#Para asigar algun valor a los nan, ejemplo se asigna el valor cero "0"
aapl_Close.fillna(0)

Algunas operaciones como la librería Reshape en R project.

#Ejemplo Pandas
#Se define otra columna para elegir el indice como columna

aapl['ind']=aapl.index 

#Se define un nuevo DataFrame por medio de melt

df=pn.melt(aapl,id_vars=['ind'])
df.head()
#Se modifica la estructura de los datos
#Como ejemplo usa df para construir una tabla pivot

pivoted=df.pivot('ind','variables','value')

pivot.head()
#Tienen la misma estructura de los datos originales appl

Ejemplos simple de muchos a muchos y agrupación de los datos.

#Ejemplo Pandas
ibm['index']=ibm.index 

df1=pd.merge(aapl,ibm,left_on='ind',right_on='index',suffixes=('_aapl','_ibm'))

df1.head()
df1.shape
#Se obtienen una tabla con todos los datos de los dos indicadores

#####group by######

#df que proviene de melt
df2=df.groupby('variable')

#Se genera un DataFrame con estructura distinta al origina, el cual muestra agrupamientos por los valores de "variable"
df2.head()

#Algunas funciones sobre el DataFrame agrupado

df2.agg([np.max,np.min,np.mean,np.std])

#Ejemplo de groupby and transform

#Se contruye una Series de los datos de AAPL
aapl.head()
ts=aapl.Open

#Se revisa el tipo de datos y la forma
type(ts)
ts.head()

kye=lambda x:x.year
zscore:lambda x:(x-x.mean())/x.std()

#Caso 1

ts_trans=ts.groupby(key).transform(zscore)

TS_grp=ts_trans.groupby(key)
TS_grp.mean()
TS_grp.std()

#Caso 2

grp=ts.groupby(key)
grp.mean()
grp.std()

#Gráfica de los datos de cierre de los dos inficadores

Indicadores=DataFrame({'AAPL_Close':df1.Close_aapl,'IBM_Close':df1.Close_ibm})
Indicadores.plot()
plt.show()

La gráfica que se obtiene es la siguiente:

Pandas_2

Espero que con este sencillo ejemplo se aprecie que las herramientas de Python para hacer data analysis son bastante buenas, rápidas y dentro de Ipython se tienen prácticamente un entorno de desarrollo solo basta agregarle un block de notas para escribir el código. En la referencia [9] se pueden consultar todos los detalles sobre pandas, muchas cosas al respecto no las menciono pero creo que el mejor lugar para aprender es allí.

Data.Frame-Julia

PENDIENTE DE TERMINAR

 

Tutoriales:

1.-https://www.youtube.com/watch?v=8SGif63VW6E

2.-https://www.youtube.com/watch?v=qLrdYhizEMg

3.-https://www.youtube.com/watch?v=MvH1eTdsekA

Referencias:

1.-http://www.jstatsoft.org/v21/i12/paper

2.-http://had.co.nz/thesis/practical-tools-hadley-wickham.pdf

3.-http://cran.r-project.org/web/packages/reshape2/reshape2.pdf

4.-http://www.jstatsoft.org/v40/i01/paper

5.-http://static.googleusercontent.com/media/research.google.com/es//archive/mapreduce-osdi04.pdf

6.http://cran.rstudio.com/web/packages/dplyr/vignettes/introduction.html

7.-http://cran.r-project.org/web/packages/data.table/vignettes/datatable-intro.pdf

8.-http://blog.yhathq.com/posts/fast-summary-statistics-with-data-dot-table.html

9.-http://pandas.pydata.org/pandas-docs/stable/index.html

10.-http://shop.oreilly.com/product/0636920023784.do

11.-http://interactivepython.org/runestone/static/pythonds/index.html