Saltar al contenido

# introduccion-a-la-ciencia-de-datos-con-python

Introducción a la Ciencia de Datos con Python

Volver a la portada del curso
Notebook

Análisis de datos avanzados con pandas

Sección 2 · Manipulación y Análisis de Datos

Análisis de datos avanzados con pandas

Con groupby y mean ya sabes que en 2007 la vida media en Africa era de 54.8 años y en Europe de 77.6. Este notebook da el siguiente paso: resumir varias métricas a la vez, poner la evolución en una tabla continente × año, encontrar los países que retrocedieron y limpiar una copia de Gapminder a la que le metemos errores a propósito para practicar. El notebook pandas-gapminder acompaña esta lección; aquí tienes la guía de lo que hace cada sección y qué debe darte.

1. Resúmenes con nombre: agg

agg con tuplas (columna, función) calcula varias métricas por grupo y les pone nombre en un solo paso:

import plotly.express as px

gap = px.data.gapminder().drop(columns=["iso_alpha", "iso_num"])
g07 = gap[gap["year"] == 2007]
resumen = g07.groupby("continent").agg(
    paises=("country", "count"),
    vida_media=("lifeExp", "mean"),
    pib_pc_mediano=("gdpPercap", "median"),
    poblacion=("pop", "sum"),
)
print(resumen.round(1))

Asia suma 3812 millones de habitantes en 33 países; Oceania, 2 países. El PIB per cápita mediano de Africa es de 1452 dólares y el de Europe de 28 054. Se usa la mediana porque el PIB está muy sesgado: unos pocos países ricos jalan la media hacia arriba.

2. Tablas continente × año: pivot_table

pivot_table pasa los datos de formato largo a ancho para leer la evolución de un vistazo:

tabla = gap.pivot_table(index="continent", columns="year",
                        values="lifeExp", aggfunc="mean")
print(tabla[[1952, 1977, 2007]].round(1))

Africa pasa de 39.1 a 49.6 y a 54.8; Asia, de 46.3 a 59.6 y a 70.7. Asia ganó 24 años en el periodo; Africa, casi 16. La tabla ancha es buena para mirar; para seguir calculando conviene volver al formato largo.

3. Columnas nuevas con assign y comparaciones con merge

assign crea columnas sin modificar el original, por ejemplo pib_total = pop * gdpPercap. Para comparar 1952 con 2007 país por país, se separan los dos años y se unen por country:

a = gap.loc[gap["year"] == 1952, ["country", "lifeExp"]]
b = gap.loc[gap["year"] == 2007, ["country", "continent", "lifeExp"]]
ambos = a.merge(b, on="country", suffixes=("_1952", "_2007"))
ambos["ganancia"] = ambos["lifeExp_2007"] - ambos["lifeExp_1952"]
print(ambos.shape, round(ambos["ganancia"].mean(), 2))   # (142, 5) 17.95
print(ambos.nlargest(3, "ganancia")[["country", "ganancia"]].round(1))

La ganancia media es de 17.95 años. Las mayores: Oman 38.1, Vietnam 33.8 e Indonesia 33.2. Solo dos países terminan peor que en 1952: Zimbabwe (−5.0) y Swaziland (−1.8). Después de un merge, revisa siempre el número de filas: si sale más de 142, alguna llave estaba repetida.

4. Cambios dentro de cada país: diff por grupo

Para ver retrocesos entre mediciones consecutivas, se ordena por país y año y se aplica diff dentro de cada país. Sin el groupby, la primera fila de un país se restaría de la última del anterior.

gap = gap.sort_values(["country", "year"])
gap["cambio"] = gap.groupby("country")["lifeExp"].diff()
caidas = gap[gap["cambio"] < -5]
print(len(caidas))   # 15
print(caidas.nsmallest(3, "cambio")[["country", "year", "lifeExp", "cambio"]].round(1))

Hay 15 caídas de más de 5 años. La peor es Rwanda en 1992: −20.4 años, hasta 23.6. El periodo coincide con la guerra civil iniciada en 1990, que desembocó en el genocidio de 1994; la serie cada 5 años suaviza los eventos. Le siguen Zimbabwe 1997 (−13.6), Lesotho 2002 (−11.0), Swaziland 2002 (−10.4) y Botswana 1997 (−10.2), todos en África austral durante la epidemia de VIH/sida. Detrás de cada número atípico hay una historia: investígala antes de tratarlo como error.

5. Limpieza de una copia sucia

Gapminder viene limpio, así que el notebook define gapminder_sucio(semilla=42): la tabla de 2007 con nulos, texto inconsistente y duplicados metidos a propósito. Tiene 145 filas, 5 nulos en lifeExp, 3 en gdpPercap, 3 filas duplicadas y 10 escrituras distintas de continente («africa», «Africa », «AFRICA»…). La limpieza va en este orden:

limpio = sucio.drop_duplicates().copy()
limpio["continent"] = limpio["continent"].str.strip().str.title()
mediana = limpio.groupby("continent")[["lifeExp", "gdpPercap"]].transform("median")
limpio[["lifeExp", "gdpPercap"]] = limpio[["lifeExp", "gdpPercap"]].fillna(mediana)
print(limpio.shape, limpio.isna().sum().sum())   # (142, 6) 0

transform("median") devuelve, para cada fila, la mediana de su continente, con el mismo índice que la tabla; por eso fillna rellena cada nulo con el valor de su grupo. Quedan 142 filas, 5 continentes y 0 nulos.

Imputar inventa datos, y el notebook lo mide: comparado con el valor real, el error en lifeExp es de 7.3 años en Bolivia, 6.1 en Nigeria, 3.1 en Iceland, 0.8 en Venezuela y 0.7 en Slovenia. Si imputas, dilo en el reporte y di cuántas filas afectó.

6. apply y map, con moderación

map con un diccionario sirve para recodificar, por ejemplo continente → código de dos letras. apply con una función de Python recorre fila por fila y es lento; casi siempre existe una versión vectorizada (np.log10, operaciones entre columnas, métodos .str). Úsalo solo cuando no la haya.

Trampas comunes

  • diff sin agrupar ni ordenar: mezcla países y años.
  • Imputar con la media global: un país africano recibiría un valor sesgado hacia Europe. Agrupa primero.
  • Arreglar el texto después de agrupar: «Africa » y «Africa» quedarían como dos grupos.
  • No contar filas después de un merge: una llave repetida multiplica filas sin avisar.

Cierre

Al terminar el notebook, verifica con números: 142 filas, 0 nulos, 5 continentes y 15 caídas. Si algún conteo no coincide, revisa el orden de los pasos de limpieza antes de seguir.

Recursos