{"id":1930,"date":"2020-03-24T12:16:19","date_gmt":"2020-03-24T18:16:19","guid":{"rendered":"https:\/\/naps.com.mx\/blog\/?p=1930"},"modified":"2020-04-21T09:42:47","modified_gmt":"2020-04-21T14:42:47","slug":"fases-del-analisis-de-datos-usando-python","status":"publish","type":"post","link":"https:\/\/naps.com.mx\/blog\/fases-del-analisis-de-datos-usando-python\/","title":{"rendered":"Fases del an\u00e1lisis de datos usando Python"},"content":{"rendered":"<p>Veremos las siguientes fases del an\u00e1lisis de datos: ingesta de datos, diagn\u00f3stico de la calidad de los datos, y agrupaci\u00f3n de variables.<\/p>\n<p><!--more--><\/p>\n<p>Si deseas obtener el conjunto de datos que vamos a utilizar, puedes descargarlo aqu\u00ed: <a href=\"https:\/\/drive.google.com\/file\/d\/1IkmLk9m46Urpc39H2CO6GfSS3bPJZuvG\/view?usp=sharing\" target=\"_blank\" rel=\"noopener\">vehiculos_original.csv<\/a> (tama\u00f1o 4.3 MB).<\/p>\n<p>Los datos fueron tomados de\u00a0<a href=\"https:\/\/www.fueleconomy.gov\/feg\/ws\/index.shtml\" target=\"_blank\" rel=\"noopener\">https:\/\/www.fueleconomy.gov\/feg\/ws\/index.shtml<\/a><\/p>\n<div id=\"attachment_1945\" style=\"width: 650px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2020\/03\/fases-del-an\u00e1lisis-de-datos.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1945\" class=\"size-full wp-image-1945\" src=\"https:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2020\/03\/fases-del-an\u00e1lisis-de-datos.jpg\" alt=\"fases del an\u00e1lisis de datos\" width=\"640\" height=\"423\" srcset=\"https:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2020\/03\/fases-del-an\u00e1lisis-de-datos.jpg 640w, https:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2020\/03\/fases-del-an\u00e1lisis-de-datos-300x198.jpg 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><p id=\"caption-attachment-1945\" class=\"wp-caption-text\">Aprende las primeras fases del an\u00e1lisis de datos en Python<\/p><\/div>\n<h2>Primeras fases del an\u00e1lisis de datos<\/h2>\n<h2>Fase 1. Ingesta de datos.<\/h2>\n<p>En esta fase leemos el conjunto de datos original y le aplicamos el tratamiento necesario para facilitar su uso, por ejemplo, renombrar las columnas.<\/p>\n<p>Importar pandas y leer el archivo csv<\/p>\n<pre class=\"lang:python decode:true\">import pandas as pd\r\nvehiculos = pd.read_csv(\"vehiculos_original.csv\")\r\n<\/pre>\n<p>Renombrar las columnas<\/p>\n<pre class=\"lang:python decode:true\">vehiculos = vehiculos.rename(columns={\r\n\t\"cylinders\": \"cilindros\",\r\n\t\"trany\": \"transmision\",\r\n\t\"make\": \"fabricante\",\r\n\t\"model\": \"modelo\",\r\n\t\"displ\": \"desplazamiento\",\r\n\t\"drive\": \"traccion\",\r\n\t\"VClass\": \"clase\",\r\n\t\"fuelType\": \"combustible\",\r\n\t\"comb08\": \"consumo\",\r\n\t\"co2TailpipeGpm\": \"co2\"\r\n\t})<\/pre>\n<p>Guardar los cambios en un nuevo csv para no modificar el archivo original<\/p>\n<pre class=\"lang:python decode:true\">vehiculos.to_csv(\"vehiculos_paso1.csv\", index=False)\r\n<\/pre>\n<h2>Fase 2. Diagn\u00f3stico de la calidad de los datos (QA)<\/h2>\n<p>En esta fase revisamos que no existan datos duplicados (que no debiesen estar duplicados), datos nulos o inexistentes (que pudiesen arrojarnos errores de procesamiento), y se revisan tambi\u00e9n los valores extremos.<\/p>\n<p>Importamos las librer\u00edas que requeriremos, leemos el archivo csv y mostramos cu\u00e1ntas filas y columnas tiene nuestro dataset.<\/p>\n<pre class=\"lang:python decode:true \">import pandas as pd\r\nimport matplotlib.pyplot as plt\r\nvehiculos = pd.read_csv(\"vehiculospaso1.csv\")\r\nprint(vehiculos.shape)<\/pre>\n<h3>Eliminaci\u00f3n de filas duplicadas<\/h3>\n<p>Veamos cu\u00e1ntas filas duplicadas hay<\/p>\n<pre class=\"lang:python decode:true \">print (vehiculos[vehiculos.duplicated()].shape)<\/pre>\n<p>Eliminamos las filas duplicadas<\/p>\n<pre class=\"lang:python decode:true \">vehiculos = vehiculos.drop_duplicates()\r\nprint (vehiculos.shape)<\/pre>\n<h3>Cardinalidad<\/h3>\n<p>Midamos ahora la cardinalidad de algunas columnas. Con esto queremos observar si una cantidad grande de registros tiene el mismo valor.<\/p>\n<p>La siguiente funci\u00f3n nos permite ver el porcentaje de valores comunes en cada columna.<\/p>\n<pre class=\"lang:python decode:true \">n_registros = len(vehiculos)\r\ndef valores_duplicados_col(df):\r\n\tfor columna in df:\r\n\t\tn_por_valor = df[columna].value_counts()\r\n\t\tmas_comun = n_por_valor.iloc[0]\r\n\t\tmenos_comun = n_por_valor.iloc[-1]\r\n\t\tprint (\"{} | {} - {} | {}\".format(\r\n\t\t\tdf[columna].name,\r\n\t\t\tround(mas_comun\/(1.0*n_registros),3),\r\n\t\t\tround(menos_comun\/(1.0*n_registros),3),\r\n\t\t\tdf[columna].dtype\r\n\t\t))\r\nprint(\"Revisando valores duplicados\")\r\nvalores_duplicados_col(vehiculos)<\/pre>\n<p>Desde luego podemos observar \u00e9sto en forma gr\u00e1fica, columna por columna. Por ejemplo, para las columnas \u00abtransmision\u00bb y \u00abcombustible\u00bb:<\/p>\n<pre class=\"lang:python decode:true \">vehiculos.transmision.value_counts(normalize=True).plot.barh()\r\nvehiculos.cilindros.hist()\r\nvehiculos.combustible.value_counts(normalize=True).plot.barh()\r\nplt.show()<\/pre>\n<h3>Revisi\u00f3n de valores inexistentes<\/h3>\n<p>La siguiente funci\u00f3n nos permite observar el porcentaje de valores inexistentes en cada columna<\/p>\n<pre class=\"lang:python decode:true \">print (\"Revisando valores inexistentes\")\r\nn_registros = len(vehiculos)\r\ndef valores_inexistentes_col(df):\r\n\tfor columna in df:\r\n\t\tprint (\"{} | {} |{}\".format(\r\n\t\t\tdf[columna].name, \r\n\t\t\tlen(df[df[columna].isnull()]) \/ (1.0*n_registros),\r\n\t\t\tdf[columna].dtype\r\n\r\n\r\n\t\t\t))\r\n\r\nvalores_inexistentes_col(vehiculos)<\/pre>\n<h3>Valores extremos<\/h3>\n<p>Se consideran valores extremos aquellos cuya puntuaci\u00f3n Z es mayor a 3. Se considera a Z como<\/p>\n<p>Z = (x &#8211; media ) \/ desviaci\u00f3n_est\u00e1ndar<\/p>\n<p>Afortunadamente, contamos con la librer\u00eda <strong>scipy<\/strong> que nos permite obtener la puntaci\u00f3n Z f\u00e1cilmente.<\/p>\n<p>Podemos implementar una funci\u00f3n que nos permita observar la cantidad de valores extremos que existen en cada columna.<\/p>\n<pre class=\"lang:python decode:true \">from scipy import stats\r\nimport numpy as np \r\n\r\n\r\ndef extermos_col(df):\r\n\tfor columna in df:\r\n\t\tif df[columna].dtype != np.object:\r\n\t\t\tn_extremos = len(df[np.abs(stats.zscore(df[columna]))&gt;3])\r\n\t\t\tprint (\"{} | {} | {}\".format(\r\n\t\t\t\tdf[columna].name,\r\n\t\t\t\tn_extremos,\r\n\t\t\t\tdf[columna].dtype\r\n\r\n\t\t\t\t))\r\n\r\nprint (\"Revisando valores extremos\")\r\nextermos_col(vehiculos)\r\n<\/pre>\n<p>Gr\u00e1ficamente tambi\u00e9n podemos revisar los valores extremos. Por ejemplo, en las columnas consumo y co2.<\/p>\n<pre class=\"lang:python decode:true \">vehiculos.boxplot(column='consumo')\r\nvehiculos.boxplot(column='co2')\r\nplt.show()<\/pre>\n<p>Se observa que hay coches que no producen co2. \u00bfQu\u00e9 combustible usar\u00e1n?<\/p>\n<pre class=\"lang:python decode:true \">print(vehiculos[vehiculos.co2==0].combustible.unique())\r\n#Los tipos de combustible son\r\nprint(vehiculos.combustible.unique())<\/pre>\n<p>Bueno, para \u00e9ste ejercicio s\u00f3lo nos interesan los veh\u00edculos que s\u00ed generan co2, por lo que vamos a eliminar a los que no generan co2.<\/p>\n<pre class=\"lang:python decode:true \">print (vehiculos[vehiculos.co2==0].shape) #Hay 139 que no generan co2\r\nvehiculos_no_electricos = vehiculos[vehiculos.co2&gt;0] \r\nprint (vehiculos_no_electricos.shape)<\/pre>\n<h3>Conclusiones de \u00e9sta fase<\/h3>\n<p>Hay 1506 registros duplicados que se han eliminado.<br \/>\nLas variables desplazamiento, cilindro, transmision y traccion tienen valores nulos o inexistentes.<br \/>\nLa variable combustible tiene una clase dominante en 65%.<br \/>\nSe eliminaron 139 registros correspondientes a autos electricos que\u00a0no emiten co2.<\/p>\n<p>Guardamos un nuevo csv con los cambios<\/p>\n<pre class=\"lang:python decode:true \">vehiculos_no_electricos.to_csv(\"vehiculospaso2.csv\", index=False)<\/pre>\n<h2>Fase 3. Agrupaci\u00f3n de variables<\/h2>\n<p>Se requiere agrupar algunas variables a fin de reducir el campo de estudio a aquellas variables que nos interesan.<\/p>\n<p>La siguiente funci\u00f3n permite ver los valores \u00fanicos de cada columna.<\/p>\n<pre class=\"lang:python decode:true \">vehiculos = pd.read_csv(\"vehiculospaso2.csv\")\r\n\r\ndef valores_unicos_col(df):\r\n\tfor column in df:\r\n\t\tprint (\"{} | {} | {} \".format(\r\n\t\t\tdf[column].name, len(df[column].unique()), df[column].dtype\r\n\t\t\t))\r\nprint (\"=== Valores unicos por columna\")\r\nvalores_unicos_col(vehiculos)<\/pre>\n<h3>Agrupaci\u00f3n de variables categ\u00f3ricas: Primer caso, la columna \u00abclase\u00bb<\/h3>\n<p>Veamos qu\u00e9 valores componen la columna clase<\/p>\n<pre class=\"lang:python decode:true \">print (\"*** Valores de la columna clase\")\r\nprint (vehiculos.clase.unique())<\/pre>\n<p>Si se observan, podemos clasificar todos \u00e9stos valores en ciertas categor\u00edas. Vamos a crear las siguientes categor\u00edas o tipos para la columna clase: Coches peque\u00f1os, Coches medianos, Coches grandes, Camionetas, Veh\u00edculos especiales, Deportivos, Coche familiar, Furgoneta.<\/p>\n<p>A continuaci\u00f3n creamos una nueva columna llamada \u00abclase_tipo\u00bb, donde se clasificar\u00e1 cada registro en su tipo correspondiente.<\/p>\n<pre class=\"lang:python decode:true \">pequeno = ['Compact Cars', 'Subcompact Cars', 'Two Seaters', 'Minicompact Cars']\r\nmedio = ['Midsize Cars']\r\ngrande= ['Large Cars']\r\n\r\nvehiculos.loc[vehiculos['clase'].isin(pequeno),'clase_tipo'] = 'Coches peque\u00f1os'\r\nvehiculos.loc[vehiculos['clase'].isin(medio),'clase_tipo'] = 'Coches medianos'\r\n\r\nvehiculos.loc[vehiculos['clase'].isin(grande),'clase_tipo'] = 'Coches grandes'\r\n\r\nvehiculos.loc[vehiculos['clase'].str.contains('Truck'), 'clase_tipo'] = 'Camionetas'\r\nvehiculos.loc[vehiculos['clase'].str.contains('Special Purpose'), 'clase_tipo'] = 'Vehiculos especiales'\r\nvehiculos.loc[vehiculos['clase'].str.contains('Sport Utility'), 'clase_tipo'] = 'Deportivos'\r\nvehiculos.loc[vehiculos['clase'].str.contains('Station'), 'clase_tipo'] = 'Coche familiar'\r\nvehiculos.loc[vehiculos['clase'].str.lower().str.contains('van'), 'clase_tipo'] = 'Furgoneta'\r\n<\/pre>\n<p>Es \u00fatil que las columnas categ\u00f3ricas sean consideradas como tales por Python. A continuaci\u00f3n haremos eso a la columna \u00abclase_tipo\u00bb.<\/p>\n<pre class=\"lang:python decode:true \">vehiculos.clase_tipo = vehiculos.clase_tipo.astype(\"category\")\r\n<\/pre>\n<p>Si deseamos verificar que todas las filas hayan recibido una categor\u00eda, podemos contar cu\u00e1ntos registros contiene cada una de ellas.<\/p>\n<pre class=\"lang:python decode:true \">print (\"==== Mis Categorias de clase\")\r\nprint(vehiculos.clase_tipo.value_counts())<\/pre>\n<h3>Segundo caso: la columna \u00abtraccion\u00bb<\/h3>\n<p>Agruparemos los registros en dos tipos: dos y cuatro ruedas.<\/p>\n<pre class=\"lang:python decode:true \">print (\"Valores de la columna traccion\")\r\nprint(vehiculos.traccion.unique())\r\n\r\n\r\nvehiculos[\"traccion_tipo\"] = \"dos\"\r\nvehiculos.loc[vehiculos.traccion.isin([\r\n\t\"4-Wheel or All-Whell Drive\", \"All-Whell Drive\", \r\n\t\"4-Wheel Drive\", \"Part Time 4-Whell Drive\"]), \"traccion_tipo\"] = \"cuatro\"\r\nprint(\"\")\r\nprint (\"=== Mis Categorias de traccion\")\r\nprint (vehiculos.traccion_tipo.value_counts())<\/pre>\n<h3>Tercer caso: la columna \u00abtransmision\u00bb<\/h3>\n<p>Aqu\u00ed necesitamos solo dos categor\u00edas (Manual y Autom\u00e1tica) de todas las que el dataset maneja.<\/p>\n<pre class=\"lang:python decode:true \">vehiculos[\"transmision_tipo\"] = \"Autom\u00e1tica\"\r\nvehiculos.loc[vehiculos.transmision.notnull() &amp; vehiculos.transmision.str.startswith('M'), \"transmision_tipo\"] = \"Manual\"\r\n\r\nprint(\"\")\r\nprint (\"=== Mis Categorias de transmision\")\r\nprint (vehiculos.transmision_tipo.value_counts())<\/pre>\n<p>Cuarto caso: la columna \u00abcombustible\u00bb<\/p>\n<p>Crearemos los tipos: Normal, Premium, Hibrido y Otros tipos de combustible<\/p>\n<pre class=\"lang:python decode:true \">vehiculos[\"combustible_tipo\"] = \"Otros tipos de combustible\"\r\nvehiculos.loc[vehiculos[\"combustible\"] == \"Regular\", \"combustible_tipo\"] = \"Normal\"\r\nvehiculos.loc[vehiculos[\"combustible\"] == \"Premium\", \"combustible_tipo\"] = \"Premium\"\r\nvehiculos.loc[vehiculos[\"combustible\"].str.contains(\"Electricity\"), \"combustible_tipo\"]= \"Hibrido\"\r\n\r\nprint(\"\")\r\nprint (\"=== Mis Categorias de combustible\")\r\nprint (vehiculos.combustible_tipo.value_counts())\r\n<\/pre>\n<h3>Agrupamiento de variables continuas<\/h3>\n<p>Las variables continuas tienen valores num\u00e9ricos por lo que se deben clasificar de acuerdo a rangos de valores.<\/p>\n<p>Esto ocurre en el caso de las columnas \u00abdesplazamiento\u00bb, \u00abconsumo\u00bb y \u00abco2\u00bb. \u00c9stas columnas las clasificaremos en categor\u00edas como \u00abmuy bajo\u00bb, \u00abbajo\u00bb, \u00abmoderado\u00bb, \u00abalto\u00bb, \u00abmuy alto\u00bb, o de una forma similar.<\/p>\n<pre class=\"lang:python decode:true \">tipos_tam_motor = [\"muy peque\u00f1o\", \"peque\u00f1o\", \"mediano\", \"grande\", \"muy grande\"]\r\nvehiculos[\"tamano_motor_tipo\"] = pd.qcut(vehiculos[\"desplazamiento\"], 5, tipos_tam_motor) \r\n\r\nprint(\"\")\r\nprint (\"=== Mis Categorias de desplazamiento\")\r\nprint (vehiculos.tamano_motor_tipo.value_counts())\r\n\r\ntipos_consumo = [\"muy bajo\", \"bajo\", \"moderado\",\"alto\", \"muy alto\"]\r\nvehiculos[\"consumo_tipo\"] = pd.qcut(vehiculos[\"consumo\"], 5, tipos_consumo)\r\n\r\nprint(\"\")\r\nprint (\"=== Mis Categorias de consumo\")\r\nprint (vehiculos.consumo_tipo.value_counts())\r\n\r\ntipos_co2 = [\"muy bajo\", \"bajo\", \"moderado\",\"alto\", \"muy alto\"]\r\nvehiculos[\"co2_tipo\"] = pd.qcut(vehiculos[\"co2\"], 5, tipos_co2)\r\n\r\nprint(\"\")\r\nprint (\"=== Mis Categorias de co2\")\r\nprint (vehiculos.co2_tipo.value_counts())<\/pre>\n<p>Por \u00faltimo ajustaremos los valores de consumo y co2 para que ambos utilicen una misma unidad de medida.<\/p>\n<pre class=\"lang:python decode:true\">litros_por_galon = 3.78541\r\nvehiculos[\"consumo_litros_milla\"] = litros_por_galon \/ vehiculos.consumo\r\nprint(vehiculos.head(5))\r\n\r\nvehiculos.plot.scatter(x=\"consumo_litros_milla\", y = \"co2\")\r\nplt.show()<\/pre>\n<h3>Guardar los datos en formato pickle<\/h3>\n<p>Para evitar que se pierda informaci\u00f3n sobre qu\u00e9 variables son categ\u00f3ricas, en vez del formato CSV guardaremos en formato <em>pickle<\/em>. Pandas puede leer y escribir sobre <em>pickle<\/em> y al hacerlo es como si el dataframe nunca hubiese perdido ninguna propiedad.<\/p>\n<pre class=\"lang:python decode:true\">vehiculos.to_pickle(\"vehiculospaso3.pkl\")<\/pre>\n<p>\u00c9stas son las primeras 3 de las fases del an\u00e1lisis de datos. En otra entrada consideraremos las siguientes.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Veremos las siguientes fases del an\u00e1lisis de datos: ingesta de datos, diagn\u00f3stico de la calidad de los datos, y agrupaci\u00f3n de variables.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"amp_status":"","footnotes":""},"categories":[52],"tags":[269,266,268,230],"class_list":["post-1930","post","type-post","status-publish","format-standard","hentry","category-estadistica","tag-agrupacion-de-variables","tag-analisis-de-datos","tag-ingesta-de-datos","tag-python"],"_links":{"self":[{"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/posts\/1930","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/comments?post=1930"}],"version-history":[{"count":21,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/posts\/1930\/revisions"}],"predecessor-version":[{"id":2029,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/posts\/1930\/revisions\/2029"}],"wp:attachment":[{"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/media?parent=1930"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/categories?post=1930"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/tags?post=1930"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}