{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "feature_sets.ipynb", "version": "0.3.2", "views": {}, "default_view": {}, "provenance": [], "collapsed_sections": [ "IGINhMIJ5Wyt", "pZa8miwu6_tQ", "copyright-notice" ] } }, "cells": [ { "source": [ "#### Copyright 2017 Google LLC." ], "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "copyright-notice" } }, { "execution_count": 0, "source": [ "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ], "cell_type": "code", "metadata": { "cellView": "both", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } }, "colab_type": "code", "id": "copyright-notice2" }, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "zbIgBK-oXHO7", "colab_type": "text" }, "source": [ " # Conjuntos de atributos" ] }, { "cell_type": "markdown", "metadata": { "id": "bL04rAQwH3pH", "colab_type": "text" }, "source": [ " **Objetivo de aprendizaje:** crear un conjunto de atributos m\u00ednimo que se desempe\u00f1e tan bien como un conjunto de atributos m\u00e1s complejo" ] }, { "cell_type": "markdown", "metadata": { "id": "F8Hci6tAH3pH", "colab_type": "text" }, "source": [ " Hasta ahora, hemos ingresado en el modelo todos nuestros atributos. Los modelos con menos atributos usan menos recursos y son m\u00e1s f\u00e1ciles de mantener. Veamos si podemos desarrollar un modelo con un conjunto m\u00ednimo de atributos de vivienda que se desempe\u00f1e tan bien como uno que usa todos los atributos del conjunto de datos." ] }, { "cell_type": "markdown", "metadata": { "id": "F5ZjVwK_qOyR", "colab_type": "text" }, "source": [ " ## Preparaci\u00f3n\n", "\n", "Al igual que antes, carguemos y preparemos los datos de viviendas en California." ] }, { "metadata": { "id": "SrOYRILAH3pJ", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "from __future__ import print_function\n", "\n", "import math\n", "\n", "from IPython import display\n", "from matplotlib import cm\n", "from matplotlib import gridspec\n", "from matplotlib import pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "from sklearn import metrics\n", "import tensorflow as tf\n", "from tensorflow.python.data import Dataset\n", "\n", "tf.logging.set_verbosity(tf.logging.ERROR)\n", "pd.options.display.max_rows = 10\n", "pd.options.display.float_format = '{:.1f}'.format\n", "\n", "california_housing_dataframe = pd.read_csv(\"https://storage.googleapis.com/mledu-datasets/california_housing_train.csv\", sep=\",\")\n", "\n", "california_housing_dataframe = california_housing_dataframe.reindex(\n", " np.random.permutation(california_housing_dataframe.index))" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "metadata": { "id": "dGnXo7flH3pM", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "def preprocess_features(california_housing_dataframe):\n", " \"\"\"Prepares input features from California housing data set.\n", "\n", " Args:\n", " california_housing_dataframe: A Pandas DataFrame expected to contain data\n", " from the California housing data set.\n", " Returns:\n", " A DataFrame that contains the features to be used for the model, including\n", " synthetic features.\n", " \"\"\"\n", " selected_features = california_housing_dataframe[\n", " [\"latitude\",\n", " \"longitude\",\n", " \"housing_median_age\",\n", " \"total_rooms\",\n", " \"total_bedrooms\",\n", " \"population\",\n", " \"households\",\n", " \"median_income\"]]\n", " processed_features = selected_features.copy()\n", " # Create a synthetic feature.\n", " processed_features[\"rooms_per_person\"] = (\n", " california_housing_dataframe[\"total_rooms\"] /\n", " california_housing_dataframe[\"population\"])\n", " return processed_features\n", "\n", "def preprocess_targets(california_housing_dataframe):\n", " \"\"\"Prepares target features (i.e., labels) from California housing data set.\n", "\n", " Args:\n", " california_housing_dataframe: A Pandas DataFrame expected to contain data\n", " from the California housing data set.\n", " Returns:\n", " A DataFrame that contains the target feature.\n", " \"\"\"\n", " output_targets = pd.DataFrame()\n", " # Scale the target to be in units of thousands of dollars.\n", " output_targets[\"median_house_value\"] = (\n", " california_housing_dataframe[\"median_house_value\"] / 1000.0)\n", " return output_targets" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "metadata": { "id": "jLXC8y4AqsIy", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "# Choose the first 12000 (out of 17000) examples for training.\n", "training_examples = preprocess_features(california_housing_dataframe.head(12000))\n", "training_targets = preprocess_targets(california_housing_dataframe.head(12000))\n", "\n", "# Choose the last 5000 (out of 17000) examples for validation.\n", "validation_examples = preprocess_features(california_housing_dataframe.tail(5000))\n", "validation_targets = preprocess_targets(california_housing_dataframe.tail(5000))\n", "\n", "# Double-check that we've done the right thing.\n", "print(\"Training examples summary:\")\n", "display.display(training_examples.describe())\n", "print(\"Validation examples summary:\")\n", "display.display(validation_examples.describe())\n", "\n", "print(\"Training targets summary:\")\n", "display.display(training_targets.describe())\n", "print(\"Validation targets summary:\")\n", "display.display(validation_targets.describe())" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "hLvmkugKLany", "colab_type": "text" }, "source": [ " ## Tarea\u00a01: Desarrolla un buen conjunto de atributos\n", "\n", "**\u00bfCu\u00e1l es el mejor rendimiento que puedes obtener con solo 2 o 3 atributos?**\n", "\n", "Una **matriz de correlaciones** muestra correlaciones entre pares de atributos en comparaci\u00f3n con el objetivo y para cada atributo en comparaci\u00f3n con otros atributos.\n", "\n", "Aqu\u00ed, correlaci\u00f3n se define como el [coeficiente de correlaci\u00f3n de Pearson](https://es.wikipedia.org/wiki/Coeficiente_de_correlaci%C3%B3n_de_Pearson). Para este ejercicio, no es necesario que comprendas los detalles matem\u00e1ticos.\n", "\n", "Los valores de correlaci\u00f3n tienen los siguientes significados:\n", "\n", " * `-1.0`: correlaci\u00f3n negativa perfecta\n", " * `0.0`: no existe correlaci\u00f3n\n", " * `1.0`: correlaci\u00f3n positiva perfecta" ] }, { "metadata": { "id": "UzoZUSdLIolF", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "test": { "output": "ignore", "timeout": 600 } }, "cellView": "both" }, "source": [ "correlation_dataframe = training_examples.copy()\n", "correlation_dataframe[\"target\"] = training_targets[\"median_house_value\"]\n", "\n", "correlation_dataframe.corr()" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "RQpktkNpia2P", "colab_type": "text" }, "source": [ " Idealmente, quisi\u00e9ramos tener atributos estrechamente correlacionados con el objetivo.\n", "\n", "Tambi\u00e9n quisi\u00e9ramos tener atributos que no estuvieran tan estrechamente correlacionados entre s\u00ed, de manera que agreguen informaci\u00f3n independiente.\n", "\n", "Usa esta informaci\u00f3n para probar quitar atributos. Tambi\u00e9n puedes intentar desarrollar atributos sint\u00e9ticos adicionales, como proporciones de dos atributos sin procesar.\n", "\n", "Para facilitar el trabajo, incluimos el c\u00f3digo de entrenamiento del ejercicio anterior." ] }, { "metadata": { "id": "bjR5jWpFr2xs", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "def construct_feature_columns(input_features):\n", " \"\"\"Construct the TensorFlow Feature Columns.\n", "\n", " Args:\n", " input_features: The names of the numerical input features to use.\n", " Returns:\n", " A set of feature columns\n", " \"\"\" \n", " return set([tf.feature_column.numeric_column(my_feature)\n", " for my_feature in input_features])" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "metadata": { "id": "jsvKHzRciH9T", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "def my_input_fn(features, targets, batch_size=1, shuffle=True, num_epochs=None):\n", " \"\"\"Trains a linear regression model of one feature.\n", " \n", " Args:\n", " features: pandas DataFrame of features\n", " targets: pandas DataFrame of targets\n", " batch_size: Size of batches to be passed to the model\n", " shuffle: True or False. Whether to shuffle the data.\n", " num_epochs: Number of epochs for which data should be repeated. None = repeat indefinitely\n", " Returns:\n", " Tuple of (features, labels) for next data batch\n", " \"\"\"\n", " \n", " # Convert pandas data into a dict of np arrays\n", " features = {key:np.array(value) for key,value in dict(features).items()} \n", " \n", " # Construct a dataset, and configure batching/repeating\n", " ds = Dataset.from_tensor_slices((features,targets)) # warning: 2GB limit\n", " ds = ds.batch(batch_size).repeat(num_epochs)\n", "\n", " # Shuffle the data, if specified\n", " if shuffle:\n", " ds = ds.shuffle(10000)\n", " \n", " # Return the next batch of data\n", " features, labels = ds.make_one_shot_iterator().get_next()\n", " return features, labels" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "metadata": { "id": "g3kjQV9WH3pb", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "def train_model(\n", " learning_rate,\n", " steps,\n", " batch_size,\n", " training_examples,\n", " training_targets,\n", " validation_examples,\n", " validation_targets):\n", " \"\"\"Trains a linear regression model.\n", " \n", " In addition to training, this function also prints training progress information,\n", " as well as a plot of the training and validation loss over time.\n", " \n", " Args:\n", " learning_rate: A `float`, the learning rate.\n", " steps: A non-zero `int`, the total number of training steps. A training step\n", " consists of a forward and backward pass using a single batch.\n", " batch_size: A non-zero `int`, the batch size.\n", " training_examples: A `DataFrame` containing one or more columns from\n", " `california_housing_dataframe` to use as input features for training.\n", " training_targets: A `DataFrame` containing exactly one column from\n", " `california_housing_dataframe` to use as target for training.\n", " validation_examples: A `DataFrame` containing one or more columns from\n", " `california_housing_dataframe` to use as input features for validation.\n", " validation_targets: A `DataFrame` containing exactly one column from\n", " `california_housing_dataframe` to use as target for validation.\n", " \n", " Returns:\n", " A `LinearRegressor` object trained on the training data.\n", " \"\"\"\n", "\n", " periods = 10\n", " steps_per_period = steps / periods\n", "\n", " # Create a linear regressor object.\n", " my_optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)\n", " my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)\n", " linear_regressor = tf.estimator.LinearRegressor(\n", " feature_columns=construct_feature_columns(training_examples),\n", " optimizer=my_optimizer\n", " )\n", " \n", " # Create input functions\n", " training_input_fn = lambda: my_input_fn(training_examples, \n", " training_targets[\"median_house_value\"], \n", " batch_size=batch_size)\n", " predict_training_input_fn = lambda: my_input_fn(training_examples, \n", " training_targets[\"median_house_value\"], \n", " num_epochs=1, \n", " shuffle=False)\n", " predict_validation_input_fn = lambda: my_input_fn(validation_examples, \n", " validation_targets[\"median_house_value\"], \n", " num_epochs=1, \n", " shuffle=False)\n", "\n", " # Train the model, but do so inside a loop so that we can periodically assess\n", " # loss metrics.\n", " print(\"Training model...\")\n", " print(\"RMSE (on training data):\")\n", " training_rmse = []\n", " validation_rmse = []\n", " for period in range (0, periods):\n", " # Train the model, starting from the prior state.\n", " linear_regressor.train(\n", " input_fn=training_input_fn,\n", " steps=steps_per_period,\n", " )\n", " # Take a break and compute predictions.\n", " training_predictions = linear_regressor.predict(input_fn=predict_training_input_fn)\n", " training_predictions = np.array([item['predictions'][0] for item in training_predictions])\n", " \n", " validation_predictions = linear_regressor.predict(input_fn=predict_validation_input_fn)\n", " validation_predictions = np.array([item['predictions'][0] for item in validation_predictions])\n", " \n", " # Compute training and validation loss.\n", " training_root_mean_squared_error = math.sqrt(\n", " metrics.mean_squared_error(training_predictions, training_targets))\n", " validation_root_mean_squared_error = math.sqrt(\n", " metrics.mean_squared_error(validation_predictions, validation_targets))\n", " # Occasionally print the current loss.\n", " print(\" period %02d : %0.2f\" % (period, training_root_mean_squared_error))\n", " # Add the loss metrics from this period to our list.\n", " training_rmse.append(training_root_mean_squared_error)\n", " validation_rmse.append(validation_root_mean_squared_error)\n", " print(\"Model training finished.\")\n", "\n", " \n", " # Output a graph of loss metrics over periods.\n", " plt.ylabel(\"RMSE\")\n", " plt.xlabel(\"Periods\")\n", " plt.title(\"Root Mean Squared Error vs. Periods\")\n", " plt.tight_layout()\n", " plt.plot(training_rmse, label=\"training\")\n", " plt.plot(validation_rmse, label=\"validation\")\n", " plt.legend()\n", "\n", " return linear_regressor" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "varLu7RNH3pf", "colab_type": "text" }, "source": [ " Dedica 5\u00a0minutos a buscar un buen conjunto de atributos y par\u00e1metros de entrenamiento. A continuaci\u00f3n, comprueba la soluci\u00f3n para ver cu\u00e1les elegimos nosotros. No olvides que los distintos atributos pueden requerir diferentes par\u00e1metros de aprendizaje." ] }, { "metadata": { "id": "DSgUxRIlH3pg", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "#\n", "# Your code here: add your features of choice as a list of quoted strings.\n", "#\n", "minimal_features = [\n", "]\n", "\n", "assert minimal_features, \"You must select at least one feature!\"\n", "\n", "minimal_training_examples = training_examples[minimal_features]\n", "minimal_validation_examples = validation_examples[minimal_features]\n", "\n", "#\n", "# Don't forget to adjust these parameters.\n", "#\n", "train_model(\n", " learning_rate=0.001,\n", " steps=500,\n", " batch_size=5,\n", " training_examples=minimal_training_examples,\n", " training_targets=training_targets,\n", " validation_examples=minimal_validation_examples,\n", " validation_targets=validation_targets)" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "IGINhMIJ5Wyt", "colab_type": "text" }, "source": [ " ### Soluci\u00f3n\n", "\n", "Haz clic m\u00e1s abajo para conocer la soluci\u00f3n." ] }, { "metadata": { "id": "BAGoXFPZ5ZE3", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "minimal_features = [\n", " \"median_income\",\n", " \"latitude\",\n", "]\n", "\n", "minimal_training_examples = training_examples[minimal_features]\n", "minimal_validation_examples = validation_examples[minimal_features]\n", "\n", "_ = train_model(\n", " learning_rate=0.01,\n", " steps=500,\n", " batch_size=5,\n", " training_examples=minimal_training_examples,\n", " training_targets=training_targets,\n", " validation_examples=minimal_validation_examples,\n", " validation_targets=validation_targets)" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "RidI9YhKOiY2", "colab_type": "text" }, "source": [ " ## Tarea\u00a02: Usa mejor la funci\u00f3n de latitud\n", "\n", "Al representar `latitude` frente a `median_house_value`, se evidencia que, en realidad, no hay una relaci\u00f3n lineal.\n", "\n", "En lugar de eso, hay algunos picos, que a grandes rasgos corresponden a Los \u00c1ngeles y San Francisco." ] }, { "metadata": { "id": "hfGUKj2IR_F1", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "test": { "output": "ignore", "timeout": 600 } }, "cellView": "both" }, "source": [ "plt.scatter(training_examples[\"latitude\"], training_targets[\"median_house_value\"])" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "6N0p91k2iFCP", "colab_type": "text" }, "source": [ " **Prueba crear algunos atributos sint\u00e9ticos que se desempe\u00f1en mejor con el atributo de latitud.**\n", "\n", "Por ejemplo, podr\u00edas tener un atributo que asigne `latitude` a un valor de `|latitude - 38|` y denominarla `distance_from_san_francisco`.\n", "\n", "O bien, podr\u00edas dividir el espacio en 10 agrupamientos diferentes: `latitude_32_to_33`, `latitude_33_to_34`, etc., cada uno que muestre un valor de `1.0` si `latitude` est\u00e1 dentro del rango de ese agrupamiento y, de lo contrario, un valor de `0.0`.\n", "\n", "Usa la matriz de correlaciones como gu\u00eda para el desarrollo y, a continuaci\u00f3n, si encuentras algo que te pueda resultar \u00fatil, agr\u00e9galo a tu modelo.\n", "\n", "\u00bfCu\u00e1l es el mejor rendimiento de validaci\u00f3n que puedes obtener?" ] }, { "metadata": { "id": "wduJ2B28yMFl", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } }, "cellView": "form" }, "source": [ "#\n", "# YOUR CODE HERE: Train on a new data set that includes synthetic features based on latitude.\n", "#" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "pZa8miwu6_tQ", "colab_type": "text" }, "source": [ " ### Soluci\u00f3n\n", "\n", "Haz clic m\u00e1s abajo para conocer la soluci\u00f3n." ] }, { "cell_type": "markdown", "metadata": { "id": "PzABdyjq7IZU", "colab_type": "text" }, "source": [ " Adem\u00e1s de `latitude`, tambi\u00e9n conservaremos `median_income` para realizar una comparaci\u00f3n con los resultados anteriores.\n", "\n", "Decidimos agrupar la latitud. Esto es bastante sencillo de hacer en Pandas a trav\u00e9s de `Series.apply`." ] }, { "metadata": { "id": "xdVF8siZ7Lup", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "LATITUDE_RANGES = zip(range(32, 44), range(33, 45))\n", "\n", "def select_and_transform_features(source_df):\n", " selected_examples = pd.DataFrame()\n", " selected_examples[\"median_income\"] = source_df[\"median_income\"]\n", " for r in LATITUDE_RANGES:\n", " selected_examples[\"latitude_%d_to_%d\" % r] = source_df[\"latitude\"].apply(\n", " lambda l: 1.0 if l >= r[0] and l < r[1] else 0.0)\n", " return selected_examples\n", "\n", "selected_training_examples = select_and_transform_features(training_examples)\n", "selected_validation_examples = select_and_transform_features(validation_examples)" ], "cell_type": "code", "execution_count": 0, "outputs": [] }, { "metadata": { "id": "U4iAdY6t7Pkh", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "source": [ "_ = train_model(\n", " learning_rate=0.01,\n", " steps=500,\n", " batch_size=5,\n", " training_examples=selected_training_examples,\n", " training_targets=training_targets,\n", " validation_examples=selected_validation_examples,\n", " validation_targets=validation_targets)" ], "cell_type": "code", "execution_count": 0, "outputs": [] } ] }