{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "_cePBYijlmH8"
},
"source": [
"# Laboratorio 2 - Parte 1"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "E6d18EXXlmH4"
},
"source": [
"\n",
"
\n",
"\n",
"**Recuerda que una vez abierto, Da clic en \"Copiar en Drive\", de lo contrario no podras alamancenar tu progreso**\n",
"\n",
"Nota: no olvide ir ejecutando las celdas de código de arriba hacia abajo para que no tenga errores de importación de librerías o por falta de definición de variables."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "YpzuvE42lmH5",
"tags": []
},
"outputs": [],
"source": [
"#configuración del laboratorio\n",
"# Ejecuta esta celda!\n",
"%load_ext autoreload\n",
"%autoreload 2\n",
"# for local \n",
"#import sys ; sys.path.append('../commons/utils/')\n",
"!wget https://raw.githubusercontent.com/jdariasl/ML_2020/master/Labs/commons/utils/general.py -O general.py\n",
"from general import configure_lab2\n",
"configure_lab2()\n",
"from lab2 import *\n",
"GRADER, x, y = part_1()"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "jPlJQSbWlmH8"
},
"source": [
"## Ejercicio 1: Contextualización del problema\n",
"\n",
"\n",
"Usaremos el dataset iris para el problema de clasificación. En el UCI Machine Learning Repository se encuentra más información en el siguiente [link](https://archive.ics.uci.edu/ml/datasets/iris) ."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "NLajNANXlmH9",
"tags": []
},
"outputs": [],
"source": [
"print(\"muestra de los 5 primeros renglones de x:\\n\", x[0:5, :])\n",
"print(\"muestra de los 5 primeros renglones de y:\\n\", y[0:5])\n",
"print (\"¿el resultado de esta instrucción que información nos brinda?\", x.shape[0])\n",
"print (\"¿el resultado de esta instrucción que información nos brinda?\", x.shape[1])\n",
"print (\"¿el resultado de esta instrucción que información nos brinda?\", len(np.unique(y)))"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "UjxCQdFSlmIA"
},
"source": [
"En un problema de clasificación de más de una clase, tener un desbalance de muestras puede ser perjudicial para el proceso de entrenamiento. Vamos a crear una función para verificar el numero de muestras por clases."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "C_H1V6UilmIA"
},
"outputs": [],
"source": [
"#Ejercicio de código\n",
"def muestras_por_clases (Y):\n",
" \"\"\"Funcion que calcula el numero de muestras por cada clase\n",
" Y: vector de numpy con las etiquetas de las muestras del conjunto X\n",
" retorna: diccionario [int/float:int/float] \n",
" con la estructura:{etiquetaclase1: numero de muestras clase1, etiquetaclase2: numero de muestras clase2}\n",
" \"\"\"\n",
" dicto = {}\n",
" ## Pista se puede asginar keys a diccionario: dict[etiqueta] = valor\n",
" for \n",
" \n",
"\n",
" return (dicto)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "ResDJsKflmIC",
"tags": []
},
"outputs": [],
"source": [
"## la funcion que prueba tu implementacion\n",
"GRADER.run_test(\"ejercicio1\", muestras_por_clases)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "BxYN119rlmIE"
},
"outputs": [],
"source": [
"# con esta linea de codigo puedes ver la dsitribucion de forma grafica\n",
"fig, ax = plt.subplots()\n",
"ax.bar(muestras_por_clases(y).keys(), muestras_por_clases(y).values())\n",
"ax.set_title(\"numero de muestras por clase\")\n",
"ax.set_xlabel(\"etiqueta de clase\")\n",
"ax.set_ylabel(\"# muestras por clase\")\n",
"ax.set_xticks(list(muestras_por_clases(y).keys()))\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"colab": {},
"colab_type": "code",
"id": "HdXA-uQTlmIH"
},
"outputs": [],
"source": [
"#@title Pregunta Abierta\n",
"#@markdown ¿dependiendo de los resultados de la informacion anterior, cuantas caracteristicas tiene el problema, muestras y como calficaria la distribución de clases?\n",
"respuesta_1 = \"\" #@param {type:\"string\"}"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "Z-SvlavllmIJ"
},
"source": [
"## Ejercicio 2: Completar código KNN\n",
"\n",
"Recuerde los conceptos vistos en teoria para los modelos basados en los K-vecimos mas cercanos. En este ejercicio vamos a escribir la función que implementa este modelo. Pero primero se sugiere esta implementación que calcula el error de clasificación.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "oPkzTnejlmIJ"
},
"outputs": [],
"source": [
"def ErrorClas(Y_lest, Y):\n",
" \"\"\"funcion que calcula el error de clasificación\n",
" Y_lest: numpy array con la estimaciones de etiqueta\n",
" Y: etiquetas reales\n",
" retorna: error de clasificación (int)\n",
" \"\"\"\n",
" error = 1 - np.sum(Y_lest == Y)/len(Y)\n",
" \n",
" return error\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "Ug9-Q6gYlmIM"
},
"source": [
"Ahora si es hora del ejercicio. Ten en cuenta lo siguiente:\n",
"\n",
"Pistas\n",
"\n",
"1. Para el cáculo de la distancia entre vectores existen varias opciones:\n",
" 1. usar la función la distancia entre matrices `scipy.spatial.distance.cdist`([Ejemplo](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html#scipy.spatial.distance.cdist))--esta puede ser usada directamente como `cdist(...)`. Entiende la salida de esta función. Al usarla, se logra un rendimiento superior.\n",
" 2. usar la función la distancia euclidiana `scipy.spatial.distance.euclidean`([Ejemplo](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.euclidean.html))--pueder acceder a ella directamente como `euclidean`. Aca debe pensar en un algoritmo elemento a elemento, por lo tanto menos eficiente.\n",
"2. También serán de utilidad las funciones `np.sort` y `np.argsort`.\n",
"3. ten presente que la moda es una operación que calcula el valor más común. En el [notebook ya se encuentra cargada esta operacion](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mode.html), es posible usarla de esta manera : `mode(y)`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "-5h9vhE2lmIO"
},
"outputs": [],
"source": [
"#ejercicio de codigo\n",
"def KNN_Clasificacion(X_train, Y_train, X_test, k):\n",
" \"\"\" Funcion que implementa el modelo de K-Vecino mas cercanos\n",
" para clasificación\n",
" X_train: es la matriz con las muestras de entrenamiento\n",
" Y_train: es un vector con los valores de salida pra cada una de las muestras de entrenamiento\n",
" X_test: es la matriz con las muestras de validación\n",
" k (int): valor de vecinos a usar\n",
" retorna: las estimaciones del modelo KNN para el conjunto X_test \n",
" esta matriz debe tener un shape de [row/muestras de X_test] \n",
" y las distancias de X_test respecto a X_train, estan matrix\n",
" debe tener un shape de [rows de X_test, rows X_train]\n",
" lo que es lo mismo [muestras de X_test, muestras de X_train]\n",
" \"\"\"\n",
" if k > X_train.shape[0]:\n",
" print(\"k no puede ser menor que las muestras de entrenamiento\")\n",
" return(None)\n",
" distancias = \n",
" Yest = np.zeros(X_test.shape[0])\n",
" \n",
" for \n",
" \n",
" \n",
" return (Yest, distancias) \n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "k_9TyR5RlmIR"
},
"outputs": [],
"source": [
"## la funcion que prueba tu implementacion\n",
"GRADER.run_test(\"ejercicio2\", KNN_Clasificacion)"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "uf14uGTjlmIT"
},
"source": [
"## Ejercicio 3: Experimentos de KNN\n",
"\n",
"Ahora vamos a probar nuestro algoritmo. Pero antes de esto vamos a tener que dividir nuestro conjunto de datos, vamos a usar una función llamada train_test_split de la libreria sklearn. [Aca puedes ver la ayuda](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html). Entiende su funcionamiento. Vamos a usarla para crear una función con una propoción fija de 70%-30% entre nuestro conjunto de entrenamiento y de pruebas.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "aohW53I3lmIU"
},
"outputs": [],
"source": [
"#ejercicio de codigo\n",
"def train_test_split_fix(X,Y):\n",
" \"\"\"funcion que divide el conjunto de datos en\n",
" entrenamiento y pruebas\n",
" usando un proporcion fija de 30 %\n",
" para el conjunto de pruebas.\n",
"\n",
" X: matriz de numpy con las muestras y caractersiticas\n",
" Y: matriz de numpy con las las etiquetas reales\n",
" retorna:\n",
" Xtrain: conjunto de datos para entrenamiento\n",
" Xtest: conjunto de datos para pruebas\n",
" Ytrain: conjunto de etiquetas para entrenamiento\n",
" Ytest: conjunto de etiquetas para prueba \n",
" \"\"\"\n",
" Xtrain, Xtest, Ytrain, Ytest = train_test_split( ...)\n",
"\n",
" return (Xtrain, Xtest, Ytrain, Ytest)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "V9ysrjCjlmIV"
},
"outputs": [],
"source": [
"## la funcion que prueba tu implementacion\n",
"GRADER.run_test(\"ejercicio3\", train_test_split_fix)"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "O0GoV9iZlmIX"
},
"source": [
"Vamos a proceder a experimentar. Para ello vamos a crear una función que realiza los experimentos usando las funciones previamente construidas. En el código se hace uso de la función [StandardScaler](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html), para normalizar los datos."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "790OsCdmlmIX"
},
"outputs": [],
"source": [
"#Ejercicio de código\n",
"def experimentar (X, Y, ks):\n",
" \"\"\"Función que realiza los experimentos con knn usando\n",
" una estrategia de validacion entrenamiento y pruebas\n",
" X: matriz de numpy conjunto con muestras y caracteristicas\n",
" Y: vector de numpy con los valores de las etiquetas\n",
" ks: List[int/float] lista con los valores de k-vecinos a usar\n",
" retorna: dataframe con los resultados\n",
" \"\"\"\n",
"\n",
" # dividimos usando la función\n",
" Xtrain, Xtest, Ytrain, Ytest = train_test_split_fix(X,Y)\n",
"\n",
" scaler = StandardScaler()\n",
" scaler.fit(Xtrain)\n",
" Xtrain= scaler.transform(Xtrain)\n",
" Xtest = scaler.transform(Xtest)\n",
"\n",
" resultados = pd.DataFrame()\n",
" idx = 0\n",
" for k in ks:\n",
" # iteramos sobre la lista de k's\n",
" resultados.loc[idx,'k-vecinos'] = k\n",
" Yest, dist =\n",
" errorTest = \n",
" resultados.loc[idx,'error de prueba'] = \n",
" idx+=1\n",
"\n",
" return (resultados)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"colab": {},
"colab_type": "code",
"id": "vVfhToZYlmIZ"
},
"outputs": [],
"source": [
"#@title Pregunta Abierta\n",
"#@markdown como se observo en nuestro experimentos usamos una metodologia basica de dividir el conjunto de entrenamiento y pruebas. ¿Cual es la diferencia si quisieramos aplicar una metodologia de validación cruzada?\n",
"respuesta_2 = \"\" #@param {type:\"string\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "uqlarUy7lmIb"
},
"outputs": [],
"source": [
"## la funcion que prueba tu implementacion\n",
"GRADER.run_test(\"ejercicio4\", experimentar)"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "89jKEygplmId"
},
"source": [
"Ahora ejecuta los experimentos con k = 2,3,4,5,6,7,10"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "GUJwi9dilmId"
},
"outputs": [],
"source": [
"resultados = experimentar (x, y,[2,3,4,5,6,7,10])\n",
"resultados"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "RjYA5v8UlmIf"
},
"source": [
"## Ejercicio 4: ventana de Parzen\n",
"\n",
"Ahora vamos a utilizar el metodo de ventana de parzen. Recuerde de las clases teoricas, quedemos usar una función kernel. En la siguiente celda se proponen dos funciones para:\n",
"1. calculo de un kernel gausiano\n",
"2. calculo de la ventana de parzen, es decir el termino: $ \\sum_{i=1}^{N} K(u_i)$, siendo $\\;\\; u_i = \\frac{d({\\bf{x}}^*,{\\bf{x}}_i)}{h}$ y la función $K$ el kernel gausiano"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "REi5LxoilmIg"
},
"outputs": [],
"source": [
"def kernel_gaussiano(x):\n",
" \"\"\"Calcula el kernel gaussiano de x\n",
" x: matriz/vector de numpy\n",
" retorna: el valor de de kernel gaussiano\n",
" \"\"\"\n",
" return np.exp((-0.5)*x**2)\n",
"\n",
"def ParzenWindow(x,Data,h):\n",
" \"\"\"\"ventana de parzen\n",
" x: vector con representando una sola muestra\n",
" Data: vector de muestras de entrenamiento\n",
" h: ancho de la ventana de kernel\n",
" retorna: el valor de ventana de parzen para una muestra\n",
" \"\"\"\n",
" h = h\n",
" Ns = Data.shape[0]\n",
" suma = 0\n",
" for k in range(Ns):\n",
" u = euclidean(x,Data[k,:])\n",
" suma += kernel_gaussiano(u/h)\n",
" return suma\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "MAlolkzzlmIh"
},
"source": [
"Entiendalos la implementación de las anteriores funciones y uselas para resolver el ejercicio de código."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "K-8GS3A8lmIh"
},
"outputs": [],
"source": [
"#Ejercicio de código\n",
"def parzenClass(X_train, Y_train, X_test, h):\n",
" \"\"\" Funcion que implementa metodo de ventana de parzen para\n",
" para clasificación\n",
" X_train: es la matriz con las muestras de entrenamiento\n",
" Y_train: es un vector con los valores de salida pra cada una de las muestras de entrenamiento\n",
" X_test: es la matriz con las muestras de validación\n",
" h (float): ancho de h de la ventana\n",
" retorna: - las estimaciones del modelo parzen para el conjunto X_test \n",
" esta matriz debe tener un shape de [row/muestras de X_test]\n",
" - las probabilidades de la vetana [row/muestras de X_test, numero de clases] \n",
" \"\"\"\n",
" \n",
" Yest = np.zeros(X_test.shape[0])\n",
" clases = np.unique(Y_train)\n",
" fds_matrix = np.zeros((X_test.shape[0], len(clases)))\n",
" \n",
" \n",
" ## pista: recuerde el termino que acompaña al sumatoria (N)\n",
" \n",
" for n, sample in enumerate (X_test):\n",
" \n",
" for label in clases:\n",
" \n",
" \n",
" \n",
" \n",
" \n",
"\n",
" #Debe retornar un vector que contenga las predicciones para cada una de las muestras en X_val, en el mismo orden. \n",
" return Yest, fds_matrix"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "i0eLRBbqlmIj"
},
"outputs": [],
"source": [
"## la funcion que prueba tu implementacion\n",
"GRADER.run_test(\"ejercicio5\", parzenClass)"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "_Z2-claRlmIk"
},
"source": [
"## Ejercicio 5 - Experimentos con Parzen\n",
"\n",
"Ahora vamos a realizar los experimentos, pero esta vez, debemos implementar otro tipo de validación. Dentro del código se encuentra ya esta implementación sugerida, usando [esta función](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.StratifiedKFold.html)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"colab": {},
"colab_type": "code",
"id": "Kh__flOllmIk"
},
"outputs": [],
"source": [
"#@title Pregunta Abierta\n",
"#@markdown ¿cual es la metodologia de validación usada en el experimento? ¿qué diferencia tiene respecto a una validación cruzada?\n",
"respuesta_3 = \"\" #@param {type:\"string\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "rHF6dWYYlmIn"
},
"outputs": [],
"source": [
"#ejercicio de codigo\n",
"def experimentarParzen (X, Y, hs):\n",
" \"\"\"Función que realiza los experimentos con knn usando\n",
" una estrategia de validacion entrenamiento y pruebas\n",
" X: matriz de numpy conjunto con muestras y caracteristicas\n",
" Y: vector de numpy con los valores de las etiquetas\n",
" ks: List[int/float] lista con los valores de k-vecinos a usar\n",
" retorna: dataframe con los resultados, debe contener las siguientes columnas:\n",
" - el ancho de ventana, el error medio de prueba, la desviacion estandar del error\n",
" \"\"\"\n",
" \n",
" \n",
" # se usa la función para implementar la estrategia de validación.\n",
" skf = StratifiedKFold(n_splits=4)\n",
" resultados = pd.DataFrame()\n",
" idx = 0\n",
" # iteramos sobre los valores de hs\n",
" for h in hs:\n",
" # lista para almacenar los errores de cada iteración\n",
" # de la validación\n",
" error_temp = []\n",
" \n",
" for train, test in skf.split(X, Y):\n",
"\n",
" Xtrain = X[train,:]\n",
" Ytrain = Y[train]\n",
" Xtest = X[test,:]\n",
" Ytest = Y[test]\n",
" #normalizamos los datos\n",
" scaler = StandardScaler()\n",
" scaler.fit(Xtrain)\n",
" Xtrain = scaler.transform(Xtrain)\n",
" Xtest = scaler.transform(Xtest)\n",
" \n",
" Yest, probabilidades = \n",
" errorTest =\n",
" error_temp.append(errorTest)\n",
" \n",
" resultados.loc[idx,'ancho de ventana'] = h \n",
" resultados.loc[idx,'error de prueba(media)'] = \n",
" resultados.loc[idx,'error de prueba(desviación estandar)'] = \n",
" idx+=1\n",
" return (resultados)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "i7cPkOUAlmIo"
},
"outputs": [],
"source": [
"## la funcion que prueba tu implementacion\n",
"GRADER.run_test(\"ejercicio6\", experimentarParzen)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "6qwO7XGllmIq"
},
"outputs": [],
"source": [
"hs = [0.05, 0.1, 0.5, 1, 2, 5, 10]\n",
"experimentos_parzen = experimentarParzen(x,y, hs)\n",
"experimentos_parzen"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"colab": {},
"colab_type": "code",
"id": "vx9AQMO7lmIs"
},
"outputs": [],
"source": [
"#@title Pregunta Abierta\n",
"#@markdown ¿por qué usando una ventana de parzen, no hay necesidad de definir un numero de vecinos cercanos? \n",
"respuesta_4 = \"\" #@param {type:\"string\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"colab": {},
"colab_type": "code",
"id": "Yrq718yylmIu"
},
"outputs": [],
"source": [
"#@title Pregunta Abierta\n",
"#@markdown ¿De acuerdo al problema, cual de las dos metodologias usadas en los experimentos es más recomendada?\n",
"respuesta_5 = \"\" #@param {type:\"string\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "xHa3qR1ulmIv"
},
"outputs": [],
"source": [
"GRADER.check_tests()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"colab": {},
"colab_type": "code",
"id": "v--KrYKQlmIw"
},
"outputs": [],
"source": [
"#@title Integrantes\n",
"codigo_integrante_1 ='' #@param {type:\"string\"}\n",
"codigo_integrante_2 = '' #@param {type:\"string\"}"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "XB1mvFqflmIz"
},
"source": [
"----\n",
"esta linea de codigo va fallar, es de uso exclusivo del los profesores\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "YoZbRijflmIz"
},
"outputs": [],
"source": [
"GRADER.grade()"
]
}
],
"metadata": {
"colab": {
"name": "lab2_parte1.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 1
}