Friday, May 16, 2014

Julia versus R - Jugando un poco

Así que...a medida que pasa el tiempo, me estoy volviendo más experto en Julia...lo cual es algo medianamente fácil puesto que la curva de aprendizaje es bastante rápida...

Decidí cargar un archivo con 590,209 registros que obtuve de Freebase...el archivo en cuestión contiene Actores y Actrices de películas...pueden darle un pequeño vistazo aquí...


Para esta prueba, estoy usando mi Linux en VMWare corriendo con 2 GB of RAM...ejecutando Ubuntu 12.04.4 (Precise)

Para R, no estoy usando ningún paquete en particular...solo R plano...versión 2.14.1 y para Julia versión 0.2.1, estoy usando el paquete DataFrames...

Veamos primero el código fuente de R junto con su tiempo de procesamiento...

Actors_Info.R
start.time <- Sys.time()
if(!exists("Actors")){
Actors<-read.csv("Actors_Table.csv", header=TRUE, 
                     stringsAsFactors=FALSE, colClasses="character", na.strings = "")
}
Actors<-unique(Actors)
Actors<-Actors[complete.cases(Actors),]
Actor_Info<-data.frame(Actor_Id=Actors$Actor_Id,Name=Actors$Name,Gender=Actors$Gender)
Actor_Info<-Actor_Info[order(Actor_Info$Gender),]
write.csv(Actor_Info,"Actor_Info_R.csv",row.names=TRUE)
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken

Este código va a preguntar si el archivo ya ha sido cargado, si no...va a cargarlo...luego, va a eliminar los registros repetidos, borrar todos los nulos o NA's y luego crear un nuevo Data Frame, ordenarlo por "Gender" y luego escribir un nuevo archivo CSV...el tiempo va a ser tomado para medir su velocidad...vamos a ejecutarlo dos veces...la primera vez el archivo no va a estar cargado...la segunda vez si estará...y eso debería incrementar altamente el tiempo de ejecución...



Como podemos ver...los tiempos son muy buenos...y la diferencia entre el primero y el segundo es bastante obvia...para que quede nota...el archivo generado contiene 105874 registros...

Ahora...veamos la versión en Julia del código fuente...

Actors_Info.jl
using DataFrames
start = time()
isdefined(:Actors) || (Actors = readtable("Actors_Table.csv", header=true, nastrings=["","NA"]))
drop_duplicates!(Actors)
complete_cases!(Actors)
Actor_Info = DataFrame(Actor_Id=Actors["Actor_Id"],Name=Actors["Name"],Gender=Actors["Gender"])
sortby!(Actor_Info, [:Gender])
writetable("Actor_Info_Julia.csv", Actor_Info)
finish = time()
println("Time: ", finish-start)


Aquí...estamos haciendo lo mismo...cargamos el paquete DataFrames (Pero excluyendolo del tiempo de ejecución), revisamos si el archivo está cargado para no tener que cargarlo nuevamente la segunda vez...eliminamos los duplicados, borramos todos los nulos o NA, creamos un nuevo DataFrame, lo ordenamos por "Gender" y finalmente creamos un nuevo archivo CVS...


Bueno...la diferencia entre la primera y segunda ejecución es bastante significativa...pero por supuesto...mucho más lento que R...

Pero...dejenme decirles algo bastane simple...Julia es aún un lenguage de programación bastante nuevo...el paquete DataFrames no es parte del núcleo de Julia, lo cual significa...que es aún más nuevo...y las optimizaciones están siendo aplicadas mientras hablamos...debo decir que para un lenguaje tan joven...18 segundos para procesar 590,209 registros es bastante impresionate...y por supuesto...mi experiencia en R sobrepasa con creces mi experiencia en Julia...

Así que...realmente no quiero dejarlos con la impresión de que Julia no es bueno o lo suficientemente rápido...porque creanme...lo es...y van a adorar mi siguiente experimento -;)

Veamos primero el código fuente en R...

Random_Names.R
start.time <- Sys.time()
names<-c("Anne","Gigi","Blag","Juergen","Marek","Ingo","Lars","Julia",
         "Danielle","Rocky","Julien","Uwe","Myles","Mike", "Steven")

last_names<-c("Hardy","Read","Tejada","Schmerder","Kowalkiewicz","Sauerzapf",
              "Karg","Satsuta","Keene","Ongkowidjojo","Vayssiere","Kylau",
              "Fenlon","Flynn","Taylor")
full_names<-c()
for(i in 1:100000){
  name<-sample(1:15, 1)
  last_name<-sample(1:15, 1)
  full_name<-paste(names[name],last_names[last_name],sep=" ")
  full_names<-append(full_names,full_name)
}
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken

Este código es bastante simple...tenemos un par de vectores con nombres y apellidos...luego hacemos un 100000 veces y luego generamos un par de números aleatorios simplemente para leer los vectores, creamos un nombre completo y populamos un nuevo vector...con algunos divetidos nombres aleatorios...



Bueno....la diferencia entre ambas ejecuciones no es muy buena...la segunda ejecución es ligeramente más lenta...y 1 minuto es en realidad bastante tiempo...veamos como se comporta Julia...

Aquí está el código fuente en Julia...

Random_Numbers.jl
start = time()
names=["Anne","Gigi","Blag","Juergen","Marek","Ingo","Lars","Julia",
       "Danielle","Rocky","Julien","Uwe","Myles","Mike", "Steven"]
last_names=["Hardy","Read","Tejada","Schmerder","Kowalkiewicz","Sauerzapf",
            "Karg","Satsuta","Keene","Ongkowidjojo","Vayssiere","Kylau","Fenlon","Flynn","Taylor"]
full_names=String[]
full_name = ""
for i = 1:100000
        name=rand(1:15)
        last_name=rand(1:15)
        full_name = names[name] * " " * last_names[last_name]
        push!(full_names,full_name)
end
finish = time()
println("Time: ", finish-start)

Así que este código también, crea dos arreglos con nombres y apellidos, hace un loop 100000 veces, genera un par de números aleatorios, mezcla con un nombre con un apellido y luego popula un arreglo con algunos nombre completos mezclados...


Tal como en el código de R...la segunda ejecución le toma a Julia ligeramente más...pero...menos de un segundo?! Eso es algo como...asombrozamente rápido y realmente toma a R por sorpresa...

Ahora...yo creo que van a comenzar a tomar a Julia más en serio -:D

Espero que les haya gustado este blog...

Saludos,

Blag.
Development Culture.

No comments: