<jupyter_start><jupyter_text>Hagamos un Ejercicio PrácticoEn este ejemplo cargaremos un archivo .csv de entrada obtenido por webscraping que contiene diversas URLs a artículos sobre Machine Learning de algunos sitios muy importantes como Techcrunch o KDnuggets y como características de entrada -las columnas- tendremos: Title: Titulo del Artículo, url: ruta al artículo, Word count: la cantidad de palabras del artículo, N° of Links: los enlaces externos que contiene, N° of comments: cantidad de comentarios, N° Images video: suma de imágenes (o videos), Elapsed days: la cantidad de días transcurridos (al momento de crear el archivo), N° Shares: nuestra columna de salida que será la «cantidad de veces que se compartió el artículo.A partir de las características de un artículo de machine learning intentaremos predecir, cuantas veces será compartido en Redes Sociales.Haremos una primer predicción de regresión lineal simple -con una sola variable predictora-  para poder graficar en 2 dimensiones (ejes X e Y) y luego un ejemplo de regresión Lineal Múltiple, en la que utilizaremos 3  dimensiones (X,Y,Z) y predicciones.  Comencemos por importar las librerías que utilizaremos:<jupyter_code># Imports necesarios
import numpy as np
import pandas as pd
import seaborn as sb
import matplotlib.pyplot as plt
%matplotlib inline
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
plt.rcParams['figure.figsize'] = (16, 9)
plt.style.use('ggplot')
from sklearn import linear_model
from sklearn.metrics import mean_squared_error, r2_score<jupyter_output><empty_output><jupyter_text>Leemos el archivo csv y lo cargamos como un dataset de Pandas. Y vemos su tamaño<jupyter_code>#cargamos los datos de entrada
data = pd.read_csv("./articulos_ml.csv")
#veamos cuantas dimensiones y registros contiene
data.shape<jupyter_output><empty_output><jupyter_text>Veamos esas primeras filas:<jupyter_code>#son 161 registros con 8 columnas. Veamos los primeros registros
data.head()<jupyter_output><empty_output><jupyter_text>Se ven algunos campos con valores NaN (nulos) por ejemplo algunas urls o en comentarios.Veamos algunas estadísticas básicas de nuestros datos de entrada:<jupyter_code># Ahora veamos algunas estadísticas de nuestros datos
data.describe()<jupyter_output><empty_output><jupyter_text>Aqui vemos que la media de palabras en los artículos es de 1808. El artículo más corto tiene 250 palabras y el más extenso 8401. Intentaremos ver con nuestra relación lineal, si hay una correlación entre la cantidad de palabras del texto y la cantidad de Shares obtenidos.Hacemos una visualización en general de los datos de entrada:<jupyter_code># Visualizamos rápidamente las caraterísticas de entrada
data.drop(['Title','url', 'Elapsed days'],1).hist()
plt.show()<jupyter_output><empty_output><jupyter_text>En estas gráficas vemos entre qué valores se concentran la mayoría de registros.Vamos a filtrar los datos de cantidad de palabras para quedarnos con los registros con menos de 3500 palabras y también con los que tengan Cantidad de compartidos menos a 80.000. Lo gratificaremos pintando en azul los puntos con menos de 1808 palabras (la media) y en naranja los que tengan más.<jupyter_code># Vamos a RECORTAR los datos en la zona donde se concentran más los puntos
# esto es en el eje X: entre 0 y 3.500
# y en el eje Y: entre 0 y 80.000
filtered_data = data[(data['Word count'] <= 3500) & (data['# Shares'] <= 80000)]

colores=['orange','blue']
tamanios=[30,60]

f1 = filtered_data['Word count'].values
f2 = filtered_data['# Shares'].values

# Vamos a pintar en colores los puntos por debajo y por encima de la media de Cantidad de Palabras
asignar=[]
for index, row in filtered_data.iterrows():
    if(row['Word count']>1808):
        asignar.append(colores[0])
    else:
        asignar.append(colores[1])
    
plt.scatter(f1, f2, c=asignar, s=tamanios[0])
plt.show()<jupyter_output><empty_output><jupyter_text>Regresión Lineal con Python y SKLearnVamos a crear nuestros datos de entrada por el momento sólo Word Count y como etiquetas los  Shares. Creamos el objeto LinearRegression y lo hacemos «encajar» (entrenar) con el método fit(). Finalmente imprimimos los coeficientes y puntajes obtenidos.<jupyter_code># Asignamos nuestra variable de entrada X para entrenamiento y las etiquetas Y.
dataX =filtered_data[["Word count"]]
X_train = np.array(dataX)
y_train = filtered_data['# Shares'].values

# Creamos el objeto de Regresión Linear
regr = linear_model.LinearRegression()

# Entrenamos nuestro modelo
regr.fit(X_train, y_train)

# Hacemos las predicciones que en definitiva una línea (en este caso, al ser 2D)
y_pred = regr.predict(X_train)

# Veamos los coeficienetes obtenidos, En nuestro caso, serán la Tangente
print('Coeficientes: \n', regr.coef_)
# Este es el valor donde corta el eje Y (en X=0)
print('Término independiente o bias: \n', regr.intercept_)
# Error Cuadrado Medio
print("Mean squared error: %.2f" % mean_squared_error(y_train, y_pred))
# Puntaje de Varianza. El mejor puntaje es un 1.0
print('Variance score: %.2f' % r2_score(y_train, y_pred))<jupyter_output>Coeficientes: 
 [5.69765366]
Término independiente o bias: 
 11200.303223074157
Mean squared error: 372888728.34
Variance score: 0.06<jupyter_text>p style=»padding-left: 30px;»>Coefficients: [5.69765366]Independent term: 11200.303223074163Mean squared error: 372888728.34Variance score: 0.06De la ecuación de la recta y = mX + b nuestra pendiente «m» es el coeficiente 5,69 y el término independiente «b» es 11200. Tenemos un Error Cuadrático medio enorme… por lo que en realidad este modelo no será muy bueno 😉 Pero estamos aprendiendo a usarlo, que es lo que nos importa ahora 🙂 Esto también se ve reflejado en el puntaje de Varianza que debería ser cercano a 1.0.  Visualicemos la Recta<jupyter_code>plt.scatter(f1, f2, c=asignar, s=tamanios[0])
plt.plot(X_train,y_pred)
plt.show()<jupyter_output><empty_output><jupyter_text>Predicción en regresión lineal simpleVamos a intentar probar nuestro algoritmo, suponiendo que quisiéramos predecir cuántos «compartir» obtendrá un articulo sobre ML de 2000 palabras<jupyter_code>#Vamos a comprobar:
# Quiero predecir cuántos "Shares" voy a obtener por un artículo con 2.000 palabras,
# según nuestro modelo, hacemos:
y_Dosmil = regr.predict([[2000]])
print(int(y_Dosmil))<jupyter_output><empty_output><jupyter_text>Nos devuelve una predicción de 22595 «Shares» para un artículo de 2000 palabras Regresión Lineal Múltiple en PythonVamos a extender el ejercicio utilizando más de una variable de entrada para el modelo. Esto le da mayor poder al algoritmo de Machine Learning, pues de esta manera podremos obtener predicciones más complejas.En nuestro caso, utilizaremos 2 «variables predictivas» para poder graficar en 3D, pero recordar que para mejores predicciones podemos utilizar más de 2 entradas y prescindir del grafico.Nuestra primer variable seguirá siendo la cantidad de palabras y la segunda variable será la suma de 3 columnas de entrada: la cantidad de enlaces, comentarios y cantidad de imágenes. Vamos a programar!<jupyter_code>#Vamos a intentar mejorar el Modelo, con una dimensión más: 
# Para poder graficar en 3D, haremos una variable nueva que será la suma de los enlaces, comentarios e imágenes
suma = (filtered_data["# of Links"] + filtered_data['# of comments'].fillna(0) + filtered_data['# Images video'])

dataX2 =  pd.DataFrame()
dataX2["Word count"] = filtered_data["Word count"]
dataX2["suma"] = suma
XY_train = np.array(dataX2)
z_train = filtered_data['# Shares'].values<jupyter_output><empty_output><jupyter_text>Ya tenemos nuestras 2 variables de entrada en XY_train y nuestra variable de salida pasa de ser «Y» a ser el eje «Z».Creamos un nuevo objeto de Regresión lineal con SKLearn pero esta vez tendrá las dos dimensiones que entrenar: las que contiene XY_train. Al igual que antes, imprimimos los coeficientes y puntajes obtenidos:<jupyter_code># Creamos un nuevo objeto de Regresión Lineal
regr2 = linear_model.LinearRegression()

# Entrenamos el modelo, esta vez, con 2 dimensiones
# obtendremos 2 coeficientes, para graficar un plano
regr2.fit(XY_train, z_train)

# Hacemos la predicción con la que tendremos puntos sobre el plano hallado
z_pred = regr2.predict(XY_train)

# Los coeficientes
print('Coefficients: \n', regr2.coef_)
# Error cuadrático medio
print("Mean squared error: %.2f" % mean_squared_error(z_train, z_pred))
# Evaluamos el puntaje de varianza (siendo 1.0 el mejor posible)
print('Variance score: %.2f' % r2_score(z_train, z_pred))<jupyter_output>Coefficients: 
 [   6.63216324 -483.40753769]
Mean squared error: 352122816.48
Variance score: 0.11<jupyter_text>p style=»padding-left: 30px;»>Coefficients: [ 6.63216324 -483.40753769]Mean squared error: 352122816.48Variance score: 0.11Como vemos, obtenemos 2 coeficientes (cada uno correspondiente a nuestras 2 variables predictivas), pues ahora lo que graficamos no será una linea si no, un plano en 3 Dimensiones.El error obtenido sigue siendo grande, aunque algo mejor que el anterior y el puntaje de Varianza mejora casi el doble del anterior (aunque sigue siendo muy malo, muy lejos del 1). Visualizar un plano en 3 DimensionesGraficaremos nuestros puntos de las características de entrada en color azul y los puntos proyectados en el plano en rojo. Recordemos que en esta gráfica, el eje Z corresponde a la «altura» y representa la cantidad de Shares que obtendremos.<jupyter_code>fig = plt.figure()
ax = Axes3D(fig)

# Creamos una malla, sobre la cual graficaremos el plano
xx, yy = np.meshgrid(np.linspace(0, 3500, num=10), np.linspace(0, 60, num=10))

# calculamos los valores del plano para los puntos x e y
nuevoX = (regr2.coef_[0] * xx)
nuevoY = (regr2.coef_[1] * yy) 

# calculamos los correspondientes valores para z. Debemos sumar el punto de intercepción
z = (nuevoX + nuevoY + regr2.intercept_)

# Graficamos el plano
ax.plot_surface(xx, yy, z, alpha=0.2, cmap='hot')

# Graficamos en azul los puntos en 3D
ax.scatter(XY_train[:, 0], XY_train[:, 1], z_train, c='blue',s=30)

# Graficamos en rojo, los puntos que 
ax.scatter(XY_train[:, 0], XY_train[:, 1], z_pred, c='red',s=40)

# con esto situamos la "camara" con la que visualizamos
ax.view_init(elev=30., azim=65)
        
ax.set_xlabel('Cantidad de Palabras')
ax.set_ylabel('Cantidad de Enlaces,Comentarios e Imagenes')
ax.set_zlabel('Compartido en Redes')
ax.set_title('Regresión Lineal con Múltiples Variables')<jupyter_output><empty_output><jupyter_text>Podemos rotar el gráfico para apreciar el plano desde diversos ángulos modificando el valor del parámetro azim en view_init con números de 0 a 360. Predicción con el modelo de Mútiples VariablesVeamos ahora, que predicción tendremos para un artículo de 2000 palabras, con 10 enlaces, 4 comentarios y 6 imágenes.<jupyter_code># Si quiero predecir cuántos "Shares" voy a obtener por un artículo con: 
# 2000 palabras y con enlaces: 10, comentarios: 4, imagenes: 6
# según nuestro modelo, hacemos:

z_Dosmil = regr2.predict([[2000, 10+4+6]])
print(int(z_Dosmil))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07633932604571325, 'fraction_numerical': 0.03198120878128106, 'mean_word_length': 5.668674698795181, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 54, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '356921', 'license': 'Unlicense', 'n_tokens_mistral': 4168, 'n_tokens_neox': 3900, 'n_words': 1411, 'path': 'Practico 5 - Regresion Lineal/2019 RegresionLineal Dset articulos_ml.ipynb', 'repo_name': 'csuarez689/IA-2019', 'size': '11069'}