Hola. En este video, vamos a estudiar algunas de las operaciones que nos ofrece Pandas para hacer un análisis rápido de la información contenida en un DataFrame. Para estudiar estas funciones, utilizaremos dos DataFrames que contienen subconjuntos de las columnas de nuestro dataset de contratación estatal. El primer DataFrame tendrá sólo información categórica, mientras que el segundo tendrá solo información numérica. Esto nos permitirá ver que las funciones se comportan de forma diferente según sean los tipos de datos. Empecemos explorando nuestro DataFrame con datos categóricos que hemos guardado en una variable con el nombre "categoricos". Cuando empezamos a trabajar con un nuevo DataFrame, lo primero que solemos hacer es explorar una pequeña parte de los datos. Para conocer los primeros datos, podemos usar la función "head", indicando en el parámetro cuántos registros queremos extraer. Para conocer los últimos datos, podemos usar la función "tail" que funciona de forma muy similar. En este caso, vemos que nuestro DataFrame tiene cuatro columnas y vemos una muestra de los posibles valores que puede tener cada una. En este caso, también, descubrimos, por casualidad en realidad, que la columna fecha de firma puede tener valores nulos, los cuales aparecen con la sigla NaT, que significa "Not attained". Otras funciones de mucha utilidad son "info" y "describe". Con info obtenemos un resumen sobre las columnas del DataFrame que nos indica el nombre y tipo de cada uno. Además, nos muestra si hay valores nulos en esa columna para que los tengamos en cuenta cuando hagamos cálculos y otras operaciones. En el ejemplo que estamos viendo, las columnas cuyo tipo aparece indicado como "object" son columnas con cadenas de caracteres. Por otro lado, la función "describe" intenta hacer un análisis de los valores contenidos en cada columna. Como nuestro DataFrame no tiene columnas numéricas, los campos que retorna la función "describe" son los siguientes: "count" que nos da el total de valores no nulos que hay en cada columna, "unique" que nos indica cuántos valores diferentes hay en cada columna, "top" que indica el valor más frecuente de una columna y "frec" que indica cuántas veces aparece el valor más frecuente. Por ejemplo, en la columna "Sector" hay 661.635 registros no nulos repartidos entre 26 valores diferentes. El que más aparece, es decir, el sector del Estado que más contratos tiene registrados, es el sector de "Salud y Protección Social" para el cual hay 113.811 contratos. Finalmente, las filas "First" y "Last" indican, solo para las columnas de tipo fecha, las fechas extremas. Exploremos ahora una de las columnas para saber más sobre los valores que aparecen en ella. En primer lugar, repasemos la forma en la que extraemos columnas de un DataFrame. Usamos el nombre del DataFrame y los paréntesis cuadrados, y con esto podemos extraer bien sea una columna en particular o un conjunto de columnas si usamos una lista de nombres dentro de los paréntesis. En la imagen de la izquierda, estamos extrayendo solo la columna llamada "Sector" y lo que vemos al invocar la función "type" es que esta operación de extracción resulta en algo de tipo serie. Si invocamos la función "unique" sobre una serie, obtendremos un "array" o arreglo con los valores diferentes que aparezcan en esta serie. En este caso, vemos los 26 valores que la función "describe" ya nos había anunciado. Ahora bien, "array " es un elemento propio en un pipe y no siempre es fácil trabajar con un "array". La forma más sencilla de convertirlo en uno de los tipos de datos que ya conocemos es invocar la función "list" pasándole como parámetro el "array". El resultado será una lista donde aparecerán todos los valores diferentes presentes en la serie. Finalmente, tenemos la función "value_counts", que se aplica sobre una serie y retorna una nueva serie, donde los índices son cada uno de los valores diferentes que aparecen en la serie y los valores son la cantidad de veces que aparece cada uno. Como detalle adicional, los valores de esta serie están ordenados del más frecuente al menos frecuente. Por ejemplo, en la figura vemos que, como ya sabíamos, el sector con más contratos es el de "Salud y Protección Social", pero también vemos que el segundo es "Servicio Público" y que el que tiene menos contratos es "Inteligencia Estratégica y Contrainteligencia" con solo 217. También, vemos que hay un valor llamado "No Definido" que aparece una sola vez en la columna "Sector". Detengámonos un momento para resolver una pregunta. Exploraremos ahora el DataFrame valores, en el que sólo hemos dejado columnas de tipo numérico. En primer lugar, observemos lo que aparece cuando invocamos la función "head". Tenemos solo cuatro columnas en el DataFrame y dentro de cada una hay valores numéricos. Los números se ven bastante grandes, lo cual es normal considerando que muy posiblemente estén en pesos colombianos. Siendo así, el valor del primer contrato por 22 millones de pesos correspondería cerca de 8.000 dólares americanos. Más adelante veremos cómo podríamos modificar esta DataFrame para que las cifras estén en otra moneda o estén expresadas de una forma más breve, por ejemplo, en billones de pesos. En la imagen de abajo podemos ver que al invocar la función "info", Pandas nos muestra que las columnas son de tipo "float64". Esto corresponde al tipo que usan un pipe para representar números flotantes y para efectos prácticos es equivalente al tipo float que ya conocemos desde el módulo uno del curso. Ahora veamos con cuidado lo que pasa al invocar la función "describe", porque el resultado es completamente diferente al que obtuvimos cuando hicimos el mismo ejercicio sobre el DataFrame con valores categóricos. La fila "count" nos sigue indicando la cantidad de valores que hay en cada una de las columnas. Luego tenemos las filas "mean" y "std" que nos muestran el valor promedio y la desviación estándar dentro de cada columna. Luego tenemos las filas "min", "25 por ciento", "50 por ciento", "75 por ciento" y "max" que nos indican, respectivamente, los valores correspondientes a cada cuartil. Por ejemplo, esto nos muestra que el 25 por ciento de los registros tiene un valor del contrato menor a 9 millones de pesos y que el 75 por ciento tiene un valor menor a 41 millones. En un momento, hablaremos más sobre el valor máximo que aparece registrado en esta columna. Pasemos ahora a ver otras funciones que nos permiten estudiar los resultados que nos da "describe", pero de una manera más libre. En primer lugar, tenemos la función "mean", que aplicada sobre un DataFrame, nos retorna una serie donde los índices son los nombres de las columnas y los valores son los promedios de cada columna. En la segunda instrucción, vemos lo que ocurre cuando invocamos esa misma función pero sobre una única columna. En este caso, obtenemos un valor flotante equivalente al promedio de esa columna, lo cual es bastante más fácil de utilizar. Las funciones "std" que calcular la desviación estándar y "mode" que calcula la moda o valor más común, funcionan de forma muy similar. Luego, tenemos las funciones "max", "min", "idxmax" e "idxmin". Las dos primeras nos permiten averiguar el valor máximo y el valor mínimo de cada columna. Las otras funciones, es decir "idxmax" e "idxmin", nos permiten averiguar en dónde están los registros que tienen los valores máximos y mínimos. Por ejemplo, en la figura vemos que el contrato con el mayor valor tiene el absurdo valor de 9.801 billones de pesos, que es cercano al presupuesto de todo el Estado colombiano durante 30 años. Al invocar la función "idxmax", vemos que el valor máximo se encuentra en el registro, cuya etiqueta es 449.009. Si invocamos la función "iloc" y le pasamos el valor del índice entre paréntesis cuadrados, de la misma forma en que lo hicimos cuando estudiamos series, obtendremos las otras columnas de este registro. En este caso, no nos dicen mucho porque también están en cero. Pero podemos aplicar la misma técnica sobre el DataFrame llamado "data", en el cual habíamos dejado el data set completo con toda la información que descargamos de Secop. Si observamos con cuidado los detalles del contrato, veremos que está en estado cancelado, lo cual explica por qué los otros valores numéricos estaban en cero. Este ejemplo también nos da una importante lección. El data set sobre el que estamos trabajando puede tener errores, así que no podemos confiar ciegamente en todos los resultados que obtengamos haciendo cálculos con estos datos. Por lo pronto, ya aprendimos que no deberíamos tener en cuenta los contratos cancelados puesto que podrían haber sido cancelados por tener errores, como evidentemente ocurrió en este contrato. A continuación, tenemos la función "quantile" que nos permite trabajar no solo con los cuartiles, sino con cualquier otro porcentaje que queramos. Por ejemplo, al invocar la función usando 0,95 como parámetro, podemos ver que el 95 por ciento de los contratos tienen un valor menor a 226 millones de pesos colombianos. Pandas también ofrece funciones agregadas que operan sobre todos los elementos de una columna. La función "sum" calcula la suma de todos los elementos de una columna, mientras que la función "prod" los multiplica entre sí. Por el contrario, la función "div" divide todos los elementos del DataFrame por un valor que pasamos por parámetro. En este caso, esto nos permite convertir fácilmente todas las cifras de pesos a millones de pesos. Finalmente, la función "sum" puede invocarse usando el parámetro llamado "axis" que sirve para indicar si queremos aplicar la función "sum" sobre las columnas o sobre las filas. En este caso, estamos indicando que "axis" es igual a uno, así que la función nos generará una serie con un valor por cada fila del DataFrame original que será igual a la suma de todos los valores en esa fila. Si, en cambio, hubiéramos indicado "axis" igual a cero habríamos obtenido un valor por columna como cuando no usamos ningún valor para el parámetro. Detengámonos ahora un momento para resolver una pregunta. Para concluir, en este video hemos explorado las funciones más importantes de Pandas para analizar DataFrames. Hay mucho más por estudiar sobre estas funciones y sobre todas las otras funciones que no alcanzamos a presentar. Lo invitamos a explorar la documentación oficial para saber más y para descubrir otros parámetros que se pueden usar para controlar mejor muchas de las funciones que acá estudiamos.