In [0]:
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Introducción rápida a Pandas

Objetivos de aprendizaje:

  • Obtener una introducción a las estructuras de datos de DataFrame y Series de la biblioteca de Pandas
  • Acceder y manipular datos dentro de DataFrame y Series
  • Importar datos CSV a un DataFrame de Pandas
  • Reindexar un DataFrame para obtener datos aleatorios

pandas es una API de análisis de datos en columnas, ideal para manipular y analizar datos de entrada. Además, muchos marcos de trabajo de AA admiten las estructuras de datos pandas como entradas. Si bien una introducción detallada a la API de pandas abarcaría muchas páginas, los conceptos principales que presentamos a continuación son simples. Para obtener una referencia más completa, el sitio de documentación de pandas incluye una documentación exhaustiva y numerosos instructivos.

Conceptos básicos

La siguiente línea importa la API de pandas e imprime la versión de la API:


In [0]:
from __future__ import print_function

import pandas as pd
pd.__version__

Las estructuras de datos principales en pandas están implementadas en dos clases:

  • DataFrame, que puedes imaginar como una tabla de datos relacional, con filas y columnas con nombre.
  • Series, que es una columna simple. Una clase DataFrame incluye una o más Series y un nombre para cada Series.

El marco de datos es una abstracción que se usa normalmente para manipular datos. Hay implementaciones similares en Spark y R.

Una manera de crear una Series es construir un objeto de Series. Por ejemplo:


In [0]:
pd.Series(['San Francisco', 'San Jose', 'Sacramento'])

Los objetos de DataFrame pueden crearse al enviar un dict que asigne nombres de columnas de string a sus Series correspondientes. Si las Series no coinciden con la longitud, los valores que falten se completan con valores NA/NaN especiales. Ejemplo:


In [0]:
city_names = pd.Series(['San Francisco', 'San Jose', 'Sacramento'])
population = pd.Series([852469, 1015785, 485199])

pd.DataFrame({ 'City name': city_names, 'Population': population })

Pero por lo general, cargas un archivo completo en un DataFrame. El siguiente ejemplo carga un archivo con datos de viviendas de California. Ejecuta la siguiente celda para cargar los datos y crear definiciones de funciones:


In [0]:
california_housing_dataframe = pd.read_csv("https://download.mlcc.google.com/mledu-datasets/california_housing_train.csv", sep=",")
california_housing_dataframe.describe()

En el ejemplo de arriba, se usó DataFrame.describe para mostrar estadísticas interesantes sobre un DataFrame. Otra función útil es DataFrame.head, que muestra los primeros registros de un DataFrame:


In [0]:
california_housing_dataframe.head()

Otra función util de pandas es la generación de gráficos. Por ejemplo, DataFrame.hist permite estudiar rápidamente la distribución de los valores en una columna:


In [0]:
california_housing_dataframe.hist('housing_median_age')

Acceso a los datos

Puedes acceder a los datos de DataFrame mediante las operaciones convencionales de dict/list de Python:


In [0]:
cities = pd.DataFrame({ 'City name': city_names, 'Population': population })
print(type(cities['City name']))
cities['City name']

In [0]:
print(type(cities['City name'][1]))
cities['City name'][1]

In [0]:
print(type(cities[0:2]))
cities[0:2]

Además, pandas proporciona una API muy enriquecida para una indexación y selección avanzadas, que es un tema demasiado amplio como para cubrirlo aquí.

Manipulación de datos

Puedes aplicar operaciones aritméticas básicas de Python a las Series. Por ejemplo:


In [0]:
population / 1000.

NumPy es un kit de herramientas popular para el cálculo científico. Las Series de pandas pueden usarse como argumentos para la mayoría de las funciones NumPy:


In [0]:
import numpy as np

np.log(population)

Para obtener información sobre transformaciones más complejas de una sola columna, puedes usar Series.apply. Al igual que la función función map de Python, Series.apply acepta como argumento una función función lambda, que se aplica a cada valor.

El siguiente ejemplo crea una nueva Series que indica si la population es superior a un millón:


In [0]:
population.apply(lambda val: val > 1000000)

Modificar DataFrames también es simple. Por ejemplo, el siguiente código agrega dos Series a un DataFrame existente:


In [0]:
cities['Area square miles'] = pd.Series([46.87, 176.53, 97.92])
cities['Population density'] = cities['Population'] / cities['Area square miles']
cities

Ejercicio n.º 1

Para modificar la tabla de cities, agrega una nueva columna booleana que sea Verdadera si y solo si ambos de los siguientes valores son Verdaderos:

  • La ciudad le debe su nombre a un santo.
  • La ciudad tiene un área superior a 50 millas cuadradas.

Nota: Las Series booleanas se combinan en función de los bits, en lugar de los operadores booleanos tradicionales. Por ejemplo, cuando utilices logical and, usa & en lugar de and.

Hint: "San" en español representa "santo".


In [0]:
# Your code here

Solución

Haz clic a continuación para obtener una solución.


In [0]:
cities['Is wide and has saint name'] = (cities['Area square miles'] > 50) & cities['City name'].apply(lambda name: name.startswith('San'))
cities

Índices

Los objetos Series y DataFrame también definen una propiedad de index que asigna un valor de identificador a cada elemento Series o fila DataFrame.

De forma predeterminada, en la construcción, pandas asigna valores de índice que reflejan la solicitud de los datos de origen. Una vez creados, los valores de índice son estables, es decir, no cambian cuando cambia el orden de los datos.


In [0]:
city_names.index

In [0]:
cities.index

Llama DataFrame.reindex para cambiar el orden de las filas de forma manual. Por ejemplo, la siguiente acción tiene el mismo efecto que ordenar los valores por nombre de ciudad:


In [0]:
cities.reindex([2, 0, 1])

La reindexación es una excelente manera de seleccionar un DataFrame de forma aleatoria. En el ejemplo que se muestra a continuación, tomamos el índice, que es del tipo matriz, y lo enviamos a la función random.permutation de NumPy, que selecciona sus valores de forma aleatoria. Utilizar la reindexación con esta matriz aleatoria provoca que las filas de DataFrame se seleccionen de forma aleatoria de la misma manera. ¡Prueba ejecutar la siguiente celda varias veces!


In [0]:
cities.reindex(np.random.permutation(cities.index))

Para obtener más información, consulta Documentación de índice.

Ejercicio n.º 2

El método de reindex permite los valores de índice que no están en los valores de índice originales de DataFrame. Pruébalo y observa lo que sucede si usas esos valores. ¿Por qué supones que los permite?


In [0]:
# Your code here

Solución

Haz clic a continuación para conocer la solución.

Si la matriz de la entrada reindex incluye valores que no se encuentran en los valores de índice originales DataFrame, reindex agregará nuevas filas para esos índices "faltantes" y completará todas las columnas correspondientes con los valores NaN:


In [0]:
cities.reindex([0, 4, 5, 2])

Este comportamiento es util, ya que por lo general los índices son strings extraídos de los datos actuales (consulta la pandas reindex documentation para obtener un ejemplo en el que los valores de índice son nombres de navegadores).

En este caso, permitir los índices "faltantes" facilita la reindexación mediante una lista externa, dado que no tienes que preocuparte por sanear directamente las entradas.