{ "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", " \"Open\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 }