<jupyter_start><jupyter_text>PANDASPandas es una muy popular librería de código abierto dentro de los desarrolladores de Python, y sobre todo dentro del ámbito de Data Science y Machine Learning, ya que ofrece unas estructuras muy poderosas y flexibles que facilitan la manipulación y tratamiento de datos.Pandas surgió como necesidad de aunar en una única librería todo lo necesario para que un analista de datos pudiese tener en una misma herramienta todas las funcionalidades que necesitaba en su día a día, como son: cargar datos, modelar, analizar, manipular y prepararlos.<jupyter_code>import pandas as pd<jupyter_output><empty_output><jupyter_text>¿Qué tipo de datos maneja `pandas`?Cuando trabajen con datos tabulares, como datos almacenados en hojas de cálculo o bases de datos, `pandas` es la herramienta adecuada. `pandas` lo ayudará a explorar, limpiar y procesar sus datos. En pandas, una tabla de datos se llama `DataFrame`.![](https://pandas.pydata.org/pandas-docs/stable/_images/01_table_dataframe.svg)<jupyter_code>df = pd.DataFrame(
  {
    "Name": [
      "Braund, Mr. <NAME>",
      "Allen, Mr. <NAME>",
      "<NAME>",
    ],
    "Age": [22, 35, 58],
    "Sex": ["male", "male", "female"],
  }
)

df<jupyter_output><empty_output><jupyter_text>Un DataFrame es una estructura de datos bidimensional que puede almacenar datos de diferentes tipos (incluidos caracteres, números enteros, valores de coma flotante, datos categóricos y más) en columnas. Es similar a una hoja de cálculo, una tabla `SQL` o el `data.frame` en R.Cada `column` en un `DataFrame` es una `series`![](https://pandas.pydata.org/pandas-docs/stable/_images/01_table_series.svg)<jupyter_code>type(df['Sex'])

df['Sex']
# También puede crear una serie desde cero:

ages = pd.Series([22, 35, 58], name="Age")<jupyter_output><empty_output><jupyter_text>Una serie pandas **no tiene** etiquetas de `columns`, ya que es solo una columna de un `DataFrame`. Una `Series` tiene etiquetas de `rows`.Suponga que queremos saber la Edad máxima de los pasajerosPodemos hacer esto en el DataFrame seleccionando la columna Edad y aplicando `max()`:<jupyter_code>df["Age"].max()
ages.max()<jupyter_output><empty_output><jupyter_text>¿Interesado en algunas estadísticas básicas de los datos numéricos de mi tabla de datos?<jupyter_code>df.describe()<jupyter_output><empty_output><jupyter_text>¿Cómo leo y escribo datos tabulares?*pandas* admite la integración con muchos formatos de archivo o fuentes de datos listos para usar (csv, excel, sql, json, parquet,...). La función con el prefijo `read_*` proporciona la importación de datos de cada una de estas fuentes de datos. De manera similar, los métodos `to_*` se utilizan para almacenar datos.![](https://pandas.pydata.org/pandas-docs/stable/_images/02_io_readwrite.svg) Veamos un ejemplo con data del *Titanic* (el barco, no la 🎬)- PassengerId: Id of every passenger.- Survived: This feature have value 0 and 1. 0 for not survived and 1 for survived.- Pclass: There are 3 classes: Class 1, Class 2 and Class 3.- Name: Name of passenger.- Sex: Gender of passenger.- Age: Age of passenger.- SibSp: Indication that passenger have siblings and spouse.- Parch: Whether a passenger is alone or have family.- Ticket: Ticket number of passenger.- Fare: Indicating the fare.- Cabin: The cabin of passenger.- Embarked: The embarked category.[Download raw data](https://raw.githubusercontent.com/pandas-dev/pandas/main/doc/data/titanic.csv)<jupyter_code>titanic = pd.read_csv("data/titanic.csv") # leer el csv y cargarlo a un DataFrame

titanic.head(8) # primeras 8 filas del dataframe
titanic.dtypes
titanic.info()
# Guardar a un Excel

titanic.to_excel(".\\excel\\titanic.xlsx", sheet_name="passengers", index=False)<jupyter_output><empty_output><jupyter_text>¿Cómo selecciono un subconjunto de una tabla?¿Seleccionar o filtrar filas y/o columnas específicas? ¿Filtrar los datos en una condición? Los métodos para cortar, seleccionar y extraer los datos que necesita están disponibles en pandas.![](https://pandas.pydata.org/pandas-docs/stable/_images/03_subset_columns.svg)<jupyter_code>ages = titanic["Age"]

ages.head()
type(titanic['Age'])
titanic["Age"].shape # Una columna<jupyter_output><empty_output><jupyter_text>Para seleccionar una sola columna, utilice corchetes `[]` con el nombre de columna o  columnas de interés.<jupyter_code>age_sex = titanic[["Age", "Sex"]]

age_sex.head(10)
type(titanic[["Age", "Sex"]])
titanic[["Age", "Sex"]].shape # Dos columnas<jupyter_output><empty_output><jupyter_text>¿Cómo filtro filas específicas de un `DataFrame`?![](https://pandas.pydata.org/pandas-docs/stable/_images/03_subset_rows.svg) Por ejemplo Me interesan los pasajeros mayores de 35 años.<jupyter_code>above_35 = titanic[titanic["Age"] > 35]

above_35.head()<jupyter_output><empty_output><jupyter_text>La condición dentro de los corchetes de selección `titanic["Age"] > 35` comprueba para qué filas la columna Edad tiene un valor mayor que 35:<jupyter_code>titanic["Age"] > 35
above_35.shape<jupyter_output><empty_output><jupyter_text>Ahora estoy interesado en los pasajeros del Titanic de clase de cabina 2 y 3.<jupyter_code>class_23 = titanic[titanic["Pclass"].isin([2, 3])]

class_23.head()<jupyter_output><empty_output><jupyter_text>De forma similar a la expresión condicional, la función condicional `isin()` devuelve `True` para cada fila en la que los valores están en la lista proporcionada. Para filtrar las filas según dicha función, use la función condicional dentro de los corchetes de selección `[]`. En este caso, la condición dentro de los paréntesis de selección `titanic["Pclass"].isin([2, 3])` comprueba para qué filas la columna `Pclass` es 2 o 3.Lo anterior es equivalente a filtrar por filas para las cuales la clase es 2 o 3 y combinar las dos declaraciones con un `|` (`or`) operador:<jupyter_code>class_23 = titanic[(titanic["Pclass"] == 2) | (titanic["Pclass"] == 3)]

class_23.head()<jupyter_output><empty_output><jupyter_text>Supongamos que ahora queremos trabajar con datos de pasajeros para los que se conoce la edad.<jupyter_code>age_no_na = titanic[titanic["Age"].notna()]

age_no_na.head()<jupyter_output><empty_output><jupyter_text>La función condicional `notna()` devuelve un valor verdadero para cada fila en la que los valores no son un valor nulo. Como tal, puede combinarse con los corchetes de selección `[]` para filtrar la tabla de datos.Es posible que se pregunte qué cambió realmente, ya que las primeras 5 líneas siguen siendo los mismos valores. Una forma de verificar es verificar si la forma ha cambiado:<jupyter_code>print(age_no_na.shape)
print(titanic.shape) # Hay menos filas<jupyter_output>(714, 12)
(891, 12)<jupyter_text>¿Cómo selecciono filas y columnas específicas de un `DataFrame`?![](https://pandas.pydata.org/pandas-docs/stable/_images/03_subset_columns_rows.svg)Imagine que queremos los nombres de los pasajeros mayores de 35 años.<jupyter_code>adult_names = titanic.loc[titanic["Age"] > 35, "Name"]

adult_names.head()<jupyter_output><empty_output><jupyter_text>En este caso, se crea un subconjunto de `rows` y `columns` de una sola vez y ya no es suficiente usar corchetes de selección `[]`. Los operadores `loc/iloc` son obligatorios delante de los corchetes de selección `[]`. Cuando se usa `loc/iloc`, la parte anterior a la coma son las filas que desea y la parte posterior a la coma son las columnas que desea seleccionar.Cuando utilice los nombres de las columnas, las etiquetas de las filas o una expresión de condición, utilice el operador 'loc' delante de los corchetes de selección `[]`. Tanto para la parte anterior como posterior a la coma, puede usar una sola etiqueta, una lista de etiquetas, una porción de etiquetas, una expresión condicional o dos puntos. El uso de dos puntos especifica que desea seleccionar todas las filas o columnas.<jupyter_code>titanic.iloc[9:25, 2:5]<jupyter_output><empty_output><jupyter_text>Al seleccionar filas y/o columnas específicas con `loc` o `iloc`, se pueden asignar nuevos valores a los datos seleccionados. Por ejemplo, para asignar el nombre anónimo a los 3 primeros elementos de la tercera columna:<jupyter_code>titanic.iloc[0:3, 3] = "anonymous"

titanic.head()<jupyter_output><empty_output><jupyter_text>¿Cómo crear plots en `pandas`?![](https://pandas.pydata.org/pandas-docs/stable/_images/04_plot_overview.svg)Para este tutorial, se utilizan datos sobre la calidad del aire, disponibles mediante openaq y utilizando el paquete py-openaq. El conjunto de datos air_quality_no2.csv proporciona valores para las estaciones de medición FR04014, BETR801 y London Westminster en París, Amberes y Londres, respectivamente.[Download raw data](https://raw.githubusercontent.com/pandas-dev/pandas/main/doc/data/air_quality_no2.csv)<jupyter_code>import matplotlib.pyplot as plt
air_quality = pd.read_csv("data/air_quality_no2.csv", index_col=0, parse_dates=True)

air_quality.head()
air_quality.plot()<jupyter_output><empty_output><jupyter_text>Quiero trazar solo las columnas de la tabla de datos con los datos de París.<jupyter_code>air_quality["station_paris"].plot()<jupyter_output><empty_output><jupyter_text>Quiero comparar visualmente los valores $NO_2$ medidos en Londres frente a París.<jupyter_code>air_quality.plot.scatter(x="station_london", y="station_paris", alpha=0.5)<jupyter_output><empty_output><jupyter_text>Una de las opciones es `DataFrame.plot.box()`, que hace referencia a un `boxplot`. El método de caja es aplicable en los datos de ejemplo de calidad del aire:<jupyter_code>air_quality.plot.box()<jupyter_output><empty_output><jupyter_text>Quiero cada una de las columnas en una `subplot` separada.<jupyter_code>axs = air_quality.plot.area(figsize=(12, 4), subplots=True)<jupyter_output><empty_output><jupyter_text>Quiero personalizar, ampliar o guardar el gráfico resultante.<jupyter_code># Create an empty matplotlib Figure and Axes
fig, axs = plt.subplots(figsize=(12, 4))

# Use pandas to put the area plot on the prepared Figure/Axes
air_quality.plot.area(ax=axs)         

# Do any matplotlib customization you like
axs.set_ylabel("$NO_2$ concentration")   

# Save the Figure/Axes using the existing matplotlib method.
fig.savefig("no2_concentrations.png")<jupyter_output><empty_output><jupyter_text>¿Cómo crear nuevas columnas derivadas de columnas existentes?![](https://pandas.pydata.org/pandas-docs/stable/_images/05_newcolumn_1.svg)Por ejemplo, quiero expresar la concentración $NO_2$ de la estación de Londres en $mg/m^3$ (si suponemos una temperatura de 25 grados centígrados y una presión de 1013 hPa, el factor de conversión es 1.882)<jupyter_code>air_quality["london_mg_per_cubic"] = air_quality["station_london"] * 1.882

air_quality.head()<jupyter_output><empty_output><jupyter_text>El cálculo de los valores se realiza elemento por elemento. Esto significa que todos los valores en la columna dada se multiplican por el valor 1.882 a la vez. **¡No necesita usar un bucle para iterar cada una de las filas!**Ahora, quiero verificar la proporción de los valores en París frente a Amberes y guardar el resultado en una nueva columna<jupyter_code>air_quality["ratio_paris_antwerp"] = (
  air_quality["station_paris"] / air_quality["station_antwerp"]
)

air_quality.head()<jupyter_output><empty_output><jupyter_text>Quiero cambiar el nombre de las columnas de datos a los identificadores de estación correspondientes utilizados por openAQ<jupyter_code>air_quality_renamed = air_quality.rename(
  columns={
    "station_antwerp": "BETR801",
    "station_paris": "FR04014",
    "station_london": "London Westminster",
})

air_quality_renamed.head()<jupyter_output><empty_output><jupyter_text>¿Cómo calcular las estadísticas de resumen?![](https://pandas.pydata.org/pandas-docs/stable/_images/06_aggregate.svg)¿Cuál es la edad promedio de las pasajeros del Titanic?<jupyter_code>titanic["Age"].mean()<jupyter_output><empty_output><jupyter_text>¿Cuál es la edad mediana y el precio de la tarifa del billete de los pasajeros del Titanic?<jupyter_code>titanic[["Age", "Fare"]].median()<jupyter_output><empty_output><jupyter_text>La estadística de agregación se puede calcular para varias columnas al mismo tiempo. ¿Recuerdas la función `describe` del primer tutorial?<jupyter_code>titanic[["Age", "Fare"]].describe()
# Otra forma

titanic.agg({
  "Age": ["min", "max", "median", "skew"],
  "Fare": ["min", "max", "median", "mean"],
})<jupyter_output><empty_output><jupyter_text>Agregando estadísticas agrupadas por categoría![](https://pandas.pydata.org/pandas-docs/stable/_images/06_groupby.svg)¿Cuál es la edad promedio de los pasajeros masculinos y femeninos del Titanic?<jupyter_code>titanic[["Sex", "Age"]].groupby("Sex").mean()
titanic.groupby("Sex").mean()
titanic.groupby("Sex")["Age"].mean()<jupyter_output><empty_output><jupyter_text>![](https://pandas.pydata.org/pandas-docs/stable/_images/06_groupby_select_detail.svg)La columna `Pclass` contiene datos numéricos pero en realidad representa 3 categorías (o factores) con las etiquetas '1', '2' y '3' respectivamente. Calcular estadísticas sobre estos no tiene mucho sentido. Por lo tanto, pandas proporciona un tipo de datos categóricos para manejar este tipo de datos.Veamos ¿Cuál es el precio promedio de la tarifa del boleto para cada combinación de sexo y clase de cabina?<jupyter_code>titanic.groupby(["Sex", "Pclass"])["Fare"].mean()<jupyter_output><empty_output><jupyter_text>¿Cuál es el precio promedio de la tarifa del boleto para cada combinación de sexo y clase de cabina?![](https://pandas.pydata.org/pandas-docs/stable/_images/06_valuecounts.svg)El método `count()` cuenta el número de registros para cada categoría en una columna.<jupyter_code>titanic.groupby("Pclass")["Pclass"].count()
df['conteo']= titanic.groupby("Pclass")['Age'].count()
df['media']= titanic.groupby("Pclass")['Age'].mean()
df<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10525556917309495, 'fraction_numerical': 0.011823228318073678, 'mean_word_length': 6.339682539682539, 'pattern_counts': {'":': 8, '<': 131, '<?xml version=': 0, '>': 135, 'https://': 14, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '32', 'dir': 'jupyter-structured-clean-dedup', 'id': '99239', 'license': 'MIT', 'n_tokens_mistral': 5120, 'n_tokens_neox': 4914, 'n_words': 1431, 'path': 'intro_a_pandas.ipynb', 'repo_name': 'newpaxonian/curso_python', 'size': '13901'}