<jupyter_start><jupyter_text>IntroducciónEn este apunte nos enfocaremos en dos de las limitantes más importantes de regresión lineal: outliers y heterocedasticidad. Para esta parte utilizaremos un dataset diferente que se encuentra dentro de la librería Seaborn. En este caso sobre [propinas en restaurantes](https://github.com/mwaskom/seaborn-data).<jupyter_code>import numpy as np
from scipy.stats import norm 
import pandas as pd 
import seaborn as sns
import matplotlib.pyplot as plt

%matplotlib inline
plt.rcParams['figure.figsize'] = (20, 10)
plt.style.use('ggplot')

import warnings
warnings.filterwarnings('ignore')
df = sns.load_dataset("tips")
df<jupyter_output><empty_output><jupyter_text>Por cuestión de procesamientos posteriores, no usaremos las siguientes columnas categóricas.<jupyter_code>df.drop(["sex", "smoker", "day", "time"], axis=1, inplace=True)<jupyter_output><empty_output><jupyter_text>Las columnas restantes son:* **total_bill**: el total de la cuenta* **tip**: propinas* **size**: número de comensales  Outliers Poder identificar a los outliers es muy sencillo. Todo lo que tenemos que hacer es utilizar la función *boxplot* dentro de seaborn para generar un diagrama de caja.<jupyter_code>ax = sns.boxplot(x=df["total_bill"])<jupyter_output><empty_output><jupyter_text>Lo que podemos apreciar es el * Mínimo y máximo no atípico, representados por las líneas en los extremos.* El rango intercuartílico, representado por la caja en rojo. En este caso, tenemos un rango que va del cuartil 1 (Q1) al cuartil 3 (Q3). Dentro de este encontramos a la mayoría de nuestros data points.* La línea dentro de la caja roja que representa a la mediana.* Los puntos fuera del máximo no atípico, que son los outliers o valores atípicos.En este caso podemos ver que tenemos 8 valores atípicos que podría afectar a nuestro modelo.  Heterocedasticidad Para evaluar la heterocedasticidad, solo tenemos que correr de nuevo la función *regplot* dentro de Seaborn. En este caso evaluaremos la correlación entre el total de la cuenta y las propinas.<jupyter_code>sns.regplot(x=df["total_bill"], y=df["tip"])<jupyter_output><empty_output><jupyter_text>En este caso podemos ver hay más homocedasticidad (lo contrario de heterocedasticidad) al principio de la línea, pero que la varianza aumenta al avanzar la línea.Es decir, las propinas suelen ser similares cuando la cuenta es pequeña. Sin embargo, varía más a medida que la cuenta se vuelve más grande.   Una Posible SoluciónComo mencionamos, una de las posibles formulas es descartar a los outliers. Esta es una opción válida para algunos casos y se debe de tener cuidado al usarla. De ninguna manera es una bala de plata para todos los problemas, ya que los outliers podrían tener información importante.En este caso preservaremos solo los valores dentro del rango intercuartílico. Antes que nada veamos la información básica del dataset y su distribución normal.<jupyter_code>df.describe()
mu = df["total_bill"].mean() 
sigma = df["total_bill"].std() 
x1 =  13
x2 = 24

z1 = ( x1 - mu ) / sigma
z2 = ( x2 - mu ) / sigma

x = np.arange(z1, z2, 0.001) 
x_all = np.arange(-10, 10, 0.001) 
y = norm.pdf(x,0,1)
y2 = norm.pdf(x_all,0,1)


fig, ax = plt.subplots(figsize=(20,10))
plt.style.use('fivethirtyeight')
ax.plot(x_all,y2)

ax.fill_between(x,y,0, alpha=0.3, color='b')
ax.fill_between(x_all,y2,0, alpha=0.1)
ax.set_xlim([-4,4])
ax.set_xlabel('Número de Desviaciones Estándard Fuera de la Media')
ax.set_yticklabels([])
ax.set_title('Distribución Normal')

plt.show()<jupyter_output><empty_output><jupyter_text>Lo primero que haremos es determinar el rango intercuartílico de nuestro data set con la función *quantile*.<jupyter_code>Q1 = df.quantile(0.25)
Q3 = df.quantile(0.75)
IQR = Q3 - Q1

IQR<jupyter_output><empty_output><jupyter_text>Con el siguiente código eliminamos todos los valores de nuestro dataset que se encuentran fuera del rango intercuartílico.<jupyter_code>df = df[~((df < (Q1 - 1.5 * IQR)) | (df > (Q3 + 1.5 * IQR))).any(axis=1)]
df<jupyter_output><empty_output><jupyter_text>Vemos ahora que al quitar los valores atípicos, solo perdimos que hemos perdido 10 de ellos. Por ende, la solución podría ser válida. Vemos que resultado ha dado:<jupyter_code>df.describe()<jupyter_output><empty_output><jupyter_text>Primero vemos que el promedio ajustado pasó de 19.78 a 18.22 en las cuentas y de 2.99 a 2.77 en las propinas. Mientras que el número de comensales no varío demasiado.Sin embargo, hubo una variación importante en la desviación estándard en las cuentas. Esta pasó de 19.78 a 18.22 cuando se ajusta. Estos cambios podrían indicar que hay un grupo de personas que consumen bastante más que el resto de comensales, por lo que al excluirlos tenemos una idea más clara del comportamiento de la mayoría de ellos.<jupyter_code>mu = df["total_bill"].mean() 
sigma = df["total_bill"].std() 
x1 =  13
x2 = 24

z1 = ( x1 - mu ) / sigma
z2 = ( x2 - mu ) / sigma

x = np.arange(z1, z2, 0.001) 
x_all = np.arange(-10, 10, 0.001) 
y = norm.pdf(x,0,1)
y2 = norm.pdf(x_all,0,1)


fig, ax = plt.subplots(figsize=(20,10))
plt.style.use('fivethirtyeight')
ax.plot(x_all,y2)

ax.fill_between(x,y,0, alpha=0.3, color='b')
ax.fill_between(x_all,y2,0, alpha=0.1)
ax.set_xlim([-4,4])
ax.set_xlabel('Número de Desviaciones Estándard Fuera de la Media')
ax.set_yticklabels([])
ax.set_title('Distribución Normal')

plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09804283604135894, 'fraction_numerical': 0.025295420974889217, 'mean_word_length': 5.380447585394582, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 38, 'https://': 1, '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': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '389351', 'license': 'MIT', 'n_tokens_mistral': 2074, 'n_tokens_neox': 1986, 'n_words': 644, 'path': '4_Limitaciones_Regresión_Linear.ipynb', 'repo_name': 'XavierCarrera/Tutorial-Machine-Learning-Regresion-Lineal', 'size': '5416'}