In [405]:
# Carga de librerías
using Gadfly;
using DataFrames;
In [449]:
# Lectura de set demo (2 variables (x1 e Y), 50 datos en total)
df = readtable("data_regresion_lineal.txt", header=true);
In [463]:
# Estadísticas básicas del set de datos
describe(df)
In [451]:
# Una muestra de los primeros 10 registros
df[1:10,:]
Out[451]:
In [459]:
# Tamaño del set de datos
@printf("filas: %d, columnas: %d\n",size(df,1),size(df,2))
In [462]:
# Examen gráfico de datos
plot(x=df[:x1],y=df[:y],Geom.point, Guide.title("Nube de puntos"))
Out[462]:
Para la construcción de las funciones, se usaron las versiones vectorizadas y matriciales de costo y gradiente:
In [409]:
# Función de costo
function J(Theta,X,Y)
m = length(Y);
(X*Theta-Y)'*(X*Theta-Y)/m;
end
Out[409]:
In [410]:
# Función Nabla de J
function nabla(Theta,X,Y)
((X'*X)*Theta - X'*Y);
end
Out[410]:
In [464]:
# Gradiente
function gradiente(X,Y,Theta,alpha,epsilon)
m = length(Y);
Jhist = [];
n = 1
while alpha*norm(nabla(Theta,X,Y)) > epsilon
temp = Theta - alpha * nabla(Theta,X,Y)/m;
Theta = temp;
push!(Jhist,J(Theta,X,Y)[1]) # El subíndice 1 es porque J es matriz de 1x1
n += 1;
end
return (Jhist,Theta,n)
end
Out[464]:
In [465]:
# Inicialización
X = [ones(50) df[:x1]];
Y = df[:y];
In [466]:
# Iteraciones para a = 0.001 y epsilon = 0.001
@time (Jhist,Theta,n) = gradiente(X,Y,[0,0],0.001,0.001);
In [467]:
#Número de iteraciones
n
Out[467]:
In [468]:
# Parámetro Theta
Theta
Out[468]:
In [469]:
# Curva de costo
plot(x=1:length(Jhist),y=Jhist,Geom.line)
Out[469]:
In [433]:
# Recta ajustada
plot(layer(x=df[:x1],y=df[:y],Geom.point),layer(x=df[:x1],
y=Theta[1]+Theta[2]*df[:x1],Geom.line,Theme(default_color=color("red"))))
Out[433]:
In [434]:
# Resultado exacto: Mínimos Cuadrados Ordinarios
Beta = pinv(X'*X)*(X'*Y)
Out[434]:
In [435]:
# Recta ajustada con Beta superpuesta
plot(layer(x=df[:x1],y=df[:y],Geom.point),layer(x=df[:x1],
y=Theta[1]+Theta[2]*df[:x1],Geom.line,Theme(default_color=color("red"))),
layer(x=df[:x1],y=Beta[1]+Beta[2]*df[:x1],Geom.line,Theme(default_color=color("green"))))
Out[435]:
In [441]:
# Error general
norm(Beta-Theta)^(0.5)
Out[441]:
Se puede observar que el resultado obtenido es lo esperable por el algoritmo. Después de 31.788 iteraciones en 0.9 segundos, se obtuvieron los valores de $\theta_0$ y $\theta_1$, con una muy pequeña diferencia respecto del valor obtenido por la solución algebraica de Mínimos Cuadrados Ordinarios.
En términos de la usabilidad, es muy cómodo poder utilizar las fórmulas vectorizadas y es agradable la velocidad de ejecución. Para una prueba más definitiva, probaré el algoritmo con un set de datos más grande y con más variables, y también haré un paralelo con Octave para probar velocidad.
Pero más allá de la mera eficacia computacional, me agradó mucho como lenguaje, y creo que de comprobarse las aseveraciones de sus creadores, fácilmente podría transformarse en mi herramienta predilecta para análisis de datos y Machine Learning.